여태까지는 한 브랜치에서 다른 브랜치를 합치려면 merge를 사용했지만, 다른 방법으로 rebase를 사용하는 방법이 있다. 이번 포스팅에서는 Rebase가 무엇인지, 어떻게 사용하는지, 좋은 점은 무엇인지, 어떤 상황에서 사용하고 사용하지 말아야 할지 적어보고자 한다.
기존의 merge는 두 브랜치의 마지막 커밋 두 개(C3, C4)와 공통 조상(C2)을 사용하는 3-way Merge로 새로운 커밋을 만들어 낸다. 비슷한 결과를 만드는 다른 방식으로, C3 에서 변경된 사항을 Patch로 만들고 이를 다시 C4 에 적용시키는 방법이 있다. Git에서는 이런 방식을 Rebase 라고 한다. rebase 명령으로 한 브랜치에서 변경된 사항을 다른 브랜치에 적용할 수 있다.
git checkout feature/main
git add .
git commit -m "~~~"
git rebase -i master
feature/main 브랜치로 이동해 master를 base삼아 Rebase를 하면, 내부에서는 master가 base가 되고, C3과 C4의 차이를 임시로 저장하게 된다. 이때 이 임시로 저장하는 공간을 Patch
라고 한다. 그리고 C3에 Patch를 순서대로 적용하게 되면 커밋들이 여러갈래로 있었던 Merge와 다르게 커밋 히스토리가 한 줄로 깔끔하게 정렬된 것을 볼 수 있다.
Squash는 여러번 커밋한 이력을 하나의 커밋 이력으로 만드는데 사용한다. git rebase -i 명령어를 통해 rebase를 실행하게 되면, Git이 Rebase를 통해 커밋 이전의 상태로 되돌아 가려고 하는데, 현재와 과거 사이에 남아 있는 커밋을 어떻게 처리할지에 대해 물어보는 터미널 화면이 뜨게 된다.
pick b91e257 first commit
pick 0118d46 second commit
pick 1f199b7 third commit
# Rebase db078da..1f199b7 onto db078da (3 commands)
#
# 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 messag
여기서 i 버튼을 눌러 insert 모드에 들어가서, 아래와 같이 수정해 준다.
pick b91e257 first commit
s 0118d46 second commit
s 1f199b7 third commit
# Rebase db078da..1f199b7 onto db078da (3 commands)
#
# 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 messag
그리고 키보드의 esc 버튼을 누른뒤, :wq
를 입력해 빠져나가면 다음과 같은 화면이 뜨게 된다.
# This is a combination of 3 commits.
# This is the 1st commit message:
first commit
# This is the commit message #2:
second commit
# This is the commit message #3:
third commit
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Mon Apr 20 14:42:26 2020 +0900
#
# interactive rebase in progress; onto db078da
# Last commands done (3 commands done):
# squash 0118d46 second commit
이 화면은 Git이 Rebase를 통해 Squash를 할 예정인데, 이전에 작성한 커밋 메시지는 어떻게 할지 물어보는 화면이다. 역시 키보드의 i 버튼을 누른 다음, 아래와 같이 수정한다.
# This is a combination of 3 commits.
# This is the 1st commit message:
commit : 1 , 2, 3
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
메시지 작성이 완료되었다면, 키보드의 ESC 버튼을 누르고 :wq를 입력하여 저장해 준다. 이후에 확인하면, Rebase 이전과는 다르게 커밋이 하나만 나오는 것을 확인할 수 있다. 이제 해당 커밋들을 원격 저장소에 push해 주면 되는데, 이미 이전에 커밋한 내용을 원격 저장소에 Push한적이 있다면, --force 명령어를 통해 강제로 push해주어 교체해주어야 한다.
git push origin feature/main --force
항상 push 할때마다 force로 강제로 push하는 것이 어딘지 모르게 찝찝했는데, 원래 원격 저장소에 push를 했으면 force를 써야 한다는 걸 알고는 마음이 편해졌다.
덕분에 git rebase에 대해 잘 알고 갑니다~ㅂ