TIL/TIL

[TIL][GitHub] 이미 Push 한 Commit 수정하기 feat. force push

아람2 2026. 2. 15. 12:55
반응형

이전에 쓴 글은 Push 를 하기 전에 Commit 을 수정하는 글이었다
https://helloahram.tistory.com/271 

 

[TIL][GitHub] HEAD 가 아닌 과거 Commit 수정하기 (git rebase + amend)

Commit 을 여러 개 쌓았는데 중간에 있는 Commit 에 빠뜨린 게 있었다6c381c2 Feat: 기능 추가8b8dba7 Refactor: 리팩토링a775b72 Feat: 다른 기능9b31d5a Chore: echo 메시지 정리 👈 여기에 추가하고 싶음c01b112 Feat:

helloahram.tistory.com

 

그런데 실무에서는 Push 한 뒤에 수정해야 할 일이 생긴다

그럴 땐 어떻게 해야 하는지 정리해봤다


🤔 왜 Push 후에는 다른가?

Push 하면 Remote 에 Commit 이 올라간다

내가 rebase 나 amend 로 Commit 을 고치면 Commit Hash 가 바뀐다

[로컬]  a1b2c3d → 수정 후 → x9y8z7w  (Hash 바뀜)
[리모트] a1b2c3d                        (아직 옛날 것)

이 상태에서 git push 하면 거절당한다

$ git push
 ! [rejected] main -> main (non-fast-forward)
hint: Updates were rejected because the tip of your current branch is behind

리모트의 a1b2c3d 와 로컬의 x9y8z7w 가 다르기 때문이다


🔑 핵심: --force vs --force-with-lease

❌ git push --force

# 리모트를 로컬로 덮어쓴다 (무조건)
git push --force

위험한 이유: 다른 사람이 그 사이에 Push 한 Commit 도 날아간다

[나]     a → b → c (amend) → c'
[동료]   a → b → c → d       👈 동료가 d 를 push 함
[리모트] a → b → c → d

git push --force 하면:
[리모트] a → b → c'           👈 동료의 d 가 사라짐!

✅ git push --force-with-lease

# 리모트가 내가 마지막으로 본 상태와 같을 때만 덮어쓴다
git push --force-with-lease

안전한 이유: 누군가 그 사이에 push 했으면 거절된다

$ git push --force-with-lease
 ! [rejected] main -> main (stale info)
# → "리모트가 바뀌었다. 먼저 pull 해라"

항상 --force-with-lease 를 쓴다


📋 상황별 가이드

상황 1: 혼자 쓰는 브랜치 (feature branch)

가장 흔한 케이스,
PR 올리기 전에 Commit 정리할 때

# 1. rebase 로 Commit 수정 (04편 참고)
GIT_SEQUENCE_EDITOR="sed -i '' 's/^pick abc1234/edit abc1234/'" git rebase -i abc1234~1

# 2. 수정 후 amend
git add .
git commit --amend --no-edit

# 3. rebase 완료
git rebase --continue

# 4. force push (혼자 쓰는 브랜치이므로 안전)
git push --force-with-lease

혼자 쓰는 브랜치여도 --force-with-lease 를 습관으로 쓴다

상황 2: PR 리뷰 반영 후 Commit 정리

리뷰어가 "Commit 합쳐주세요" 라고 할 때

# 1. 최근 3개 Commit 을 하나로 합치기
GIT_SEQUENCE_EDITOR="sed -i '' '2,3s/^pick/squash/'" git rebase -i HEAD~3

# 2. Commit 메시지 정리 (에디터 열림)
# → 메시지 수정 후 저장

# 3. force push
git push --force-with-lease

PR 의 Commit 히스토리가 깔끔해진다

상황 3: 공유 브랜치 (main, develop)

⚠️ 공유 브랜치에서는 force push 를 하지 않는다

대신 revert 를 쓴다

# 잘못된 Commit 을 되돌리는 새 Commit 생성
git revert abc1234

# 일반 push (force 아님)
git push
abc1234 Feat: 잘못된 기능
def5678 Revert "Feat: 잘못된 기능"  👈 새 Commit 으로 되돌림

히스토리에 "되돌렸다" 는 기록이 남지만, 다른 사람 작업을 망치지 않는다


🛡️ force push 전 체크리스트

□ 1. 이 브랜치를 나만 쓰는가?
     → Yes: --force-with-lease 사용
     → No:  revert 사용 (force push 금지)

□ 2. fetch 먼저 했는가?
     → git fetch origin
     → --force-with-lease 가 최신 리모트 상태를 비교하려면 필요

□ 3. 로컬 변경사항을 백업했는가?
     → 불안하면 브랜치 복사: git branch backup-branch

fetch 를 먼저 해야 하는 이유

--force-with-lease로컬이 알고 있는 리모트 상태와 비교한다

fetch 안 하면 옛날 정보로 비교해서 보호가 안 될 수 있다

# ✅ 안전한 순서
git fetch origin
git push --force-with-lease

🔧 편하게 쓰기: alias 설정

매번 --force-with-lease 치기 귀찮으니 alias 등록

# ~/.gitconfig 에 추가
git config --global alias.pushf "push --force-with-lease"
# 사용
git pushf origin feature/my-branch

--force 를 직접 칠 일을 줄여준다


💥 사고 복구: force push 로 날린 Commit 살리기

실수로 --force 해서 Commit 이 날아갔을 때

reflog 으로 복구

# 1. reflog 에서 잃어버린 Commit 찾기
git reflog
# abc1234 HEAD@{2}: commit: Feat: 중요한 기능  👈 이거

# 2. 해당 Commit 으로 브랜치 복구
git branch recover-branch abc1234

# 3. 확인 후 merge 또는 cherry-pick
git cherry-pick abc1234

reflog: Git 이 HEAD 이동 기록을 저장하는 로그, 기본 90일간 유지된다

동료 Commit 이 날아간 경우

# 동료 로컬에 아직 있으므로
# 동료가 push 하면 복구됨
git push origin feature/branch

동료 로컬에도 없으면 reflog 이 유일한 희망이다


📊 정리: 언제 뭘 쓰는가

상황 방법 명령어
push 전 Commit 수정 rebase + amend git rebase -igit push
push 후 + 혼자 쓰는 브랜치 rebase + force push git rebase -igit push --force-with-lease
push 후 + 공유 브랜치 revert git revertgit push
사고 복구 reflog git refloggit cherry-pick

🎯 결론

Push 한 뒤에도 Commit 수정은 가능하다

  1. 혼자 쓰는 브랜치면 --force-with-lease 로 force push
  2. 공유 브랜치면 revert 로 새 Commit 생성
  3. --force 는 쓰지 않는다
  4. 실수해도 reflog 으로 90일 내 복구 가능

--force 대신 --force-with-lease 를 습관으로 만들자
하지만, 그 전에 Commit 을 꼼꼼하게 확인하는 게 더 중요하다^_^

반응형