Как вставить чужой коммит в ветку Git, не ломая цепочку коммитов
Что проверяют
Знаете ли вы git cherry-pick и понимаете ли, почему он не ломает историю: он добавляет новый коммит сверху, а не вставляет старый в середину. Следом спрашивают про конфликты и про то, чем это отличается от merge и rebase.
Как отвечать
Сначала уточните, что значит «вставить». Если нужно перенести изменение в свою ветку, это cherry-pick:
- получить коммит: если он из чужой ветки или форка, сначала
git fetch <remote>, коммит должен оказаться в локальном репозитории; - перенести:
git switch release/1.4, затемgit cherry-pick -x <sha>. Git применяет изменения этого коммита и создаёт новый коммит с новым хешем. Автор остаётся оригинальный, коммиттером становитесь вы, а флаг-xдописывает в сообщение ссылку на исходный коммит; - несколько коммитов:
git cherry-pick A^..Bберёт диапазон включительно, без^коммитAне войдёт; - merge-коммит: нужен
-m 1, чтобы указать, относительно какого родителя брать изменения; - конфликты: правите файлы,
git add, затемgit cherry-pick --continue;--abortвозвращает всё как было,--skipпропускает текущий коммит.
После переноса прогоните тесты (pytest) и хуки pre-commit: коммит мог опираться на код, которого в целевой ветке нет. Типичный сценарий для Python-проекта: бэкпорт исправления в релизную ветку. CPython делает это постоянно, для этого у проекта есть утилита cherry_picker.
Если же нужно действительно вставить коммит между существующими, это git rebase -i. Он пересоздаёт все последующие коммиты с новыми хешами и требует git push --force-with-lease, поэтому на общей ветке так не делают.
Где спотыкаются
Думают, что cherry-pick переносит тот же самый коммит. Хеш будет другим, и при последующем слиянии исходной ветки в истории окажутся два коммита с одинаковыми изменениями, а если код успели поменять, ещё и конфликт.
Переносят коммит, не проверив зависимости. Он написан поверх предыдущих изменений, а в целевой ветке их нет, и код падает на импорте.
Используют cherry-pick вместо merge, когда нужна вся ветка целиком. Десяток коммитов, перенесённых по одному, дублирует историю и теряет связь с исходной веткой.