[git] rebase 이해하기

Git에서 한 브랜치에서 다른 브랜치로 합치는 방법으로는 두 가지가 있다. 하나는 Merge 이고 다른 하나는 Rebase 다.

타원은 커밋이고 사각형은 브랜치이름이다

experiment(exp)와 master 두 개의 브랜치가 있다.

exp는 c4 커밋을 남겼고 master는 c3 커밋을 남겼다.

 

exp와 master 브랜치를 하나로 합치는 방법은 뭐가 있을까?

하나, merge

둘, rebase

 

MERGE

익숙한 merge부터 살펴보자.

merge는 두 브랜치의 마지막 커밋 두 개(C3, C4)와 공통 조상(C2)을 사용하는 3-way Merge로 새로운 커밋(C5)을 만들어 낸다.

그림으로 표현하면 아래와 같다.

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

실제로 일어나는 일을 설명하자면

  1. 일단 두 브랜치가 나뉘기 전인 공통 커밋(C2)으로 이동하고
  2. 그 커밋부터 지금 Checkout 한 브랜치가 가리키는 커밋까지(C4) diff를 차례로 만들어 어딘가에 임시로 저장해 놓는다.
  3. Rebase 할 브랜치(역주 - experiment)가 합칠 브랜치(역주 - master)가 가리키는 커밋(C3)을 가리키게 하고
  4. 아까 저장해 놓았던 변경사항을 차례대로 적용한다.
  5. 그리고 나서 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