git cherry-pick
Узнайте о команде git cherry-pick: как копировать отдельные коммиты между ветками, параметры, разрешение конфликтов и примеры.
Что делает git cherry-pick
Команда git cherry-pick берёт изменение, внесённое одним или несколькими существующими коммитами, и повторно применяет его в текущей ветке в виде нового коммита. Там, где git merge и git rebase переносят целые линии истории, cherry-pick позволяет взять отдельный коммит и поместить его именно туда, где он нужен.
На этой странице рассматривается, как cherry-pick работает внутри, как выбрать один коммит или диапазон, какие параметры вам действительно пригодятся, как разрешать конфликты и когда стоит использовать cherry-pick вместо merge или git revert.
Как это работает
Коммит — это снимок состояния, но cherry-pick обращается с ним как с патчем: вычисляет разницу между коммитом и его родителем, применяет эту разницу к верхушке текущей ветки и записывает новый коммит. Новый коммит сохраняет исходное сообщение, автора и дату, но получает новый хэш и нового родителя, поскольку теперь занимает другое место в истории.
Это ключевое отличие в понимании: cherry-pick копирует изменение, а не перемещает его. Исходный коммит остаётся нетронутым в своей исходной ветке.
git switch main
git cherry-pick a1b2c3dИзменение из коммита a1b2c3d теперь находится в main в виде нового коммита.
Пример использования
Допустим, исправление было зафиксировано в ветке feature, но оно должно быть в main. Сначала найдите хэш коммита с помощью git log:
git switch feature
git log --oneline
# d9ae654 fix login redirect
# 7c1a902 work in progress
# fa42ab5 baseТеперь переключитесь на main и скопируйте только этот один коммит:
git switch main
git cherry-pick d9ae654[main 02bbf3e] fix login redirect
1 file changed, 1 insertion(+)Обратите внимание на новый хэш 02bbf3e — исправление теперь находится в main как совершенно новый коммит, тогда как d9ae654 по-прежнему существует нетронутым в ветке feature.
Выбор диапазона коммитов
Можно применить несколько коммитов за один раз. Диапазон копирует каждый коммит после первого вплоть до последнего включительно:
git cherry-pick a1b2c3d..f4e5d6cПри этом сам a1b2c3d исключается. Чтобы сделать диапазон включительным с начального коммита, добавьте суффикс ^, чтобы диапазон начинался с его родителя:
git cherry-pick a1b2c3d^..f4e5d6cКоммиты применяются по одному в порядке очерёдности; если возникает конфликт, cherry-pick останавливается на этом коммите, чтобы вы могли его исправить перед продолжением.
Основные параметры
| Команда | Описание |
|---|---|
git cherry-pick <commit> | Применяет изменение из <commit> как новый коммит в текущей ветке. |
git cherry-pick -n <commit> | Применяет изменение, но не фиксирует его, оставляя в индексе для проверки или доработки перед коммитом. |
git cherry-pick -x <commit> | Добавляет строку (cherry picked from commit …) к сообщению — полезно в публичных ветках, чтобы другие могли отследить происхождение. |
git cherry-pick -e <commit> | Открывает редактор, чтобы вы могли изменить сообщение коммита до его записи. |
git cherry-pick --continue | Возобновляет операцию после разрешения конфликтов. |
git cherry-pick --skip | Пропускает текущий коммит (например, когда его изменение уже присутствует) и переходит к следующему. |
git cherry-pick --abort | Отменяет операцию и восстанавливает ветку в исходное состояние. |
При использовании -x записанное сообщение выглядит следующим образом:
fix login redirect
(cherry picked from commit d9ae65426adbde425c3e386a32297e9e833d8816)Обработка конфликтов
Если изменение не применяется без конфликтов, cherry-pick приостанавливается — так же, как при слиянии — и оставляет маркеры конфликта в затронутых файлах. Вы увидите:
CONFLICT (content): Merge conflict in app.js
error: could not apply d9ae654... fix login redirect
hint: ... fix conflicts and then run "git cherry-pick --continue".Вручную разрешите конфликты в файлах, проиндексируйте их с помощью git add, затем продолжите:
git add app.js
git cherry-pick --continueНа этом этапе доступны три варианта выхода из ситуации:
git cherry-pick --continue— завершить после разрешения конфликтов.git cherry-pick --skip— пропустить текущий коммит и перейти к следующему в диапазоне.git cherry-pick --abort— полностью отменить операцию и вернуть ветку к исходному состоянию.
Используйте git status в любой момент, чтобы посмотреть, в каких файлах ещё остались конфликты.
Когда использовать
Cherry-pick особенно полезен, когда:
- Исправление попало не в ту ветку и вам нужно перенести его в другое место.
- Вы выполняете бэкпортирование отдельного патча в ветку релиза или сопровождения.
- Вам нужен один коммит из feature-ветки без слияния всей ветки целиком.
Cherry-pick против merge, rebase и revert
| Цель | Команда |
|---|---|
| Скопировать один (или несколько) конкретных коммитов в другую ветку | git cherry-pick |
| Интегрировать всю историю ветки | git merge |
| Перенести коммиты ветки на новую базу | git rebase |
| Отменить коммит, записав противоположный коммит | git revert |
Подводные камни
- Дубликаты в общей истории. Cherry-picking в ветку, которая впоследствии будет слита обратно в исходную, создаёт два коммита с одинаковым изменением. Git обычно достаточно умён, чтобы пропустить дубликат при слиянии, но это может усложнить историю — предпочтите merge или rebase, если вам нужна вся ветка.
- Пустые результаты. Если изменение уже присутствует в целевой ветке, cherry-pick останавливается с сообщением
The previous cherry-pick is now empty. Используйтеgit cherry-pick --skipдля продолжения или--abortдля отмены. - Новый хэш, а не исходный. Поскольку коммит воссоздаётся заново, его хэш меняется. Добавьте
-x, чтобы в сообщении было записано, откуда он пришёл.