- Published on
Git rebase 후 PR 커밋이 꼬일 때 복구 가이드
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 브랜치 히스토리를 깔끔하게 만들려고 git rebase를 썼는데, PR을 열어보니 커밋이 중복으로 보이거나, 이미 머지된 커밋이 다시 딸려오거나, 리뷰 코멘트가 전부 사라지는 상황을 한 번쯤 겪습니다. 대부분은 “내 로컬에서는 정상인데 PR만 이상함”처럼 보여서 더 당황스럽습니다.
이 글은 rebase 후 PR 커밋이 꼬이는 대표 패턴을 분류하고, 각 패턴에 맞는 **복구 루트(원복, 재정렬, PR 재생성)**를 안전하게 수행하는 방법을 정리합니다.
참고: 이 글은 GitHub PR을 기준으로 설명하지만, GitLab/Merge Request도 원리는 동일합니다.
왜 rebase 하면 PR 커밋이 꼬여 보일까
핵심은 rebase가 **커밋을 “이동”시키는 게 아니라 “새로 생성”**한다는 점입니다. 커밋은 내용이 같아도 SHA가 바뀌면 완전히 다른 커밋으로 취급됩니다.
PR은 보통 “내 브랜치가 베이스 브랜치에 없는 커밋들”을 보여주는데, rebase를 잘못 적용하면 다음이 발생합니다.
- 이미 베이스에 들어간 커밋을 다시 내 브랜치 위에 얹음
- 내 브랜치의 커밋이 새 SHA로 재작성되면서 PR이 중복처럼 보임
- force push로 PR의 커밋 그래프가 바뀌어 리뷰 맥락이 깨짐
이 현상은 Git이 틀린 게 아니라, “PR이 비교하는 기준(base)과 내 브랜치 히스토리”가 어긋난 결과입니다.
먼저 상태 진단: 무엇이 꼬였는지 빠르게 확인
1) PR의 base branch가 맞는지 확인
가장 흔한 실수는 PR base가 main이어야 하는데 develop 혹은 반대로 잡혀 있는 경우입니다. base가 바뀌면 PR에 보이는 커밋 집합이 완전히 달라집니다.
- GitHub PR 화면에서
base: ...확인 - 잘못됐으면 base를 올바르게 변경하고 커밋 목록이 정상화되는지 먼저 봅니다
2) 내 브랜치가 base를 “정확히” 따라가고 있는지 확인
로컬에서 다음을 실행합니다.
# 최신 원격 상태로 동기화
git fetch origin
# 내 브랜치가 base와 얼마나 다른지 확인
git log --oneline --decorate --graph --left-right origin/main...HEAD
- 왼쪽(
origin/main)에만 있는 커밋이 많다면 base가 빠르게 진화했고, 내 브랜치가 오래된 상태일 수 있습니다. - 오른쪽(내 브랜치)에만 있는 커밋이 “내가 의도한 작업 커밋”인지 확인합니다.
3) 중복 커밋처럼 보일 때는 patch 동등성 확인
SHA는 달라도 내용이 같은 커밋이 있을 수 있습니다. 이때는 --cherry 옵션이 유용합니다.
git log --oneline --cherry origin/main...HEAD
--cherry는 “내용이 같은 커밋”을 어느 정도 감지해 중복 여부 판단에 도움을 줍니다.
복구 전략 0: 무조건 백업 브랜치부터 만든다
rebase/force push가 얽힌 복구는 실수하면 더 꼬입니다. 시작 전에 현재 상태를 그대로 보존합니다.
# 현재 브랜치를 백업 브랜치로 남김
git checkout my-feature
git branch backup/my-feature-before-fix
git push origin backup/my-feature-before-fix
이 한 줄 덕분에 언제든 원래 상태로 돌아갈 수 있습니다.
케이스 1: 잘못된 브랜치 위에서 rebase 했다 (엉뚱한 커밋이 딸려옴)
증상
- PR에 내가 건드리지 않은 커밋이 대량으로 포함됨
- 다른 기능 브랜치의 커밋이 섞여 들어옴
원인
git rebase origin/main을 해야 하는데origin/develop에 했거나- 기능 브랜치가 다른 기능 브랜치를 base로 만들어진 상태에서 또 rebase함
해결: 올바른 base 위로 “재정렬(rebase)”하거나 “재생성”
가장 안전한 방법은 올바른 base에서 새 브랜치를 만드는 방식입니다.
- 올바른 base에서 새 브랜치 생성
git fetch origin
git checkout -b my-feature-clean origin/main
- 기존 브랜치에서 “내 커밋만” 골라서 가져오기
- 커밋 개수가 적으면
cherry-pick이 가장 명확합니다.
# 예: 내 작업 커밋 3개를 순서대로 적용
git cherry-pick abc1234
git cherry-pick def5678
git cherry-pick 9876fed
- 새 브랜치를 푸시하고 PR을 새로 열거나 기존 PR의 브랜치를 바꿀 수 있으면 교체
git push -u origin my-feature-clean
이 방식은 “꼬인 히스토리 위에서 수술”하는 것보다 훨씬 예측 가능하고, 리뷰어 입장에서도 변경점이 깔끔합니다.
케이스 2: rebase 후 force push 했더니 PR에 커밋이 중복으로 보인다
증상
- 같은 내용의 커밋이 두 벌처럼 보임
- PR 커밋 수가 갑자기 늘어남
원인
- 베이스 브랜치에 이미 들어간 커밋을 내 브랜치가 다시 포함
- 또는 머지 커밋/리베이스가 혼재되어 PR 비교가 혼란스러워짐
해결 1: “내 브랜치에만 있어야 하는 커밋”만 남기기 (interactive rebase)
우선 내 브랜치의 커밋 범위를 명확히 잡습니다.
git fetch origin
git rebase -i origin/main
에디터가 열리면, 내 작업과 무관하거나 이미 main에 들어간 커밋이 보이는지 확인하고 제거합니다.
- 제거: 해당 줄을 삭제하거나
drop으로 바꿈 - 여러 커밋을 합치기:
squash또는fixup
완료 후 원격에 반영합니다.
# force push는 반드시 안전 옵션 사용
git push --force-with-lease
--force-with-lease는 원격 브랜치가 내 로컬이 아는 상태에서 바뀌었으면 푸시를 막아, 팀원이 올린 커밋을 덮어쓰는 사고를 줄입니다.
해결 2: PR이 너무 망가졌으면 “새 PR”이 더 싸다
리뷰 코멘트가 커밋 SHA에 붙어있어서, rebase/force push를 반복하면 리뷰 맥락이 계속 깨집니다. 이럴 땐 과감히:
- 위의 “케이스 1 방식”으로
my-feature-clean을 만들고 - 새 PR을 열고
- 기존 PR은 close 하되 링크로 연결
이게 장기적으로 비용이 적습니다.
케이스 3: rebase를 하다 충돌 해결을 잘못해서 내용이 꼬였다
증상
- PR 커밋은 그럴듯한데 실제 코드가 일부 사라짐
- 충돌 해결 과정에서 특정 파일 변경이 누락
원인
- 충돌 해결 시 잘못된 버전을 선택
- rebase 중간에 스테이징/커밋을 잘못 수행
해결: rebase를 중단하고, 올바른 지점으로 되돌린 뒤 재시도
1) rebase 진행 중이면 즉시 중단
git rebase --abort
2) 이미 끝났다면 reflog로 “rebase 전” 커밋 찾기
git reflog --date=iso
출력에서 rebase (start) 직전의 커밋을 찾습니다. 예를 들어 되돌릴 커밋이 1122aabb라면:
git reset --hard 1122aabb
그 다음, 다시 올바른 절차로 rebase를 진행합니다.
git fetch origin
git rebase origin/main
마지막으로 원격 반영:
git push --force-with-lease
케이스 4: PR base에 쌓인 커밋을 내 브랜치에 “merge”로 받아서 히스토리가 지저분해졌다
증상
- PR 커밋 탭에 merge 커밋이 잔뜩 생김
- 리뷰가 커밋 단위로 보기 어려움
해결: merge 커밋을 없애고 선형 히스토리로 정리
팀 정책이 “PR은 rebase로 선형 유지”라면, 기능 브랜치에서 origin/main을 merge로 당겨온 기록을 정리해야 합니다.
가장 실전적인 방법은 “깨끗한 브랜치 재생성”입니다.
git fetch origin
git checkout -b my-feature-linear origin/main
git cherry-pick <내_작업_커밋_범위>
# 예: 연속 커밋이면 범위 cherry-pick도 가능
# git cherry-pick a1b2c3d..d4e5f6a
git push -u origin my-feature-linear
이후 새 PR로 전환하면 커밋 그래프가 단순해지고 리뷰 효율이 크게 올라갑니다.
실전 처방전: “PR 커밋이 꼬였다”를 가장 빨리 끝내는 체크리스트
- PR base branch부터 확인
git fetch origin후origin/main...HEAD로 차이 확인- 백업 브랜치 생성 후 푸시
- 아래 중 하나를 선택
- 수술:
git rebase -i origin/main으로 불필요 커밋 제거 후git push --force-with-lease - 재생성:
origin/main에서 새 브랜치 만들고cherry-pick으로 내 커밋만 이식
- 수술:
- 리뷰 맥락이 중요하면 새 PR이 더 낫다
팀에서 재발 방지: 안전한 rebase 운용 규칙
1) 공유 브랜치에서는 rebase 금지, 개인 브랜치에서만 허용
여러 명이 동시에 푸시하는 브랜치에서 rebase는 히스토리 재작성으로 충돌을 부릅니다. 개인 작업 브랜치에서만 rebase를 허용하고, 공유 브랜치는 merge만 허용하는 팀도 많습니다.
2) force push는 --force-with-lease만 사용
git push --force-with-lease
로컬이 모르는 원격 변경이 있으면 실패하므로, “동료 커밋 덮어쓰기”를 크게 줄입니다.
3) PR 올리기 전 “내 브랜치가 main에서 갈라진 지점”을 항상 의식
다음 명령으로 분기점을 확인할 수 있습니다.
git merge-base origin/main HEAD
분기점이 너무 오래됐으면, PR 올리기 전에 rebase로 최신 main을 반영하거나(팀 룰에 따라), 아예 새 브랜치로 이식하는 게 낫습니다.
자주 묻는 질문
이미 PR에 리뷰 코멘트가 많이 달렸는데, rebase로 커밋이 바뀌면 코멘트가 사라지나
라인 코멘트는 상황에 따라 “outdated”로 남거나 매칭이 끊길 수 있습니다. 코멘트 보존이 최우선이면, 히스토리 정리는 최소화하고(가능하면 merge로 유지), 정말 필요할 때만 --force-with-lease를 사용하세요.
reset --hard는 위험하지 않나
위험합니다. 그래서 이 글에서 먼저 backup/... 브랜치를 원격에 푸시해 두라고 강조했습니다. 백업이 있으면 reset --hard도 “되돌릴 수 있는 작업”이 됩니다.
마무리
rebase 후 PR 커밋이 꼬이는 문제는 대개 “내 커밋이 어디에 있어야 하는지”와 “PR이 무엇을 비교하는지”가 어긋나서 생깁니다. 복구는 두 갈래입니다.
- 히스토리를 수술해서 고친다:
rebase -i와--force-with-lease - 더 안전하게 갈아탄다: 깨끗한 브랜치 재생성 후
cherry-pick
운영/장애 대응 글을 쓰다 보면, 이런 문제도 결국 “원인 진단 후 체크리스트대로 복구”가 제일 빠르다는 걸 체감합니다. 비슷한 방식의 진단형 글이 필요하면 다음 글들도 함께 참고해보세요.