Skip to main content

Що таке git cherry-pick і коли його використовувати?

git cherry-pick копіює конкретний коміт з однієї гілки і застосовує його до поточної гілки як новий коміт.

Теорія

TL;DR

  • Cherry-pick - це як зірвати одну вишню з дерева, не трясучи весь кущ: береш рівно той один коміт, нічого зайвого.
  • Створює новий коміт з тими самими змінами, повідомленням і автором, але з новим хешем і твоєю гілкою як батьківською.
  • Головна різниця від merge: merge тягне всю історію гілки, cherry-pick бере diff тільки одного коміту.
  • Правило вибору: потрібно 1-3 коміти вибірково? Cherry-pick. Більше 5? Краще merge або rebase.

Швидкий приклад

bash
# В main є bugfix, develop відстає git log --oneline main # a1b2c3d Fix login crash <- потрібне це # f4e5d6c Initial commit git checkout develop git cherry-pick a1b2c3d git log --oneline develop # b7c8d9e Fix login crash <- новий хеш, ті самі зміни # f4e5d6c Initial commit

Новий коміт на develop має той самий message і diff, але інший хеш. Оригінальний коміт залишається на main без змін.

Як працює cherry-pick

Git витягує diff з цільового коміту (точний патч змін) і застосовує його до робочої директорії через three-way merge. Якщо все підходить чисто, Git робить коміт автоматично, зберігаючи оригінального автора, дату і повідомлення. Якщо є конфлікти, зупиняється і дає їх вирішити. Саме через three-way merge cherry-pick справляється з переміщеними рядками краще ніж звичайний git apply.

Коли використовувати

  • Security hotfix на release-гілку: патч є в main, продакшн на release/v4.17, і потрібно доставити один коміт туди прямо зараз.
  • Бекпорт конкретного bugfix: стабільна гілка отримує одне виправлення з main без незакінчених фіч.
  • Витягнути один коміт з feature-гілки: решта фічі не готова, але один коміт вже можна шипити.
  • Коли не варто: якщо потрібно 5+ комітів. Cherry-pick великого діапазону створює дублікати в історії і ускладнює майбутні merge. Використовуй git merge або git rebase.

Типові помилки

Помилка 1: Cherry-pick merge-коміту без -m

bash
git cherry-pick M # fatal: commit M is a merge but no -m option given

Merge-коміт має двох батьків. Git не знає, з якого боку брати diff. Виправлення:

bash
git cherry-pick -m 1 M # -m 1 = перший (mainline) батько

Помилка 2: git commit після конфлікту замість --continue

bash
# Вирішив конфлікт, і потім: git add . git commit -m "Fixed" # Неправильно - губляться метадані cherry-pick # Правильно: git add . git cherry-pick --continue

Помилка 3: Неправильний синтаксис діапазону

bash
git cherry-pick A..C # Застосовує B і C, пропускає A git cherry-pick A^..C # Застосовує A, B і C - це зазвичай і потрібно

Діапазон A..C виключає A. Додай ^, щоб включити його.

Помилка 4: Короткий хеш у великих репозиторіях

У репозиторіях з довгою історією (як Linux kernel) короткі хеші можуть збігатися. Перевіряй перед cherry-pick:

bash
git log --oneline | grep a1b2c3 git cherry-pick a1b2c3d4e5f6 # використовуй повний хеш якщо є сумніви

Де зустрічається

  • Kubernetes: cherry-pick патчі безпеки (CVE) з main на release-1.28 без зайвих змін.
  • Node.js: застосовує виправлення вразливостей у crypto до стабільної v18.x з main (наприклад, реліз v18.17.1).
  • React: портує точкові виправлення продуктивності з canary на stable/18.
  • Linux kernel: бекпортить виправлення драйверів на стабільні гілки діапазонами комітів.

Питання на співбесіді

Q: Яка різниця між git cherry-pick і git revert?
A: Cherry-pick застосовує коміт вперед, додаючи його зміни до гілки. Revert створює новий коміт, що скасовує зміни попереднього. Revert безпечніший на спільних гілках, бо не переписує історію.

Q: Як cherry-pick-нути діапазон комітів включно з першим?
A: git cherry-pick A^..B. Синтаксис A..B виключає A, тому додаєш ^ щоб включити його.

Q: Що відбувається з автором і датою оригінального коміту?
A: Вони зберігаються в новому коміті. Committer і committer date відображають тебе і поточний час.

Q: Коли cherry-pick спрацює там, де git apply впаде?
A: Cherry-pick використовує three-way merge, тому обробляє випадки де навколишній код змістився або переїхав. git apply - це простий патч, який падає якщо рядки контексту не збігаються точно.

Q: Чому в монорепо зі строгим відстеженням залежностей команди можуть надавати перевагу cherry-pick над merge для hotfix?
A: Merge тягне весь граф гілки, додаючи шум в історію залежностей і ускладнюючи роботу автоматизованих сканерів. Cherry-pick копіює тільки diff, тримаючи граф комітів лінійним і зміну прив'язаною до одної точки.

Приклади

Базовий: Hotfix на release-гілку

bash
# Security fix потрапив в main git checkout main git log --oneline -3 # a1b2c3d Fix: validate req.body size (prevents DoS) # ... # Застосовуємо на production release-гілку git checkout release/v4.17 git cherry-pick a1b2c3d # Перевіряємо git log --oneline -2 # f9e8d7c Fix: validate req.body size (prevents DoS) # 3a2b1c0 Previous release commit

Одна команда, один коміт. Release-гілка отримує виправлення без решти змін з main. Це найпоширеніший сценарій cherry-pick у продакшн-кодових базах.

Проміжний: Вирішення конфлікту під час cherry-pick

bash
git checkout feature-stable git cherry-pick b2c3d4e # CONFLICT (content): Merge conflict in src/auth.js # Відкрий src/auth.js, вирісши маркери конфлікту # Потім: git add src/auth.js git cherry-pick --continue # [feature-stable e5f6g7h] Add token expiry check

Якщо передумав - git cherry-pick --abort повертає гілку до стану до початку операції. Я сам кілька разів ішов на abort, коли конфлікт ставало зрозуміло: коміт залежить від змін, яких у цільовій гілці просто ще немає.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?