혹시 실수로 중요한 비밀번호를 커밋해버렸거나, 지저분한 실험용 커밋들을 합치기 전에 정리하고 싶었던 적 없으신가요? Git은 기본적으로 모든 변경 기록을 차곡차곡 쌓아나가지만, 때로는 과거 기록을 수정해야 할 필요가 생기죠.
등장 배경
예전에는 Git 히스토리를 한번 만들면 되돌리기 어렵다고 생각했어요. 특히 여러 사람과 함께 작업하는 프로젝트에서는 히스토리 변경이 큰 혼란을 야기할 수 있었죠. 하지만 개인 브랜치에서 작업하거나, 팀원들과 합의된 상황에서는 히스토리를 깔끔하게 정리하는 것이 오히려 더 좋을 때가 많아요. 바로 이럴 때 git rebase -i
가 강력한 해결사로 등장합니다! 🦸♂️
Git 히스토리 수정이 필요한 경우:
- 🤫 실수로 민감 정보 커밋: 비밀번호, API 키 등 공개되면 안 되는 정보를 커밋했을 때 해당 커밋을 삭제해야 합니다.
- 🧹 지저분한 히스토리 정리: 기능 개발 중 너무 잘게 쪼개진 커밋이나 실험적인 커밋들을 배포 전에 정리하고 싶을 때 사용합니다.
- ✨ 커밋 메시지 수정: 오타가 있거나 내용이 부족한 커밋 메시지를 수정하고 싶을 때도 활용할 수 있습니다.
핵심 원리: Interactive Rebase 마법 ✨
git rebase -i
(interactive rebase)는 이름처럼 사용자와 상호작용하며 커밋 히스토리를 재정렬하거나 수정할 수 있는 강력한 명령어입니다. 특정 커밋을 삭제하는 과정을 단계별로 알아볼까요?
Rebase 시작: 삭제하고 싶은 커밋 바로 이전 커밋의 해시(hash) 값을 이용해 rebase를 시작합니다. 만약
c703d02
커밋을 삭제하고 싶다면, 그 이전 커밋의 해시를 사용하거나,HEAD~N
(N은 현재로부터 몇 번째 커밋까지 볼 것인지) 형식으로 범위를 지정할 수 있습니다. 사용하신 예시처럼git rebase -i <삭제할 커밋의 부모 커밋 해시>
또는git rebase -i <삭제할 커밋 범위의 시작점 직전 커밋 해시>
명령어를 입력합니다.# 예시: c703d02 커밋을 포함한 이후 커밋들을 수정 대상으로 삼기 # c703d02의 부모 커밋 해시가 1234abcd 라고 가정 git rebase -i 1234abcd # 또는 최근 5개의 커밋을 수정 대상으로 삼기 git rebase -i HEAD~5
편집기 등장: 명령어를 실행하면 아래와 같이 편집기가 열리면서 rebase 대상 커밋 목록이 나타납니다. 각 줄은
명령어 커밋해시 커밋메시지
형식으로 되어 있습니다.pick a1b2c3d 초기 설정 추가 pick e4f5g6h 중요한 기능 개발 # 이 커밋을 삭제하고 싶다고 가정! pick i7j8k9l 버그 수정 # Rebase <시작 커밋 해시>..<현재 커밋 해시> onto <시작 커밋 해시> # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # <--- 바로 이 명령어! # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to re-edit the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # ... (이하 생략) ...
커밋 삭제: 삭제하고 싶은 커밋 앞의
pick
명령어를drop
으로 변경하거나, 해당 줄 자체를 삭제합니다.pick a1b2c3d 초기 설정 추가 drop e4f5g6h 중요한 기능 개발 # 'pick'을 'drop'으로 변경! pick i7j8k9l 버그 수정
또는
pick a1b2c3d 초기 설정 추가 # e4f5g6h 중요한 기능 개발 <-- 해당 라인을 아예 지워버려도 됩니다! pick i7j8k9l 버그 수정
저장 및 종료: 편집기를 저장하고 닫습니다. (Vim 편집기라면
:wq
입력 후 Enter)Rebase 진행: Git이 지정된 작업(
drop
또는 줄 삭제)을 수행하며 커밋을 재구성합니다. 충돌(Conflict)이 발생하지 않으면 자동으로 완료됩니다. 충돌이 발생하면, Git이 알려주는 대로 충돌을 해결하고git add .
후git rebase --continue
를 실행해야 합니다. 만약 rebase를 취소하고 싶다면git rebase --abort
를 사용하세요.원격 저장소 강제 푸시 (Force Push): 로컬 저장소의 히스토리가 변경되었으므로, 원격 저장소(예: GitHub, GitLab)의 히스토리와 달라졌습니다. 변경된 히스토리를 원격 저장소에 반영하려면
git push --force
또는git push --force-with-lease
명령어를 사용해야 합니다. ⚠️ 이 작업은 매우 주의해야 합니다!# 변경된 로컬 히스토리를 원격 저장소(dev 브랜치)에 강제로 덮어쓰기 git push origin dev --force # 또는 조금 더 안전한 force-with-lease 사용 git push origin dev --force-with-lease
주의사항 및 팁 💡
⚠️ 이것만은 주의하세요!
- Force Push의 위험성:
git push --force
는 원격 저장소의 히스토리를 강제로 덮어씁니다. 만약 다른 팀원이 이미 이전 히스토리를 기반으로 작업을 하고 있었다면, 그들의 작업 내역과 충돌하거나 유실될 수 있습니다! 😱- 상세 설명: 공유된 브랜치(예:
main
,master
,dev
)에 대해서는 절대 함부로force push
를 사용하면 안 됩니다. - 해결 방법:
- 개인 브랜치에서만
rebase -i
와force push
를 사용하세요. - 꼭 공유 브랜치의 히스토리를 수정해야 한다면, 모든 팀원과 충분히 소통하고 동의를 얻은 후에 진행하세요.
--force-with-lease
옵션은 원격 브랜치가 내가 마지막으로 pull 받은 이후 변경되지 않았을 때만 push를 허용하므로--force
보다 약간 더 안전합니다.
- 개인 브랜치에서만
- 상세 설명: 공유된 브랜치(예:
- Rebase 중 충돌: Rebase 과정에서 커밋들이 재적용될 때 코드 충돌이 발생할 수 있습니다.
- 상세 설명: 삭제하려는 커밋 이후의 커밋들이 삭제된 커밋의 코드 변경 사항에 의존하고 있었다면 충돌이 발생합니다.
- 해결 방법: Git이 알려주는 충돌 파일을 열어 직접 수정하고,
git add <수정한 파일>
명령어로 스테이징한 뒤,git rebase --continue
명령어로 rebase를 계속 진행합니다. 해결이 어렵다면git rebase --abort
로 rebase를 취소할 수 있습니다.
💡 꿀팁
- 되돌리기: 만약 rebase를 잘못했다면?
git reflog
명령어로 로컬 저장소의 HEAD 변경 이력을 확인하고,git reset --hard <원하는 시점의 해시>
명령어로 이전 상태로 되돌릴 수 있습니다. (단, force push 이후라면 원격 저장소는 이미 변경된 상태일 수 있습니다.) - 대안:
git revert
: 이미 다른 사람들과 공유된 히스토리의 특정 변경 사항을 되돌리고 싶다면, 히스토리를 삭제하는rebase
대신git revert <취소할 커밋 해시>
를 사용하는 것이 안전합니다.revert
는 특정 커밋의 변경 내용을 거꾸로 적용하는 _새로운 커밋_을 생성하므로 히스토리가 보존됩니다. - 민감 정보 완전 삭제: 단순
rebase
로는 히스토리에서만 보이지 않을 뿐, Git 데이터베이스 어딘가에 흔적이 남을 수 있습니다. 민감 정보를 완전히 제거하려면git filter-branch
나bfg-repo-cleaner
같은 전문 도구를 사용하는 것이 좋습니다. (이 도구들은 사용법이 더 복잡합니다.)
마치며
지금까지 git rebase -i
를 사용하여 Git 커밋 히스토리에서 특정 기록을 삭제하는 방법을 알아보았습니다. 처음에는 조금 복잡하게 느껴질 수 있지만, 몇 번 연습해보면 Git 히스토리를 훨씬 깔끔하고 효율적으로 관리할 수 있게 될 거예요! 😎 특히 force push
의 위험성을 항상 기억하고 신중하게 사용하는 것이 중요합니다.
혹시 이 과정에서 궁금한 점이나 더 알고 싶은 부분이 있으신가요? 댓글로 자유롭게 질문해주세요! 🙋♀️
참고 자료 🔖
- Git 공식 문서 - Rewriting History: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History
- Atlassian Git Tutorial - Rewriting History: https://www.atlassian.com/git/tutorials/rewriting-history
#Git #Rebase #CommitHistory #버전관리 #개발팁 #깃허브 #Git커밋삭제 #InteractiveRebase
'100===Dev Ops > Git' 카테고리의 다른 글
Git 로컬 커밋 완전 삭제 - 원격 저장소 무결성 유지하기 🔄 (0) | 2025.05.22 |
---|---|
Git Rebase 가이드 - 커밋 히스토리 정리부터 안전하게 푸시하기까지 (1) | 2025.04.22 |
Git 제대로 이해하기: 시간여행자의 코드 관리 비법 🚀 (2) | 2024.11.17 |
GitLab CICD로 쉽고 강력한 자동화 파이프라인 구축하기 🚀 (0) | 2024.06.11 |
How do you sync your local repository with a remote one with git? (0) | 2024.06.09 |