git rebase
merge하지 않고도 branch를 합칠 수 있어..!
Table Of Contents
Git branch 합치기
Git에서 한 브랜치를 다른 브랜치로 합치는 방법으로는 Merge
와 Rebase
가 있다.
보통 merge는 많이 사용하는 데에 비해서 rebase는 잘 사용되지 않아 익숙하지 경우가 많은 것 같아, 오늘은 rebase가 무엇인지, merge와는 어떻게 다른지 알아보자!
Rebase
rebase는 커밋 시퀀스를 새 기준 커밋으로 이동하거나 결합하는 프로세스이다.
- 브랜치의 기준을 다른 커밋으로 변경한다.
- 이 과정에서 브랜치는 기존 내용과 똑같은 것처럼 보이지만, 완전히 새로운 커밋으로 대체되게 된다.
- 결과적으로 마치 새로운 기준 커밋에서 브랜치를 만든 것처럼 보이게 한다.
Merge와의 차이점
나는 main 브랜치에서 feature 브랜치를 만들어 새로은 기능을 구현중인데, main 브랜치에서 업데이트가 발생했다!
(출처: https://www.atlassian.com/ko/git/tutorials/merging-vs-rebasing)
merge
와 rebase
모두 이런 상황을 해결해 동일한 결과물을 만들지만, 커밋 히스토리는 다르다.
Merge를 사용하는 경우
merge
는 main
브랜치를 feature
브랜치에 병합해준다.
git checkout feature git merge main
또는
git merge feature main
명령어를 통해 merge를 수행하면, feature
브랜치에 새로운 merge commit(병합 커밋)이 만들어진다.
- 새로운 merge commit(*)이 만들어진 모습
만약 main
브랜치가 자주 변경되는 경우, feature
브랜치에는 merge commit이 계속 생기기 때문에 커밋 기록을 알아보기 어렵다는 단점이 있다.
Rebase를 사용하는 경우
rebase
는 feature
브랜치의 기준을 main
브랜치의 가장 최신 커밋으로 바꿔줄 수 있다.
git checkout feature git rebase main
main
브랜치의 끝에서feature
브랜치가 시작한 것처럼 새로운 커밋들이 만들어진다.- 실제로 일어나는 일은 다음과 같다.
- 두 브랜치가 나뉘기 전인 공통 커밋으로 이동한다.
- 그 커밋부터 checkout한 브랜치(
feature
)가 가리키는 커밋까지 diff를 차례로 만들어 어딘가에 임시로 저장해놓는다. - rebase할 브랜치(
feature
)가 합칠 브랜치(main
)가 가리키는 커밋(main
브랜치의 최신 커밋)을 가리키게 한다. - 아까 저장해 놓았던 변경사항을 차례대로 적용한다.
rebase
하면 불필요한 merge commit들이 없어지기 때문에 커밋 기록이 더 깔끔하다는 장점이 있다.
하지만 잘못 사용하는 경우, 협업에 악영향을 줄 수 있다.
rebase
유의사항
rebase
는 공용 브랜치에서는 사용하지 않아야 한다
모두가 사용하는 main
브랜치를 feature
브랜치로 rebase한 경우를 살펴보자.
rebase 수행 이후, main
의 모든 커밋이 feature
이후로 옮겨지게 된다.
하지만 이 변화는 로컬 레포에서만 이루어지고, 다른 개발자들은 여전히 원래 main
에서 작업을 하게 된다.
이렇게 생긴 두 main
브랜치를 동기화하려면 merge
명령을 수행해야 하고, 이로 인해서 새로운 merge commit이 생겨 기록이 매우 복잡해지게 된다.
rebase
활용
#1 --interactive
옵션 으로 대화형 rebase하기
대화형 rebase는 모든 커밋을 새로운 기준 커밋 뒤로 이동하지 않고, 커밋을 개별적으로 제거, 분할, 변경할 수 있다.
- 따라서
main
으로 변경 내역을 적용하기 전에 복잡한 기록을 정리할 수 있다.
대화형 rebase가 실행되면 이렇게 여러 가지 명령어가 제공된다.
pick 2231360 some old commit pick ee2adc2 Adds new feature # Rebase 2cf755d..ee2adc2 onto 2cf755d (9 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit
pick
,p
- 기본 작업이며, 해당 커밋의 변경 사항이 그대로 적용된다.
reword
,r
- 커밋 내용은 바꾸지 않고, 메시지만 수정한다.
edit
,e
- 커밋을 수정하기 위해 리베이스를 일시 중지한다.
squash
,s
- 해당 커밋을 이전 커밋과 합치면서, 두 커밋의 메시지를 모두 유지하고 편집할 수 있다.
- 여러 개의 커밋을 하나로 합쳐 기록을 깔끔하게 할 수 있다.
fixup
,f
- 해당 커밋을 이전 커밋과 합치면서, 해당 커밋의 메시지는 버리고 이전 커밋의 메시지만 유지한다.
exec
,x
- 특정 커밋 시점에 쉘 명령어를 실행한다.
- 테스트 수행 등이 가능하다.
drop
,d
- 선택한 커밋을 제거한다.
이렇게 --interactive
또는 -i
옵션을 주어 대화형 rebase를 실행할 수 있다.
git rebase --interactive <base>
또는
git rebase -i <base>
#2 --onto
옵션 사용하기
이런 상황을 생각해 볼 수 있다.
master
에서 server
라는 브랜치를 만들어 작업을 하다가, server
에서 다시 client
로 브랜치를 만들어 작업을 한다. client
가 생긴 이후에도 server
에서 기능이 계속 추가된다.
(출처: https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
이 때, client
브랜치만 master
으로 합치려 한다.
server
와 관련 없는 client
커밋은 C8
, C9
이다. 이 두 커밋을 master
에 적용하기 위해서는 --onto
옵션을 사용할 수 있다.
git rebase --onto master server client
이 명령어를 사용하면 client
브랜치에서만 변경된 사항들을 따로 저장했다가, master
브랜치에 차례로 적용하게 된다.
- 이 경우, <
master
브랜치>부터 <server
브랜치와client
브랜치의 공통 조상>까지의 커밋은client
에서 제거된다.
결과적으로 커밋 히스토리는 이렇게 정리된다.
이제 server
의 커밋 내역을 master
에 rebase하려면
git checkout master git merge client
를 통해 우선 master
브랜치의 포인터를 client
가 master
에 rebase
된 이후로 이동시켜줘야 한다.
git rebase master server
그리고 rebase를 실행하면 최종적으로 아래와 같은 히스토리를 얻을 수 있다.
아래 명령어로 master
의 포인터를 이동시켜 주는 것도 잊지 말자!
git checkout master git merge server
참고
- https://git-scm.com/docs/git-rebase
- 3.6 Git Branching - Rebasing: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
- Using Git rebase on the command line: https://docs.github.com/en/get-started/using-git/using-git-rebase-on-the-command-line
- git rebase: https://www.atlassian.com/ko/git/tutorials/rewriting-history/git-rebase
- Merging vs. rebasing: https://www.atlassian.com/ko/git/tutorials/merging-vs-rebasing