- Published on
Git rebase 후 강제푸시 없이 PR 정리하는 법
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
git rebase는 커밋을 예쁘게 만들고(불필요한 merge 커밋 제거, 커밋 메시지 정리, squash 등) 리뷰 부담을 줄이는 데 매우 유용합니다. 문제는 이미 PR을 올린 브랜치에서 rebase를 해버리면 커밋 SHA가 바뀌고, 원격 브랜치를 업데이트하려면 보통 강제푸시(force push) 가 필요하다는 점입니다.
하지만 현실에서는 다음 같은 이유로 강제푸시가 금기이거나 불가능한 경우가 많습니다.
- 보호 브랜치/정책으로 force push가 막혀 있음
- 리뷰 중인 PR에서 커밋이 사라지거나 코멘트 위치가 어긋나는 것을 싫어함
- CI/배포 파이프라인이 “이력 변경”에 민감함
- 여러 사람이 같은 feature 브랜치를 공유하고 있음
이 글에서는 rebase를 이미 해버렸거나, rebase를 하고 싶지만 강제푸시 없이 PR을 깔끔하게 유지해야 할 때 쓸 수 있는 패턴을 정리합니다. 핵심은 “PR의 대상이 되는 브랜치를 바꾸지 않고도(= force push 없이도) 결과를 반영하는 방법”을 선택하는 것입니다.
> 참고: CI가 PR 기준으로 돌아가고, 캐시가 꼬여 빌드 시간이 갑자기 늘어나는 상황도 종종 겪습니다. 이럴 땐 캐시 키/경로/권한을 점검하는 글도 함께 보면 좋습니다: GitHub Actions 캐시가 안 먹을 때 키·경로·권한
왜 rebase 후에는 force push가 필요한가
rebase는 커밋을 “재작성”합니다. 즉, 동일한 변경 내용이라도 커밋 객체가 새로 만들어져 SHA(해시)가 달라집니다.
- PR 브랜치가
origin/feature이고, - 로컬에서
git rebase main을 하면, - 로컬
feature는 원격origin/feature와 완전히 다른 커밋 그래프를 갖게 됩니다.
이 상태에서 일반 푸시(git push)를 하면 “non-fast-forward”로 거절되고, 업데이트하려면 --force 또는 --force-with-lease가 필요합니다.
그럼 강제푸시 없이 PR을 정리하려면?
- 기존 PR 브랜치(원격)를 바꾸지 않는다
- 대신 새 브랜치를 만들거나, merge 기반으로 PR을 최신화하거나, PR을 대체하는 새 PR을 만든다
이 중 어떤 전략이 팀 정책과 상황에 맞는지 선택하면 됩니다.
전략 1) “새 브랜치 + 새 PR”로 갈아타기 (가장 안전)
강제푸시가 금지인 팀에서 가장 깔끔하고 사고가 적은 방법은 rebase된 결과를 새 브랜치로 푸시하고 새 PR을 만드는 것입니다.
언제 쓰나
- force push가 정책상 불가
- 기존 PR에서 리뷰 코멘트가 많이 달렸지만, 커밋 히스토리를 정리한 버전을 새로 리뷰받고 싶음
- 기존 PR이 꼬였거나(충돌/이력 혼란) CI가 이상하게 도는 상황
절차
- 현재 PR 브랜치(원격 기준)를 보존한 채, 로컬에서 rebase된 HEAD를 새로운 브랜치로 분기합니다.
# PR 브랜치가 feature 라고 가정
git checkout feature
git fetch origin
git rebase origin/main
# 새 브랜치 생성
git checkout -b feature-rebased
# 새 브랜치를 원격에 푸시
git push -u origin feature-rebased
GitHub에서
feature-rebased로 새 PR을 생성합니다.기존 PR은 다음 중 하나로 처리합니다.
- Close: 새 PR 링크를 남기고 종료
- Draft로 전환: 기록 보존 목적
장점
- 기존 PR 히스토리/코멘트가 깨지지 않음
- 정책(보호 규칙)과 충돌하지 않음
- “지금부터 리뷰할 대상”이 명확해짐
단점
- PR이 2개가 되어 관리 비용이 늘 수 있음
- 기존 PR 코멘트를 새 PR로 옮겨야 할 수 있음
> 팁: 새 PR 설명에 “기존 PR 링크, 변경 이유, 리뷰어가 다시 봐야 할 포인트”를 요약하면 리뷰 비용을 크게 줄일 수 있습니다.
전략 2) 기존 PR은 유지하고, rebase 결과는 “merge 커밋”으로 따라잡기
조금 역설적이지만, rebase를 했더라도 PR 브랜치에는 rebase 결과를 ‘그대로’ 강제푸시할 수 없으니, PR 브랜치를 최신 main과 merge해서 충돌을 해결하고 진행하는 방식입니다.
즉, “히스토리를 예쁘게 만들기 위해 rebase”를 했는데, PR 브랜치에는 merge 커밋이 생길 수 있습니다. 하지만 팀이 “강제푸시 금지, 대신 merge 허용”이라면 현실적인 타협안이 됩니다.
절차
# 원격 최신화
git fetch origin
# PR 브랜치로 이동
git checkout feature
# main을 merge해서 최신화
git merge origin/main
# 충돌 해결 후 커밋
git push origin feature
장점
- 기존 PR을 그대로 유지(링크/코멘트/체크 유지)
- force push 불필요
단점
- 커밋 히스토리가 복잡해질 수 있음
- rebase로 정리한 커밋 메시지/구조가 PR 브랜치에 반영되지 않음(결과만 반영)
이 방식은 “PR을 깨끗하게 보이게 만들겠다”는 목표보다는 “PR을 안전하게 최신화하고 머지 가능 상태로 만들겠다”는 목표에 더 적합합니다.
전략 3) rebase된 커밋을 cherry-pick으로 새 브랜치에 재구성
전략 1(새 브랜치 + 새 PR)과 비슷하지만, rebase를 이미 해버렸고 그 결과에서 일부 커밋만 골라 PR을 새로 구성하고 싶을 때 유용합니다.
절차
- 기준 브랜치에서 새 브랜치 생성
git fetch origin
git checkout -b feature-clean origin/main
- 기존 브랜치(또는 rebase된 로컬 브랜치)에서 필요한 커밋만 골라 적용
# 커밋 여러 개를 연속으로 가져오기(범위)
# A^..B 는 A부터 B까지 포함
git cherry-pick A^..B
# 또는 개별 커밋 선택
git cherry-pick <commit1> <commit2> <commit3>
- 푸시 후 새 PR
git push -u origin feature-clean
장점
- PR에 포함될 커밋을 “의도대로” 정제 가능
- 불필요한 커밋(실험/되돌림/로그 등)을 제거하기 쉬움
단점
- 충돌이 날 수 있고, 해결 비용이 발생
- 커밋 수가 많으면 번거로움
전략 4) PR을 “스쿼시 머지”로 끝내고, 브랜치 히스토리 정리는 포기
팀 정책이 main의 히스토리만 중요하고 PR 브랜치 히스토리는 덜 중요하다면, rebase를 굳이 PR 브랜치에 반영하지 않고:
- PR은 리뷰가 끝나는 대로
- GitHub의 Squash and merge로 머지
하는 것도 실무에서 흔한 선택입니다.
언제 좋나
- 커밋 히스토리를
main에서만 관리하고 싶다 - PR 브랜치 정리보다 “리뷰/검증된 단일 변경”이 중요하다
주의점
- PR 브랜치의 커밋이 지저분해도
main은 깔끔해짐 - 다만 PR 리뷰 중 “커밋 단위 리뷰”가 필요한 팀에는 맞지 않을 수 있음
실전에서 가장 많이 하는 조합: “force-with-lease 허용 + 예외 최소화”
질문 주제는 “강제푸시 없이”지만, 팀 차원에서 장기적으로는 완전 금지보다 --force-with-lease만 제한적으로 허용하는 쪽이 오히려 안전한 경우가 많습니다.
--force는 원격의 누군가 작업을 덮어쓸 수 있음--force-with-lease는 “내가 마지막으로 본 원격 상태 그대로일 때만” 덮어씀
# 안전장치가 있는 강제푸시
git push --force-with-lease origin feature
다만 조직 정책상 이게 불가하다면, 이 글의 전략 1(새 PR) 또는 전략 2(merge로 최신화)가 표준 운영 절차가 됩니다.
PR을 깔끔하게 유지하는 팀 규칙(강제푸시 없이도 효과 있음)
강제푸시를 하지 않더라도 PR이 “정리돼 보이게” 만드는 규칙들이 있습니다.
1) PR을 작게 쪼개기
- rebase가 필요한 이유(커밋/변경이 너무 많음)를 줄여줍니다.
- 충돌 해결 비용도 감소합니다.
2) 커밋 메시지 규칙 + PR 템플릿
- 커밋이 지저분해도 PR 설명이 명확하면 리뷰가 쉬워집니다.
What/Why/How, 테스트 방법, 롤백 방법을 템플릿화하세요.
3) “리뷰 중에는 rebase 금지, 머지 직전에만 허용”
- 리뷰 코멘트가 달린 라인이 rebase로 이동하면 맥락이 깨집니다.
- 머지 직전에만 정리하면 충돌/혼란이 줄어듭니다.
상황별 추천 의사결정표
- force push 완전 금지 + 이미 rebase 해버림: 전략 1(새 브랜치/새 PR)
- force push 금지지만 PR 링크/코멘트를 유지해야 함: 전략 2(merge로 최신화)
- 커밋 일부만 골라서 깔끔한 PR이 필요: 전략 3(cherry-pick)
- main만 깔끔하면 됨 + 빠르게 끝내기: 전략 4(squash merge)
자주 하는 실수와 체크리스트
실수 1) rebase 후 로컬 브랜치만 믿고 PR이 ‘업데이트된 줄’ 착각
- PR은 원격 브랜치 기준입니다.
- 로컬에서 아무리 rebase해도 원격을 갱신하지 않으면 PR은 그대로입니다.
# PR이 실제로 어떤 커밋을 보고 있는지 확인
git fetch origin
git log --oneline --decorate --graph origin/feature -n 20
실수 2) 새 PR로 갈아탔는데 CI/캐시가 꼬여 빌드가 느려짐
- 브랜치명이 바뀌면 캐시 키가 달라져 캐시 미스가 날 수 있습니다.
- GitHub Actions 캐시 정책을 점검하세요: GitHub Actions 캐시가 안 먹을 때 키·경로·권한
실수 3) cherry-pick으로 가져오다 테스트/포맷 커밋을 누락
- 범위를 고를 때 “의존 커밋”이 빠지지 않았는지 확인해야 합니다.
# 어떤 커밋이 어떤 파일을 건드렸는지 확인
git show --name-only <commit>
결론
git rebase는 좋은 도구지만, PR이 이미 열려 있고 강제푸시가 제한된 환경에서는 “히스토리를 재작성한 결과를 같은 PR에 반영”하기가 구조적으로 어렵습니다. 이때는 억지로 한 PR을 살리려 하기보다, 다음 중 하나를 의도적으로 선택하는 게 PR 품질과 팀 생산성을 동시에 지키는 길입니다.
- 가장 안전: 새 브랜치로 푸시 → 새 PR로 교체
- 가장 보수적: 기존 PR 유지 →
main을 merge해서 최신화 - 가장 정제된 PR: 새 브랜치에서 cherry-pick으로 재구성
- 가장 빠른 종료: squash merge로
main만 깔끔하게
팀 정책이 허용한다면 장기적으로는 --force-with-lease를 제한적으로 허용하는 것도 고려해볼 만하지만, 그렇지 않더라도 위 전략들만으로 충분히 “강제푸시 없이 PR을 정리”할 수 있습니다.