이전에 쓴 글은 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 -i → git push |
| push 후 + 혼자 쓰는 브랜치 | rebase + force push | git rebase -i → git push --force-with-lease |
| push 후 + 공유 브랜치 | revert | git revert → git push |
| 사고 복구 | reflog | git reflog → git cherry-pick |
🎯 결론
Push 한 뒤에도 Commit 수정은 가능하다
- 혼자 쓰는 브랜치면
--force-with-lease로 force push - 공유 브랜치면
revert로 새 Commit 생성 --force는 쓰지 않는다- 실수해도
reflog으로 90일 내 복구 가능
--force 대신 --force-with-lease 를 습관으로 만들자
하지만, 그 전에 Commit 을 꼼꼼하게 확인하는 게 더 중요하다^_^
'TIL > TIL' 카테고리의 다른 글
| [TIL][GitHub] HEAD 가 아닌 과거 Commit 수정하기 (git rebase + amend) (0) | 2026.02.09 |
|---|