1 Cherry-pick이란?
Cherry-pick은 특정 커밋 하나(또는 여러 개)를 골라서 현재 브랜치에 적용하는 기능이다.
브랜치 전체를 merge/rebase하는 것이 아니라, 원하는 커밋만 선택적으로 가져온다.
main: A --- B --- C --- D
\
feature: E --- F --- G
# F 커밋만 main에 적용하고 싶다
git cherry-pick F
main: A --- B --- C --- D --- F'
F’은 F와 같은 변경 내용을 가지지만, 새로운 커밋 해시를 가진 별개의 커밋이다.
2 기본 사용법
[main f9b2c3d] feat: Add payment gateway
Date: Mon Jan 15 14:00:00 2024 +0900
2 files changed, 47 insertions(+)
[main <새해시>] 형식으로 새로운 커밋이 생성된다. 원본 커밋(abc1234)과 날짜는 같지만 해시가 다른 새 커밋이 만들어진다.
[main 1a2b3c4] feat: Add payment gateway
[main 5d6e7f8] feat: Add payment history
[main 9g0h1i2] feat: Add refund feature
순서대로 3개의 커밋이 생성된다.
# 연속된 커밋 범위 적용 (시작 커밋은 제외, 끝 커밋 포함)
git cherry-pick abc1234..ghi9012
# 연속된 커밋 범위 적용 (시작 커밋도 포함)
git cherry-pick abc1234^..ghi90122.1 커밋하지 않고 변경사항만 가져오기
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/payment.js
new file: src/payment-gateway.js
커밋이 생성되지 않고 변경사항이 staged 상태로 남는다. 여러 cherry-pick을 -n 으로 적용한 후 하나의 커밋으로 합칠 수 있다.
3 충돌 해결
Cherry-pick 중 충돌이 발생하면:
충돌 발생 시:
Auto-merging src/payment.js
CONFLICT (content): Merge conflict in src/payment.js
error: could not apply abc1234... feat: Add payment gateway
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
On branch main
You are currently cherry-picking commit abc1234.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --skip" to skip this patch)
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: src/payment.js
You are currently cherry-picking commit abc1234. 메시지가 나타난다.
# 2. 충돌 파일을 열어서 수정 (충돌 마커 제거)
# <<<<<<< HEAD
# 현재 브랜치의 내용
# =======
# cherry-pick하려는 커밋의 내용
# >>>>>>> abc1234... feat: Add payment gateway
# 3. 충돌 해결 후 스테이징
git add src/payment.js
# 4. cherry-pick 계속 진행
git cherry-pick --continue[main f9b2c3d] feat: Add payment gateway
Date: Mon Jan 15 14:00:00 2024 +0900
2 files changed, 47 insertions(+), 3 deletions(-)
Successfully aborted cherry-pick.
4 실전 시나리오
4.1 시나리오 1: 핫픽스를 여러 브랜치에 적용
main에서 긴급 버그를 수정한 후, 해당 수정을 develop 브랜치에도 적용해야 할 때:
4.2 시나리오 2: feature 브랜치에서 일부 커밋만 릴리스
feature 브랜치에 여러 커밋이 있지만, 그 중 일부만 먼저 릴리스해야 할 때:
ghi9012 feat: Add refund feature
def5678 feat: Add payment history
abc1234 feat: Add payment gateway
[main 1a2b3c4] feat: Add payment gateway
Date: Mon Jan 15 14:00:00 2024 +0900
2 files changed, 47 insertions(+)
[main 5d6e7f8] feat: Add payment history
Date: Mon Jan 15 15:00:00 2024 +0900
1 file changed, 23 insertions(+)
4.3 시나리오 3: 잘못된 브랜치에 커밋한 경우
main에 직접 커밋해버린 것을 feature 브랜치로 옮길 때:
4.4 시나리오 4: release 브랜치에 핫픽스 적용
Git Flow에서 hotfix를 release 브랜치에 cherry-pick으로 적용:
5 Cherry-pick vs Merge vs Rebase
| 항목 | Cherry-pick | Merge | Rebase |
|---|---|---|---|
| 적용 범위 | 특정 커밋만 | 브랜치 전체 | 브랜치 전체 |
| 새 커밋 생성 | O (복사본) | O (병합 커밋) | O (재배치) |
| 원본 커밋 | 변경 없음 | 변경 없음 | 해시 변경 |
| 주 용도 | 선택적 적용 | 브랜치 통합 | 이력 정리 |
6 주의사항
- Cherry-pick된 커밋은 원본과 다른 해시값을 가진다. 같은 변경사항이 두 브랜치에 각각 다른 커밋으로 존재하게 된다.
- 나중에 두 브랜치를 merge할 때 동일한 변경사항이 중복으로 적용될 수 있다. Git이 대부분 자동으로 처리하지만, 간혹 충돌이 발생할 수 있다.
- Cherry-pick을 남발하면 이력 추적이 어려워진다. 브랜치 전체를 merge/rebase하는 것이 더 적합한 상황에서는 그 방법을 사용하자.
- Cherry-pick은 해당 커밋의 변경사항만 적용한다. 그 커밋이 의존하는 이전 커밋의 변경사항은 포함되지 않으므로, 독립적이지 않은 커밋을 cherry-pick하면 문제가 생길 수 있다.
7 요약
| 명령어 | 동작 |
|---|---|
git cherry-pick <hash> |
특정 커밋 적용 |
git cherry-pick A B C |
여러 커밋 적용 |
git cherry-pick A^..C |
범위 커밋 적용 (A 포함) |
git cherry-pick -n <hash> |
커밋 없이 변경사항만 적용 |
git cherry-pick --continue |
충돌 해결 후 계속 |
git cherry-pick --abort |
cherry-pick 취소 |