↓Перейти к содержанию
  1. Git: руководства и команды/

git cherry-pick: перенос коммита из одной ветки в другую

·5 минут·

Иногда нужно перенести не всю ветку, а только один конкретный коммит. Например, разработчик исправил критическую ошибку в feature-ветке, но её срочно нужно доставить в production, не дожидаясь завершения feature. Именно для таких случаев существует git cherry-pick.

Что такое cherry-pick #

git cherry-pick берёт конкретный коммит из любой ветки и применяет его изменения к текущей ветке. Это похоже на копирование: исходный коммит остаётся на месте, а в текущей ветке создаётся новый коммит с теми же изменениями, но новым SHA-хешем.

feature:  A - B - C - D
                  ↑
              cherry-pick

main:     X - Y - C'
                  ↑
            новый коммит (копия C)

Важно понимать: cherry-pick не «переносит», а «копирует» коммит. Оригинальный коммит C остаётся в ветке feature, а C' в main — его копия.

Когда использовать cherry-pick #

Срочное исправление в production. Разработчик нашёл и исправил баг в feature-ветке. Исправление нужно срочно в main, но вся feature ещё не готова.

Перенос фикса между версиями. Проект поддерживает несколько версий (v1.x и v2.x). Исправление из v2 нужно применить и к v1.

Случайно закоммитили в неправильную ветку. Коммит сделан в main вместо feature. Можно cherry-pick в нужную ветку, затем отменить в main.

Выборочный перенос функций. Нужно взять только часть работы из большой ветки.

Простой cherry-pick одного коммита #

Сначала нужно узнать SHA-хеш нужного коммита:

# Посмотреть историю ветки feature
git log --oneline feature

# Вывод:
# d5e6f7g Исправить SQL-инъекцию в форме входа
# c3d4e5f Добавить тесты для авторизации
# b2c3d4e Рефакторинг модуля авторизации

Теперь применить нужный коммит к текущей ветке:

# Переключиться на целевую ветку
git checkout main
# или
git switch main

# Cherry-pick конкретного коммита
git cherry-pick d5e6f7g

# Вывод при успехе:
# [main a1b2c3d] Исправить SQL-инъекцию в форме входа
#  1 file changed, 3 insertions(+), 2 deletions(-)

Git создал новый коммит a1b2c3d в ветке main с теми же изменениями, что и d5e6f7g в ветке feature.

Cherry-pick нескольких коммитов #

Можно перенести несколько коммитов за один раз — перечислив их или указав диапазон.

# Cherry-pick нескольких отдельных коммитов (по очереди)
git cherry-pick a1b2c3d b2c3d4e c3d4e5f

# Cherry-pick диапазона коммитов (исключающий — a1b2c3d не включается)
git cherry-pick a1b2c3d..e4f5g6h

# Cherry-pick диапазона коммитов (включающий — оба конца включаются)
git cherry-pick a1b2c3d^..e4f5g6h

Разница между a..b и a^..b: первый вариант не включает коммит a, второй — включает.

Cherry-pick без автоматического коммита #

По умолчанию cherry-pick сразу создаёт коммит. Если нужно проверить изменения или объединить с другими — используйте флаг -n (--no-commit):

# Применить изменения, но не коммитить
git cherry-pick -n a1b2c3d

# Теперь изменения в индексе, можно проверить
git status
git diff --staged

# Можно дополнить изменениями
# Затем закоммитить вручную
git commit -m "Применить исправление безопасности и улучшить логирование"

Опция -n особенно полезна при переносе нескольких коммитов с объединением в один:

git cherry-pick -n a1b2c3d b2c3d4e c3d4e5f
git commit -m "Применить все исправления безопасности"

Редактирование сообщения коммита #

При cherry-pick можно изменить сообщение коммита:

# Открыть редактор для изменения сообщения
git cherry-pick --edit a1b2c3d
# или
git cherry-pick -e a1b2c3d

Добавление подписи (signoff) #

Опция --signoff добавляет строку Signed-off-by: в сообщение коммита — полезно для проектов, требующих явного подтверждения авторства:

git cherry-pick --signoff a1b2c3d
# Коммит получит в сообщении:
# Signed-off-by: Ваше Имя <[email protected]>

Разрешение конфликтов при cherry-pick #

Если изменения в коммите конфликтуют с текущим состоянием ветки, Git остановится и сообщит о конфликте:

git cherry-pick a1b2c3d
# error: could not apply a1b2c3d... Исправить баг авторизации
# hint: after resolving the conflicts, mark the corrected paths
# hint: with 'git add <paths>' or 'git rm <paths>'
# hint: and commit the result with 'git commit'

# Проверить конфликтные файлы
git status

# Открыть файлы, разрешить конфликты (убрать маркеры <<<, ===, >>>)
# Затем добавить исправленные файлы
git add src/auth.js

# Продолжить cherry-pick
git cherry-pick --continue

# Или полностью отменить cherry-pick
git cherry-pick --abort

Просмотр непенесённых коммитов #

Команда git cherry (без -pick) показывает, какие коммиты из одной ветки ещё не применены в другой:

# Показать коммиты из feature, которых нет в master
git cherry -v master feature

# Вывод:
# + a1b2c3d Добавить функцию X   (+ = не перенесён)
# - b2c3d4e Исправить баг Y      (- = уже есть в master)
# + c3d4e5f Добавить тесты       (+ = не перенесён)

Знак + означает коммит, которого нет в целевой ветке. Знак - — коммит уже присутствует (возможно, через предыдущий cherry-pick).

Практические примеры #

# Перенести исправление безопасности из feature в main
git log --oneline feature | grep security
# a1b2c3d Исправить SQL-инъекцию

git switch main
git cherry-pick a1b2c3d

# Перенести несколько коммитов
git cherry-pick a1b2c3d b4c5d6e c5d6e7f

# Перенести диапазон включительно
git cherry-pick a1b2c3d^..e4f5g6h

# Проверить изменения перед коммитом
git cherry-pick -n a1b2c3d
git diff --staged
git commit -m "Применить исправление"

# Cherry-pick из удалённой ветки
git fetch origin
git cherry-pick origin/hotfix/critical-bug a1b2c3d

# Отменить неудачный cherry-pick
git cherry-pick --abort

# Если уже закоммитили неверный cherry-pick
git revert HEAD

# Посмотреть, что изменил коммит перед cherry-pick
git show a1b2c3d

Отмена cherry-pick #

Если cherry-pick ещё не завершён (прервался из-за конфликта):

git cherry-pick --abort

Если cherry-pick уже завершён и нужно отменить коммит:

# Отменить через revert (создаст новый отменяющий коммит)
git revert a1b2c3d  # хеш нового коммита cherry-pick, не исходного

# Или через reset (если коммит последний и не опубликован)
git reset --hard HEAD~1

Часто задаваемые вопросы #

Какая разница между cherry-pick и merge? Merge объединяет всю ветку. Cherry-pick переносит конкретные коммиты. Merge сохраняет полную историю ветки, cherry-pick создаёт копии выбранных коммитов.

Что произойдёт, если сделать cherry-pick коммита, который уже есть в текущей ветке? Git создаст дублирующий коммит с теми же изменениями. Это обычно нежелательно. Команда git cherry -v помогает проверить, каких коммитов ещё нет в ветке.

Как разрешить конфликты при cherry-pick? Так же, как при merge: открыть конфликтный файл, найти маркеры <<<<<<<, =======, >>>>>>>, выбрать нужную версию, удалить маркеры, git add <file>, затем git cherry-pick --continue.

Можно ли cherry-pick в обратном направлении (отменить изменения)? Да, с опцией --reverse или git revert. Это применит обратные изменения из коммита.

Когда НЕ следует использовать cherry-pick? Когда нужно объединить целые ветки — лучше merge или rebase. Если коммитов много и они связаны — cherry-pick каждого неудобен. Cherry-pick также затрудняет отслеживание происхождения изменений в истории.

Заключение #

git cherry-pick — инструмент для точечного переноса изменений. Он незаменим для срочных исправлений, синхронизации между ветками поддержки и исправления ошибок при коммите в неправильную ветку. Для повседневного объединения веток предпочтительнее git merge или git rebase.