Git에서 한 브랜치에서 다른 브랜치로 합치는 방법으로는 두 가지가 있다. 하나는 Merge 이고 다른 하나는 Rebase 다.
experiment(exp)와 master 두 개의 브랜치가 있다.
exp는 c4 커밋을 남겼고 master는 c3 커밋을 남겼다.
exp와 master 브랜치를 하나로 합치는 방법은 뭐가 있을까?
하나, merge
둘, rebase
MERGE
익숙한 merge부터 살펴보자.
merge는 두 브랜치의 마지막 커밋 두 개(C3, C4)와 공통 조상(C2)을 사용하는 3-way Merge로 새로운 커밋(C5)을 만들어 낸다.
그림으로 표현하면 아래와 같다.
REBASE
C4커밋을 Patch로 '가져오고' 이를 C3 커밋에 다시 적용시키는 방법이 있다. Git에서는 이런 방식을 Rebase 라고 한다.
rebase 명령으로 한 브랜치에서 변경된 사항을 다른 브랜치에 적용할 수 있다.
(1) 먼저 변경 사항을 가진 브랜치(experiment)로 체크아웃한다.
(2) 변경 사항을 적용하려는 브랜치(master)를 rebase한다.
위의 예제는 아래와 같은 명령으로 Rebase 한다.
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
실제로 일어나는 일을 설명하자면
- 일단 두 브랜치가 나뉘기 전인 공통 커밋(C2)으로 이동하고
- 그 커밋부터 지금 Checkout 한 브랜치가 가리키는 커밋까지(C4) diff를 차례로 만들어 어딘가에 임시로 저장해 놓는다.
- Rebase 할 브랜치(역주 - experiment)가 합칠 브랜치(역주 - master)가 가리키는 커밋(C3)을 가리키게 하고
- 아까 저장해 놓았던 변경사항을 차례대로 적용한다.
- 그리고 나서 master 브랜치를 Fast-forward 시킨다. (아래 이미지)
$ git checkout master
$ git merge experiment
Rebase와 Merge 중 뭐가 나은가요?
C4' 로 표시된 커밋에서의 내용은 Merge 예제에서 살펴본 C5 커밋에서의 내용과 같을 것이다. Merge 이든 Rebase 든 둘 다 합치는 관점에서는 서로 다를 게 없다. 하지만, Rebase가 좀 더 깨끗한 히스토리를 만든다. Rebase 한 브랜치의 Log를 살펴보면 히스토리가 선형이다. 일을 병렬로 동시에 진행해도 Rebase 하고 나면 모든 작업이 차례대로 수행된 것처럼 보인다.
Rebase는 보통 리모트 브랜치에 커밋을 깔끔하게 적용하고 싶을 때 사용한다. 아마 이렇게 Rebase 하는 리모트 브랜치는 직접 관리하는 것이 아니라 그냥 참여하는 브랜치일 것이다. 메인 프로젝트에 Patch를 보낼 준비가 되면 하는 것이 Rebase 니까 브랜치에서 하던 일을 완전히 마치고 origin/master 로 Rebase 한다. 이렇게 Rebase 하고 나면 프로젝트 관리자는 어떠한 통합작업도 필요 없다. 그냥 master 브랜치를 Fast-forward 시키면 된다.
Rebase를 하든지, Merge를 하든지 최종 결과물은 같고 커밋 히스토리만 다르다는 것이 중요하다. Rebase 의 경우는 브랜치의 변경사항을 순서대로 다른 브랜치에 적용하면서 합치고 Merge 의 경우는 두 브랜치의 최종결과만을 가지고 합친다.
Fast Forward?
Fast Forward는 단순히 브랜치 포인터만 이동하는 것을 말한다.
Merge를 할 경우 병합커밋Merge Commit이 생기게 된다.
하지만 Rebase를 하면 병합 커밋이 생기지 않는다. 병합 커밋 대신 브랜치 포인터를 이동시키는 Fast Forward를 사용하기 때문이다.
A---B---C (main)
\
D---E (feature)
- main 브랜치에서 feature 브랜치를 만든 후, feature에서 작업을 진행했음
- main에는 아무런 변경이 없고, feature만 앞서 나감
이때 main에서 다음을 실행하면:
git checkout main
git merge feature
- Git은 병합 커밋 없이 main 포인터를 E로 앞으로 당겨주는(fast-forward) 작업만 수행함
- 병합 커밋 없음
Fast Forward는 아래처럼 main과 feature가 서로 다른 변경을 가지고 있을 경우 불가능하다.
A---B---C (main)
\ \
D---E (feature)
이 경우 Git은 fast-forward를 할 수 없고,
병합 내용을 담은 merge commit을 자동으로 생성함
깃은 기본적으로 Fast Forward를 하려고 한다.
--no-ff 옵션을 사용하면 fast-forward가 가능해도 강제로 병합커밋을 만들 수 있다.
git merge --no-ff feature
출처 :
인간다운 Git,
https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-Rebase-%ED%95%98%EA%B8%B0
'【 개발 이야기 】' 카테고리의 다른 글
[IntelliJ] 초심자를 위한 디버깅 시작하기 (2) | 2025.06.04 |
---|---|
IV (0) | 2025.06.02 |
볼만한 개발 블로그.. (0) | 2025.05.30 |
WebClient의 .body(...)와 .bodyValue (1) | 2025.05.13 |
[spring] web client 공식 문서 번역 (1) | 2025.05.08 |