Published on

Git rebase 후 강제푸시? PR 안전복구 7단계

Authors

서로 다른 히스토리를 가진 브랜치에 git rebase를 적용한 뒤, 원격 브랜치에 푸시하려고 하면 대부분 한 번은 이 질문을 만나게 됩니다.

  • “강제푸시(--force) 해도 되나?”
  • “PR(풀 리퀘스트) 리뷰가 다 날아가는 거 아닌가?”
  • “동료가 이미 커밋을 더 올렸으면 어떡하지?”

결론부터 말하면, 강제푸시 자체는 위험한 행위가 아니라 ‘잘못된 강제푸시’가 위험합니다. 특히 PR 브랜치에서 rebase 후 강제푸시가 필요한 상황은 흔하고, 안전장치와 복구 루트를 알고 있으면 PR을 안전하게 살릴 수 있습니다.

이 글은 “rebase 후 강제푸시가 필요한데 PR을 안전하게 복구/유지하는 방법”을 7단계 체크리스트로 제공합니다.


왜 rebase 후 강제푸시가 필요한가

rebase는 커밋을 “다시 쌓는” 작업이라 커밋 SHA가 바뀝니다. 따라서 원격에 이미 존재하는 커밋들과 로컬의 커밋이 서로 다른 히스토리가 되어, 일반 푸시가 거절됩니다.

  • 원격: A - B - C
  • 로컬(rebase 후): A - B - C' - D' (C와 D가 새 SHA로 재작성)

이때 원격 브랜치를 로컬 히스토리로 “덮어써야” 하므로 강제푸시가 필요합니다.

다만, 무작정 --force를 쓰면 원격에 추가로 올라간 다른 사람의 커밋을 통째로 날릴 수 있습니다. 그래서 실무에서는 --force-with-lease를 기본으로 권장합니다.


PR 안전복구 7단계

아래 7단계는 “이미 rebase를 해버렸거나, 강제푸시를 해야 하는데 PR을 안전하게 유지/복구하고 싶다”는 상황을 기준으로 작성했습니다.

1단계) 현재 상태를 ‘스냅샷 브랜치’로 백업하기

가장 먼저 할 일은 지금 상태를 잃지 않도록 로컬에 백업 브랜치를 만드는 것입니다. 이 한 줄이 나중에 되돌릴 마지막 보험이 됩니다.

# 현재 작업 브랜치가 feature/login 이라고 가정

git status

git branch backup/feature-login-before-fix

원격에도 백업을 남기고 싶다면:

git push origin backup/feature-login-before-fix

이렇게 해두면 이후 어떤 실수를 해도 “백업 브랜치로 체크아웃 → 다시 푸시”가 가능합니다.


2단계) 원격 브랜치 최신 상태를 정확히 가져오기(fetch)

강제푸시가 위험해지는 핵심 원인은 “원격이 최신이 아닌데 덮어쓰는 것”입니다. 반드시 fetch로 원격 상태를 최신으로 맞춥니다.

git fetch origin --prune

git log --oneline --decorate --graph --max-count=20

여기서 확인해야 할 것은:

  • origin/feature/login내가 모르는 커밋이 추가로 생겼는지
  • 내 로컬 브랜치가 원격과 얼마나 diverge 되었는지

3단계) “강제푸시가 안전한가?”를 먼저 판단하기

다음 두 케이스로 나뉩니다.

케이스 A: 원격에 다른 사람이 올린 커밋이 없다

  • 내 rebase로 SHA만 바뀐 상황
  • 이 경우 --force-with-lease로 안전하게 갱신 가능

케이스 B: 원격에 다른 사람 커밋이 추가됐다

  • 이 상태에서 강제푸시하면 그 커밋을 날릴 수 있음
  • 반드시 동료 커밋을 포함하도록 재정렬/병합 후 푸시해야 함

원격에 추가 커밋이 있는지 빠르게 보는 방법:

# 내 브랜치와 원격 브랜치 차이를 요약

git log --oneline --left-right --cherry-pick origin/feature/login...feature/login
  • < 는 origin에만 있는 커밋
  • > 는 로컬에만 있는 커밋

<가 보이면, 원격에 추가 커밋이 있다는 뜻입니다.


4단계) reflog로 “rebase 이전 커밋”을 찾기 (이미 꼬였을 때 핵심)

이미 rebase를 했고 뭔가 이상해졌다면, Git의 타임머신인 reflog가 정답입니다. rebase 전 HEAD를 찾아 복구할 수 있습니다.

git reflog --date=iso

출력 예시(개념):

  • HEAD@{0}: rebase 끝난 현재
  • HEAD@{3}: rebase 시작 전 커밋

복구 포인트를 찾았다면, 그 커밋으로 “복구 브랜치”를 만들어 둡니다.

# 예: rebase 이전이 HEAD@{3} 라고 가정

git branch restore/feature-login HEAD@{3}

이 브랜치를 기준으로 다시 전략을 세울 수 있습니다.


5단계) PR을 살리는 가장 안전한 강제푸시: --force-with-lease

--force는 “무조건 덮어쓰기”지만, --force-with-lease는 “내가 마지막으로 본 원격 상태가 그대로일 때만 덮어쓰기”입니다.

즉, 누군가 원격에 커밋을 추가했다면 푸시가 실패하며, 실수로 덮어쓰는 사고를 막아줍니다.

# rebase 완료 후, 원격 브랜치를 내 로컬로 갱신

git push --force-with-lease origin feature/login

실무 규칙으로는:

  • 개인 브랜치/PR 브랜치: --force-with-lease 허용
  • 공유 브랜치(main/develop 등): 강제푸시 금지(정책으로 막는 게 좋음)

참고로 CI에서 OIDC나 권한이 엮여 강제푸시 이후 파이프라인이 꼬이는 경우도 있는데, 이때는 Git 문제가 아니라 인증/권한 문제일 수 있습니다. 관련 이슈는 GitHub Actions OIDC 401 권한 오류 해결 가이드도 함께 확인해두면 좋습니다.


6단계) PR이 이미 깨졌다면: “원격의 이전 상태”를 되살린 뒤 재정렬

강제푸시를 잘못해서 PR 브랜치가 엉뚱한 상태가 됐다면, 복구는 보통 아래 루트 중 하나로 갑니다.

루트 1: 원격의 이전 커밋을 찾아 hard reset 후 재푸시

만약 원격 브랜치가 “잘못 덮어써진 상태”라면, 로컬에서 올바른 커밋으로 되돌린 뒤 다시 --force-with-lease로 푸시합니다.

# 올바른 커밋 SHA(예: abc1234)로 되돌리기

git checkout feature/login

git reset --hard abc1234

git push --force-with-lease origin feature/login

올바른 커밋 SHA는 다음에서 찾는 경우가 많습니다.

  • git reflog
  • GitHub PR의 “force-push 이벤트” 이전 커밋
  • 로컬 백업 브랜치(backup/...)의 커밋

루트 2: PR 브랜치를 새로 만들고 PR을 교체(최후의 수단)

리뷰 코멘트/히스토리를 최대한 살리고 싶다면 기존 PR을 유지하는 게 좋지만, 상황에 따라 새 PR이 더 빠를 때도 있습니다.

# 현재 올바른 상태에서 새 브랜치 생성

git checkout -b feature/login-v2

git push -u origin feature/login-v2

이후 GitHub에서 새 PR을 만들고, 기존 PR에는 “대체 PR 링크”를 남겨 정리합니다.


7단계) 재발 방지 체크리스트(팀 규칙 + 로컬 설정)

사고의 80%는 “절차가 아닌 습관”에서 납니다. 아래를 팀 규칙으로 정해두면 rebase/강제푸시 사고가 크게 줄어듭니다.

(1) 강제푸시는 무조건 --force-with-lease

# 습관화: force 대신 force-with-lease

git push --force-with-lease

(2) rebase는 “내 브랜치에서만”

  • 공유 브랜치에 rebase 금지
  • PR 브랜치도 가능하면 “혼자 쓰는 브랜치”로 유지

(3) 푸시 전 항상 fetch

git fetch origin --prune

(4) 브랜치 보호 규칙(서버에서 막기)

  • main/develop: force push 금지
  • PR 필수, status check 필수

(5) PR 커밋 정리 전략을 팀 합의로 고정

  • Squash merge를 쓸지
  • Rebase merge를 쓸지
  • Merge commit을 허용할지

전략이 섞이면 “누군가는 rebase, 누군가는 merge”가 되어 충돌/히스토리 꼬임이 잦아집니다.


실전 예시: rebase 후 PR 브랜치 안전하게 갱신하기

가장 흔한 시나리오를 커맨드 흐름으로 정리하면 아래와 같습니다.

# 0) 작업 브랜치

git checkout feature/login

# 1) 백업

git branch backup/feature-login

# 2) 최신 원격 반영

git fetch origin --prune

# 3) main 최신을 기준으로 rebase

git rebase origin/main

# 4) 테스트/빌드 확인(중요)
# 예: npm test / mvn test 등

# 5) 안전 강제푸시

git push --force-with-lease origin feature/login

포인트는 단 하나입니다.

  • 백업 브랜치 생성
  • fetch로 원격 최신화
  • --force-with-lease로만 강제푸시

이 3가지만 지켜도 PR 사고 확률이 급감합니다.


자주 묻는 질문(짧게 정리)

Q1. --force-with-lease면 100% 안전한가?

원격이 내가 마지막으로 본 상태에서 바뀌지 않았을 때만 덮어쓰므로 실수로 남의 커밋을 지우는 사고는 대부분 방지합니다. 다만, 팀원이 같은 시점에 작업하면 여전히 충돌/재시도가 필요할 수 있습니다.

Q2. PR 코멘트/리뷰는 강제푸시하면 사라지나?

대부분의 플랫폼(GitHub)은 PR 코멘트 자체는 유지됩니다. 다만 특정 커밋에 달린 코멘트가 “outdated”로 표시되거나, 라인 위치가 바뀌어 맥락이 흐려질 수 있습니다. 그래서 PR 브랜치에서 rebase는 “필요할 때만” 하는 게 좋습니다.

Q3. 이미 git push --force로 날려버렸는데 끝인가?

끝이 아닙니다. reflog, 백업 브랜치, GitHub의 이벤트/커밋 기록으로 대부분 복구 가능합니다. 이 글의 4~6단계를 그대로 따라가면 됩니다.


마무리

rebase 후 강제푸시는 “하면 안 되는 금기”가 아니라, 정해진 안전장치를 갖춘 표준 작업에 가깝습니다. 핵심은 두 가지입니다.

  1. 되돌릴 수 있는 백업(브랜치/reflog)을 먼저 확보하고
  2. --force-with-lease로만 원격을 갱신하는 것

이 7단계를 팀의 체크리스트로 고정해두면, PR을 살리면서도 히스토리를 깔끔하게 유지할 수 있습니다.