Study/기타
[Git] 터미널을 이용한 Git squash 작업 (rebase)
hyjang
2025. 4. 10. 10:21
728x90
들어가며
회사 프로젝트 내 dev 브랜치와 stage 브랜치의 싱크로율이 달라, stage 브랜치 기준으로 작업건을 체리픽하여 배포하는 작업이 필요했다.
하여 아래처럼 한 브랜치에서 여러번 커밋 + 머지를 한 경우, 하나의 커밋으로 스쿼시하여 체리픽하면 운영 배포 관리에 유용할 수 있어 Git squash에 대해 알아봤다.
💡 중요한 커밋들이 있는 브랜치라면 rebase전에 백업 브랜치를 생성하는 것을 추천
🍀 git 명령어
- develop 브랜치에 머지하지 않은 브랜치 스쿼시(해당 브랜치 커밋만 스쿼시해줌)
git rebase -i develop
- 이미 develop 브랜치에 머지한 브랜치 스쿼시
git rebase -i Head~합칠 커밋 갯수
- 3개의 커밋을 합치고 싶다면 git rebase -i Head~3 으로 진행한다.
- Head는 현재 checkout 되어있는 브랜치의 가장 최근 커밋을 가리킨다.
git rebase -i 커밋 해시
- 브랜치를 생성한 기준으로 커밋 해시를 작성합니다.
p 또는 pick | 해당 커밋 그대로 사용 (기본값) |
s 또는 squash | 현재 커밋을 이전 커밋과 합치고 커밋 메시지도 합침 |
d 또는 drop | 해당 커밋 제거 |
r 또는 reword | 커밋 메시지를 수정 |
e 또는 edit | 해당 커밋에서 멈추고 수정 기회 제공 |
f 또는 fixup | 현재 커밋을 이전 커밋과 합치지만 메시지는 버림 |
💡 브랜치에 남기고 싶지 않은 커밋은 drop 으로 제거할 수 있다.
결과물은 pick 으로 작성한 커밋만 남은 브랜치가 만들어진다.
🍀 vim 명령어
- esc와 i 로 vim 명령어 입력 상태를 바꿀 수 있다.
i | 입력 모드 시작(insert mode) |
esc | 입력 끝내기 (vim 명령어 입력 모드 시작) |
:wq 또는 zz | 저장 + 종료 = 리베이스 계속 진행 |
:q | 변경 없이 나가기 (변경이 있으면 안 나가짐) |
:q! | 강제 종료 (변경 무시하고 나가기) |
dd | 한 줄 잘라내기 (cut) |
yy | 한 줄 복사 |
p | 아래쪽에 붙여넣기 |
P | 위쪽에 붙여넣기 |
u | 행동 취소(undo) |
Ctrl + r | 다시 실행(undo를 취소) |
💡 dd 를 사용하여 squash 하고 싶은 커밋을 잘라내고, 합치고 싶은 커밋 아래에 붙여넣을 수 있다.
🍀 커밋 메시지 정리
- :wq + 엔터로 넘어왔다면, 다시 i 를 눌러 입력 모드(insert mode)로 전환한다.
💡 커밋 메시지 앞에 ‘#’ 을 기재해주면 메시지를 주석처리 할 수 있다.
💡 커밋 메시지를 새로 적고 싶다면 맨 윗줄에 작성한다. (주석들은 지워도 된다.)
🍀 강제 푸시
💡 스쿼시를 완료하면 기존 커밋은 없어지고, 스쿼시한 커밋만 남지만
git reflog를 이용해 HEAD 기록에 있는 기존 브랜치로 되돌릴 수 있다. (맨 처음에 백업 추천)
🍀 그 외
- 스쿼시는 언제 쓰는가?
- PR 또는 푸시 전에 히스토리를 깔끔하게 정리하고 싶을 때
- 기능 하나의 관련된 작업들을 하나의 커밋으로 만들고 싶을 때
- 커밋이 너무 잘게 쪼게졌을 때
(내 경우에는 이미 merge를 진행한 커밋들을 하나로 만들어 배포 브랜치에 체리픽 하기 위해 스쿼시를 진행했다.)
- 스쿼시 후에 어디에도 속하지 않은 브랜치가 단독으로 생성됐는데, 기존 브랜치와 같은 브랜치인 것인가?
- 히스토리가 바뀐 다른 브랜치다.
- 스쿼시 후엔 커밋 해시도 달라지고, Git 입장에서는 새로운 브랜치로 인식되기 때문에 이전 커밋들은 해당 브랜치에 존재하지 않는다.
- 브랜치 이름이 같을 수 있나?
- 이름은 같게 유지될 수 있다.(위치만 바뀜)
- 기존 브랜치로 돌아갈 수 있나?
- git reflog를 이용해 Head에 기록되어 있는 기존 브랜치로 돌아갈 수 있지만, 맨 처음에 백업하는 것을 추천한다.
( git reflog 해보려다 실패함..)
- 요약표
상황 | 기존 브랜치 상태 |
브랜치 위에서 리베이스 | 기존 커밋 히스토리는 없어짐 (reflog에만 존재) |
새 브랜치에서 리베이스 (백업) | 기존 브랜치 그대로 유지됨 |
기존 브랜치에 강제 덮어쓰기 (reset) | 기존 히스토리 완전 날아감 |