История Git: когда использовать rebase, cherry-pick и bisect
Rebase переписывает последовательность коммитов, cherry-pick переносит отдельные изменения, а bisect ищет коммит, сломавший поведение. Разбираем цену каждого подхода и безопасный рабочий порядок.

В Git одна и та же задача часто решается тремя командами, но последствия у них разные: rebase меняет историю, cherry-pick копирует отдельный коммит, а bisect сужает диапазон поиска регрессии. Ошибка в выборе стоит не только времени: после неосторожного rebase придётся согласовывать переписанную ветку, а после неудачного cherry-pick — разруливать конфликт и возможные дубли изменений. Ниже — практическая схема для Git 2.40 и новее: что происходит с графом коммитов, какую команду выбрать и где операция ломается.
Три команды — три разных вопроса
Начните не с команды, а с формулировки задачи.
- Нужно поставить свои коммиты поверх свежего состояния другой ветки — используйте
rebase. - Нужно перенести конкретное исправление, не забирая всю ветку, — используйте
cherry-pick. - Нужно найти первый коммит, после которого тест или функция перестали работать, — используйте
bisect.
Все три операции могут привести к конфликтам, но конфликт возникает по разным причинам. При rebase Git повторно применяет последовательность коммитов на новой базе. При cherry-pick он пытается применить один выбранный патч. При bisect Git не «исправляет» историю, а временно переключает рабочее дерево между ревизиями.
| Команда | Что меняет | Когда применять | Главный риск |
|---|---|---|---|
rebase | Перестраивает коммиты на другой базе | Локальная ветка, которую ещё не используют другие | Новые идентификаторы коммитов и необходимость force push |
cherry-pick | Создаёт копию выбранного изменения в текущей ветке | Точечный hotfix или перенос независимого исправления | Конфликт, неполный контекст и дублирование коммита |
bisect | Переключает рабочее дерево между коммитами для поиска регрессии | Есть известный хороший и плохой коммит | Неверная проверка или грязное рабочее дерево дают ложный результат |
Rebase отвечает на вопрос «как линейно представить мою работу», cherry-pick — «какое изменение мне нужно», а bisect — «где именно всё сломалось».
*Регрессия — новое ухудшение поведения, которого не было в более ранней версии: например, тест проходил на старом коммите, а после одного из следующих начал падать.
Rebase: обновить ветку без merge-коммита
Представим, что ветка feature отделилась от main, а в main уже появились новые коммиты. Rebase переносит коммиты feature на вершину актуального main. История становится линейной, но сами коммиты получают новые хеши.
Безопасная последовательность
- Проверьте рабочее дерево. Выполните
git status. Перед rebase не должно быть незаписанных изменений, либо их нужно временно сохранить. Проверка: Git показывает чистое рабочее дерево или явно перечисляет только то, с чем вы осознанно работаете. - Обновите ссылки на удалённый репозиторий. Выполните
git fetch origin. Команда получает новые объекты и указатели веток, но не меняет ваши файлы. Проверка: в выводе видны обновления вродеorigin/main, если удалённая ветка изменилась. - Перейдите в свою ветку. Используйте
git switch feature. Проверка:git branch --show-currentвыводитfeature. - Запустите rebase. Выполните
git rebase origin/main. Git применит коммиты feature поверх удалённой ветки main. Проверка: команда завершится сообщением об успешном rebase, аgit log --oneline --graph --decorate -n 12покажет новую последовательность. - Запустите тесты. Команда зависит от проекта: используйте штатный тестовый набор и проверку сборки. Проверка: тесты проходят уже на новой базе, а не только на старом состоянии feature.
Если возник конфликт, Git остановится. Посмотрите список файлов через git status, исправьте конфликт вручную, добавьте готовый файл командой git add путь/к/файлу и продолжите через git rebase --continue. Если выбранный путь оказался неверным, безопаснее отменить незавершённую операцию командой git rebase --abort, чем продолжать наугад.
Почему после rebase нужен force push
Если ветка уже опубликована, rebase меняет хеши её коммитов. Обычный git push может быть отклонён, потому что удалённая ветка больше не является прямым продолжением вашей локальной. Для собственной ветки обычно применяют:
git push --force-with-lease origin feature
--force-with-lease проверяет, что удалённая ветка не успела измениться после вашего последнего получения данных. Это не делает операцию безопасной абсолютно, но снижает риск затереть чужой новый коммит. Общую ветку команды и ветку с активным pull request не переписывайте без согласования.
Cherry-pick: перенести один коммит, а не всю ветку
Допустим, исправление уже сделано в feature, но его нужно срочно отправить в release. Слияние всей feature-ветки может принести незавершённые изменения. Cherry-pick берёт патч выбранного коммита и создаёт в текущей ветке новый коммит с другим идентификатором.
Рабочий сценарий
- Переключитесь на ветку-получатель:
git switch release. Проверка:git branch --show-currentвыводитrelease. - Обновите удалённые ссылки:
git fetch origin. Проверка: нужный исходный коммит существует в локальной истории, например его можно найти черезgit show <commit>. - Посмотрите содержимое изменения:
git show --stat <commit>, затем при необходимостиgit show <commit>. Проверка: вы понимаете, какие файлы и поведение переносите. - Примените коммит:
git cherry-pick <commit>. Проверка: Git создаёт новый коммит или останавливается на конфликте. - Запустите тесты и проверьте целевую ветку. Проверка: исправление работает в контексте release, а не только в feature.
Если коммит зависит от предыдущих изменений, одного хеша недостаточно. Можно указать несколько хешей, но сначала проверьте порядок и зависимости. Переносить большой диапазон стоит только после просмотра истории: синтаксис диапазонов легко выбрать неправильно.
При конфликте исправьте файлы, добавьте их через git add и продолжите командой git cherry-pick --continue. Если операция больше не нужна, используйте git cherry-pick --abort. Не удаляйте конфликтующие маркеры и не считайте успешным сам факт создания коммита: после cherry-pick обязательны тесты.
Bisect: найти коммит, который сломал поведение
Bisect полезен, когда вы знаете две точки: на старом коммите всё работает, на новом — уже нет. Git выбирает середину диапазона, вы запускаете проверку и отмечаете результат. При каждом шаге диапазон уменьшается примерно вдвое, поэтому среди большого числа коммитов обычно нужно проверить значительно меньше ревизий, чем просматривать их подряд.
Ручной поиск
- Сохраните или уберите локальные изменения. Bisect переключает файлы между версиями, поэтому незакоммиченные правки могут помешать.
- Запустите поиск:
git bisect start. - Отметьте текущий плохой коммит:
git bisect bad. Обычно это версия, где ошибка воспроизводится. - Отметьте известный рабочий коммит:
git bisect good <хеш>. Нужен именно коммит, где проверка ещё проходит. - Проверьте предложенную ревизию. Если ошибка есть, выполните
git bisect bad; если нет —git bisect good. Повторяйте, пока Git не назовёт первый проблемный коммит. - Завершите режим командой
git bisect reset. Проверка: вы вернулись к исходной ветке или ревизии.
Критерий good/bad должен быть одинаковым на каждом шаге. Если тест иногда падает из-за сети, времени, случайных данных или внешнего сервиса, bisect будет выбирать неверное направление. Сначала сделайте проверку детерминированной или повторяйте её несколько раз по заранее установленному правилу.
Автоматический запуск
Если проверка выполняется одной командой и возвращает код завершения 0 при успехе, можно использовать автоматический режим:
git bisect start
git bisect bad HEAD
git bisect good <known-good-commit>
git bisect run ./scripts/check-regression.sh
git bisect reset
Скрипт должен возвращать 0 для good и ненулевой код для bad. Это не место для команды, которая иногда завершается ошибкой из-за инфраструктуры: Git воспримет такую ошибку как признак плохого коммита. Перед запуском проверьте скрипт на заведомо хорошем и плохом состоянии.
Что ломается чаще всего
- Rebase общей ветки. Коллеги уже основывают работу на старых хешах, а после force push их локальная история расходится. Для общей ветки выбирайте обычное слияние или согласованный процесс обновления.
- Cherry-pick без зависимостей. Исправление переносится, но не переносится изменение схемы базы, конфигурация или вспомогательный коммит. В результате патч применяется, а функция не работает.
- Повторный cherry-pick. Git может создать второй коммит с тем же смыслом. Ищите исходный коммит и его аналоги в истории, прежде чем переносить исправление снова.
- Bisect с плохим диапазоном. Если отмеченный good-коммит уже содержит ошибку, Git всё равно найдёт «первый плохой» только внутри неверно заданного диапазона.
- Потеря контекста после переключения. Не начинайте bisect с незакоммиченными файлами. Если изменения нужно сохранить, отдельно зафиксируйте их или временно уберите и верните после
git bisect reset.
Как выбрать команду в рабочем процессе
Для регулярного обновления короткоживущей feature-ветки выбирайте rebase, если правила проекта допускают переписывание вашей ветки. Для срочного исправления в нескольких поддерживаемых ветках — cherry-pick, но фиксируйте в описании pull request исходный коммит и проверяйте зависимости. Для регрессии, которую уже можно воспроизвести, — bisect; сначала подготовьте надёжную автоматическую проверку.
Не смешивайте цели. Rebase не предназначен для поиска виновного коммита, cherry-pick не заменяет полноценное слияние фичи, а bisect не исправляет найденную проблему. Он только помогает ответить, где начать разбор.
Что сделать дальше
Добавьте в командный процесс три проверки: запрет force push в общие ветки, запуск тестов после rebase и cherry-pick, а также небольшой детерминированный smoke-тест для bisect. После любой операции смотрите не только на сообщение Git, но и на граф через git log --graph --oneline --decorate. В проде отдельно отслеживайте откаты, повторные исправления и конфликты при переносе релизных коммитов: именно эти сигналы показывают, что выбранный процесс истории стал дорогим.
Создатель презентаций: Структура и текст каждого слайда: заголовки-утверждения, одна мысль на слайд, заметки докладчику.
Спросить за 150 ₽Источники: Git Reference: rebase, Git Reference: bisect
Частые вопросы
Можно ли делать rebase ветки, которую уже отправили на сервер?
Что делать, если rebase остановился на конфликте?
Почему cherry-pick создал коммит с другим хешем?
Можно ли cherry-pick применить к коммиту с зависимостями?
Что делать, если bisect нашёл не тот коммит?
Сработает ли эта схема в другой версии Git?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.