Извлечение изменений - git cherry-pick

17 декабря 2025
Автор

Олег Марков

Введение

Извлечение изменений в Git через команду git cherry-pick позволяет вам аккуратно перенести один или несколько коммитов из одной ветки в другую, не сливая ветки целиком. Это особенно полезно, когда вы хотите:

  • забрать один фикс из feature-ветки в рабочую ветку;
  • перенести критический багфикс в релизную ветку;
  • аккуратно взять пару полезных коммитов из экспериментальной ветки, не затрагивая остальной «шум».

Смотрите, я покажу вам, как это работает на практике, а также какие подводные камни возникают чаще всего. Мы разберем синтаксис, типичные сценарии использования, работу с конфликтами и дополнительные опции, которые облегчают жизнь.


Что такое git cherry-pick и чем он отличается от merge и rebase

Основная идея cherry-pick

Команда git cherry-pick берет один конкретный коммит (или последовательность коммитов) и «повторяет» его изменения в текущей ветке. При этом:

  • создается новый коммит с новыми хешами;
  • содержимое изменений, как правило, совпадает (за исключением возможных конфликтов и ручных правок);
  • история ветки остаётся линейной, вы не добавляете merge-коммитов.

Говоря проще, вы как бы говорите Git: «Возьми вот этот коммит и сделай то же самое здесь».

Отличия от merge

Давайте разберемся:

  • git merge:

    • объединяет две ветки;
    • переносит все недостающие коммиты целиком;
    • часто создает merge-коммит;
    • сохраняет структурированную историю ветвлений.
  • git cherry-pick:

    • переносит только указанные коммиты;
    • не объединяет ветки логически;
    • создает новые коммиты, которые повторяют изменения;
    • история становится более «линейной» и локально измененной.

Поэтому cherry-pick используют, когда merge «слишком много берет» и вам нужно только несколько конкретных изменений.

Отличия от rebase

С rebase cherry-pick роднит то, что оба инструмента создают новые коммиты, изменяя историю:

  • rebase переписывает серию коммитов, как будто вы сделали их от другой базы;
  • cherry-pick позволяет избирательно переносить отдельные коммиты куда нужно.

Часто используют сочетание: сначала rebase в своей ветке, затем cherry-pick нужных коммитов в релизную ветку.


Базовый синтаксис git cherry-pick

Подготовка окружения

Перед работой с cherry-pick важно:

  1. Убедиться, что рабочее дерево чистое.
git status
# Проверяем, что нет незакоммиченных изменений

Если есть незакоммиченные изменения, лучше их либо закоммитить, либо отложить (stash), чтобы не получить конфликт рабочей директории с применяемыми изменениями.

  1. Переключиться на ветку, куда вы хотите перенести изменения.
git checkout main
# Переходим в целевую ветку, например main

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

Теперь давайте посмотрим базовую команду:

git cherry-pick <hash-коммита>
# Например
git cherry-pick a1b2c3d4

Что происходит:

  • Git находит коммит с указанным хешем;
  • применяет его дифф к текущей ветке;
  • создает новый коммит с теми же изменениями, но новым хешем;
  • если есть конфликты, процесс останавливается до их ручного решения.

Вы увидите новый коммит в истории текущей ветки:

git log --oneline --graph -5
# Смотрим последние 5 коммитов в компактном виде

Извлечение одного коммита: пошаговый пример

Представьте, что у вас есть две ветки:

  • main — основная ветка;
  • feature-x — ветка, где ведется разработка новой фичи.

В ветке feature-x вы сделали багфикс, который нужен в main, но переносить всю фичу рано.

Шаг 1. Найти нужный коммит

Сначала смотрим историю в feature-x:

git checkout feature-x
# Переходим в ветку с нужным коммитом

git log --oneline
# Отображаем историю этой ветки

Предположим, вы видите:

9f8e7d6 Исправлен баг с валидацией формы
1a2b3c4 Черновик новой фичи
...

Вас интересует коммит 9f8e7d6.

Шаг 2. Переключиться в целевую ветку

git checkout main
# Переходим в ветку, куда будем переносить фикс

Шаг 3. Выполнить cherry-pick

git cherry-pick 9f8e7d6
# Переносим фикс в main

Если конфликта нет — Git сам создаст новый коммит в main. Теперь вы можете отправить его в удаленный репозиторий:

git push origin main
# Публикуем изменения

Так вы забрали только нужный багфикс без остальной незаконченной работы из feature-x.


Извлечение нескольких коммитов

Часто требуется забрать не один, а несколько связанных коммитов: например, фиксы и доработки, которые логически принадлежат одному багу или фиче.

Последовательность коммитов (диапазон)

Если коммиты идут подряд в истории, можно взять их диапазоном. Давайте разберемся на примере:

История ветки feature-x:

d4d4d4d Рефакторинг валидации
c3c3c3c Логирование ошибок валидации
b2b2b2b Исправление ошибки валидации
a1a1a1a Начальная реализация фичи

Вы хотите перенести три верхних коммита: b2b2b2b..d4d4d4d.

Теперь вы увидите, как это выглядит в команде:

git checkout main
# Переходим в основную ветку

git cherry-pick b2b2b2b^..d4d4d4d
# Переносим все коммиты от b2b2b2b включительно до d4d4d4d

Почему b2b2b2b^..d4d4d4d:

  • запись X^..Y означает «от родителя X до Y включительно»;
  • так первый коммит в диапазоне тоже попадает в набор.

Альтернатива, если вы точно знаете базу:

git cherry-pick a1a1a1a..d4d4d4d
# Переносит все коммиты после a1a1a1a до d4d4d4d включительно

Обратите внимание, как диапазон влияет на то, какие изменения попадут в целевую ветку. Лучше дважды проверить log перед выполнением.

Неподряд идущие коммиты

Если нужные коммиты не идут подряд, cherry-pick можно запустить сразу с несколькими хешами:

git checkout main
# Переходим в целевую ветку

git cherry-pick d4d4d4d f1f1f1f 9e9e9e9
# Переносим три отдельных коммита

Git применяет их по очереди в указанном порядке. Если на каком-то из них возникнет конфликт, процесс остановится до его решения.


Работа с конфликтами при cherry-pick

Конфликты — обычная часть работы с cherry-pick, особенно если код уже изменился в целевой ветке.

Как выглядит конфликт

После выполнения cherry-pick вы можете увидеть сообщение:

error: could not apply 9f8e7d6... Исправлен баг с валидацией формы
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and then run 'git cherry-pick --continue'

Теперь давайте посмотрим, что происходит в файлах. Например, в конфликтах вы увидите примерно следующее:

<<<<<<< HEAD
// Текущая версия кода в ветке main
validateInput(input string) bool {
    // Старая логика валидации
}
=======
// Версия кода из cherry-picked коммита
validateInput(input string) bool {
    // Новая логика валидации
}
>>>>>>> 9f8e7d6 (Исправлен баг с валидацией формы)

Маркировки:

  • блок между <<<<<<< HEAD и ======= — код, который сейчас в вашей ветке;
  • блок между ======= и >>>>>>> <hash> — код из применяемого коммита.

Шаги решения конфликта

  1. Открыть файл в редакторе и вручную выбрать или объединить нужные части кода.
// Пример — вы оставили обновленную версию
func validateInput(input string) bool {
    // Новая логика валидации
    // Здесь мы добавляем дополнительные проверки длины и формата
}
  1. Удалить все конфликтные маркеры (<<<<<<<, =======, >>>>>>>).

  2. Добавить файл в индекс:

git add path/to/file.go
# Помечаем файл как решенный
  1. Продолжить процесс cherry-pick:
git cherry-pick --continue
# Git создаст коммит с учетом ваших правок

Если вы решили, что хотите отменить этот cherry-pick целиком, можно сделать так:

git cherry-pick --abort
# Откатываемся к состоянию до cherry-pick

Важные опции git cherry-pick

Опция -n или --no-commit

По умолчанию cherry-pick сразу создает новый коммит. Но иногда вам нужно:

  • применить изменения;
  • вручную доработать код;
  • возможно объединить несколько изменений в один коммит.

Тогда удобно использовать --no-commit:

git cherry-pick -n a1b2c3d
# Применяем изменения из коммита, но НЕ создаем новый коммит автоматически

Далее вы можете:

  • поменять код;
  • добавить/удалить файлы;
  • собрать один аккуратный коммит:
git commit -m "Перенос и доработка фикса валидации"
# Создаем свой собственный коммит с перенесенными и доработанными изменениями

Это хороший способ не засорять историю мелкими техническими коммитами.

Опция -x — пометка источника коммита

Если вы переносите изменения из одной ветки в другую, часто полезно явно указать, откуда коммит взят. Для этого есть -x:

git cherry-pick -x 9f8e7d6
# Создаст коммит с доп. строкой в сообщении

Сообщение коммита будет примерно таким:

Исправлен баг с валидацией формы

(cherry picked from commit 9f8e7d6abc123...)

Это помогает отслеживать, какие изменения были перенесены и откуда. Полезно в больших командах и репозиториях.

Опция -e или --edit

Если вы хотите сразу изменить сообщение коммита:

git cherry-pick -e 9f8e7d6
# Откроется редактор для редактирования сообщения коммита

Здесь вы можете:

  • адаптировать описание под контекст целевой ветки;
  • добавить пометки о релизе;
  • уточнить, что это backport или хотфикс.

Опция -s или --signoff

Эта опция добавляет строку «Signed-off-by» в конец сообщения коммита:

git cherry-pick -s 9f8e7d6
# Добавляется подпись автора cherry-pick

Это широко используется в проектах с формальной политикой коммитов (например, в open source с DCO).


Классические сценарии использования cherry-pick

Сценарий 1. Перенос хотфикса в релизную ветку

Допустим, у вас есть:

  • ветка develop — основная разработка;
  • ветка release/1.2 — текущий релиз;
  • в develop починен критический баг, который нужно срочно забрать в релиз.

Шаги:

git checkout develop
# Ищем нужный коммит
git log --oneline

# Допустим, хотфикс — коммит 7f7f7f7
git checkout release/1.2
# Переходим в релизную ветку

git cherry-pick 7f7f7f7
# Переносим хотфикс
git push origin release/1.2
# Публикуем хотфикс

Здесь cherry-pick спасает от полноценного merge с develop, который может содержать незавершенные фичи.

Сценарий 2. Частичный перенос фичи

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

Предположим:

  • feature-search содержит 10 коммитов;
  • первые 3 коммита улучшают инфраструктуру, которую уже можно использовать в других задачах;
  • остальное — unfinished UI.

Решение:

  1. Находите первые 3 коммита в логе.
  2. Переносите только их:
git checkout main
git cherry-pick c1c1c1c c2c2c2c c3c3c3c
# Забираете только инфраструктурные изменения

Так вы не тянете за собой недоделанный интерфейс.

Сценарий 3. Восстановление случайно удаленных изменений

Иногда коммит попадает в ветку по ошибке, затем его «убирают» через reset или rebase. Если у вас есть его хеш в reflog, вы можете вернуть изменения через cherry-pick.

Пример:

git reflog
# Смотрим историю локальных действий, даже если коммиты пропали из обычного лога

# Находим нужный хеш, например 3a3a3a3
git checkout main
git cherry-pick 3a3a3a3
# Восстанавливаем потерянные изменения

Здесь cherry-pick выступает как инструмент «воскрешения» полезного коммита.


Как не сломать историю репозитория, используя cherry-pick

Внимательно относитесь к публичным веткам

Если коммит:

  • уже попал в общую ветку (например, main);
  • уже был вытолкнут на удаленный репозиторий;
  • другие разработчики уже на него ссылаются,

то бессистемное использование cherry-pick может привести к дублированию изменений и путанице в истории.

Пример проблемы:

  1. В ветке develop есть коммит A.
  2. Вы сделали git cherry-pick A в main.
  3. Потом кто-то сделал git merge develop в main.
  4. В результате изменения из A могут прилететь второй раз (хотя Git часто умно их распознаёт, но не всегда однозначно).

Лучше:

  • стараться использовать cherry-pick либо для backport’ов в релизные/поддерживающие ветки;
  • либо для переноса из временных веток в основные, но с пониманием, как ветки потом будут объединяться.

Избегайте избыточного дробления истории

Если вы переносите серию коммитов, где:

  • половина — полезные;
  • половина — «фиксы фиксов» и временные правки;

есть смысл:

  1. В исходной ветке сделать rebase interactive и привести историю в порядок.
  2. Только после этого cherry-pick’ать аккуратные коммиты.

Это сделает историю в целевой ветке чище и понятнее.


Отличия cherry-pick от revert — что когда использовать

Иногда cherry-pick путают с revert. Давайте разберемся, чтобы вы выбирали подходящий инструмент.

git cherry-pick

  • переносит изменения из другого коммита в текущую ветку;
  • создает новый коммит с теми же изменениями;
  • используется для добавления функциональности или фиксов.

git revert

  • создаёт коммит, который отменяет изменения другого коммита;
  • не удаляет коммит из истории, а накладывает обратный дифф;
  • используется, чтобы «откатить» уже попавший в историю коммит без переписывания истории.

Пример:

git revert a1b2c3d
# Создает новый коммит, возвращающий состояние так, будто a1b2c3d не применялся

Если вы хотите взять изменение из одной ветки в другую — используйте cherry-pick. Если хотите отменить уже совершенный коммит в текущей ветке — используйте revert.


Практический пример: полный цикл с конфликтами и доработкой

Давайте разберемся на примере сценария с конфликтами и доработкой через --no-commit.

Условия:

  • В ветке feature-x есть коммит fix-form, который правит валидацию формы.
  • В ветке main уже изменили форму по-своему, поэтому просто перенести fix не получится без доработок.

Шаг 1. Cherry-pick с опцией --no-commit

git checkout main
# Переходим в основную ветку

git cherry-pick --no-commit fix-form
# Применяем изменения из коммита, но не создаем новый коммит

Если появляются конфликты — Git остановится и пометит конфликтующие файлы.

Шаг 2. Ручное объединение логики

Открываем проблемный файл, видим конфликтные блоки и объединяем логику:

// До конфликта было два варианта кода, теперь вы вручную объединяете:

// Теперь вы увидите, как это выглядит в коде
func validateForm(data FormData) error {
    // Сначала проверяем формат полей
    if err := validateFormat(data); err != nil {
        return err
    }

    // Затем применяем новую логику из cherry-picked коммита
    if err := checkBusinessRules(data); err != nil {
        // Здесь мы используем обновленную бизнес-логику
        return err
    }

    return nil
}

Комментарии помогают понять, как вы смешали старую и новую логику.

Шаг 3. Завершение и единый коммит

git add path/to/form_validation.go
# Помечаем файл как решенный

git status
# Проверяем, все ли конфликты решены

git commit -m "Правки валидации формы с учетом обновленной логики main"
# Создаем один аккуратный коммит с перенесенными и доработанными изменениями

Вы не просто перенесли коммит, а адаптировали его к новой реальности ветки main.


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

Хотя инструмент полезный, есть набор ситуаций, где лучше отказаться от него.

Массовый перенос большого набора коммитов

Если нужно перенести десятки или сотни коммитов из одной ветки в другую, вероятнее всего лучше:

  • сделать merge;
  • либо сделать rebase ветки на нужную базу.

Cherry-pick такого масштаба:

  • занимает много времени;
  • повышает риск конфликтов;
  • затрудняет поддержку (история становится очень запутанной).

Если ветки всё равно скоро будут мержиться

Представьте, что:

  • вы используете Git Flow или похожий процесс;
  • ветка develop через день-два будет слита в main.

Если вам не критично получить изменения прямо сейчас, проще дождаться merge, чем:

  • сейчас cherry-pick’ать;
  • а потом еще и merge’ить.

Иначе вы можете получить дубликаты и лишние сложности.

Когда изменения зависят от других коммитов

Если коммит, который вы хотите перенести:

  • опирается на предыдущее изменение (например, использует новый модуль или функцию);
  • а это предыдущее изменение вы не переносите,

то cherry-pick может привести к:

  • некомпилирующемуся проекту;
  • скрытым логическим ошибкам.

В таких случаях лучше:

  • либо переносить всю цепочку зависимых коммитов;
  • либо выделить изменение так, чтобы оно было самодостаточным.

Заключение

git cherry-pick — это инструмент точечного переноса изменений между ветками. Он позволяет:

  • забирать конкретные фиксы и доработки, не трогая остальную историю;
  • делать аккуратные backport’ы в релизные и поддерживаемые ветки;
  • восстанавливать потерянные коммиты.

При этом важно:

  • тщательно следить за конфликтами и корректно их решать;
  • понимать последствия дублирования изменений при последующем merge;
  • использовать дополнительные опции (-n, -x, -e, -s), когда нужно более тонкое управление.

Давайте еще раз коротко зафиксируем:

  • используйте cherry-pick для выборочного переноса отдельных коммитов;
  • не применяйте его для массовых переносов, где merge или rebase будут лучше;
  • помечайте источник коммита через -x, если важно отслеживать историю;
  • не забывайте про --abort, если хотите безопасно отменить неудачный cherry-pick.

Частозадаваемые технические вопросы по теме и ответы

Как отменить уже выполненный cherry-pick, если я его закоммитил и заметил ошибку?

Если вы еще не отправили изменения в удаленный репозиторий, можно сделать reset:

git reset --hard HEAD~1
# Убираем последний коммит, созданный cherry-pick

Если коммит уже опубликован, безопаснее использовать revert:

git revert <hash-cherry-picked-коммита>
# Создаем коммит, отменяющий изменения, не ломая историю

Как понять, был ли конкретный коммит уже cherry-pick’нут в текущую ветку?

Можно использовать git log с поиском по строке (cherry picked from commit ...), если вы применяли опцию -x:

git log --grep="cherry picked from commit" -i
# Ищем коммиты, помеченные как cherry-picked

Если -x не использовался, можно сравнить патчи:

git log -p <ветка-источник>..HEAD
# Смотрите, есть ли нужные изменения в диффах

Что делать, если я запустил cherry-pick сразу с несколькими коммитами и застрял на конфликте в середине?

После решения конфликта:

git add <файлы>
git cherry-pick --continue
# Продолжаем последовательность cherry-pick

Если хотите прекратить применение оставшихся коммитов и откатиться к началу:

git cherry-pick --abort
# Восстанавливаем состояние до серии cherry-pick

Как перенести cherry-pick в другую ветку, если уже начал и решил часть конфликтов?

Если вы начали cherry-pick в ветке A, но решили, что изменения должны идти в ветку B, безопаснее всего:

  1. Отменить текущий процесс:
git cherry-pick --abort
  1. Переключиться в ветку B:
git checkout B
  1. Снова выполнить cherry-pick нужных коммитов уже в правильной ветке.

Можно ли автоматизировать cherry-pick большого набора коммитов с пропуском конфликтных?

Частично да. Можно использовать опцию --skip, чтобы пропускать проблемные коммиты:

git cherry-pick <коммиты...>
# При конфликте:
git cherry-pick --skip
# Пропускаем проблемный коммит и продолжаем со следующего

Но помните, что пропущенные коммиты останутся неперенесенными, и их судьбу нужно будет решить отдельно, возможно вручную.

Стрелочка влевоПереписывание истории - git filter-branchПоиск в истории - git bisectСтрелочка вправо

Постройте личный план изучения Git до уровня Middle — бесплатно!

Git — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Git

Открыть базу знаний

Лучшие курсы по теме

изображение курса

Основы Git

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий