개발/Git

[Git] 브랜치 병합 방법 Merge, Squash, Rebase (Fast-Forward, 3-way-merge)

훈배 2024. 2. 27. 19:33

여러명이 같이 개발을 진행할 때 서로 다른 브랜치들을 자주 병합을 하게 됩니다.

이 때 어떤 브랜칭 전략이 있으며 어떤 방식으로 병합이 이루어지는지 알아보겠습니다.

Merge

일반적으로 많이 사용되는 병합 방법이며, 커밋 이력을 모두 남길 때 사용합니다.

$ git checkout main
$ git merge my-branch

이 방식은 상황에 따라 다시 Fast-Forward 방식과 Recursive 방식으로 나뉩니다.

 

Merge (Fast-Forward)

Fast-Forward Merge

새로운 브랜치 my-branch  main 브랜치로부터 분기된 이후 main 브랜치에 새로운 커밋이 올라오지 않았다면, my-branch  main 와 비교하여 최신의 브랜치라고 할 수 있습니다.

 

즉, my-branch가 base인 main을 포함하고 있는 관계일 때 이런 경우 my-branch 의 변경 이력을 그대로 main 으로 가져올 수 있는데, 이를 Fast-Forward Merge 라고 합니다.

 

Merge (Recursive)

Recursive Merge

my-branch  main 브랜치에서 분기되고, main 브랜치에 새로운 커밋이 생겼다면, my-branch 를 최신이라고 간주할 수 없습니다. 따라서 my-branch  main 을 공통 부모로 한 새로운 Merge Commit 을 생성하게됩니다. 이런 방법을 Recursive Merge라고 합니다.

 

이 때 merge commit을 생성할 때 git에서는 3-way-merge 방식을 사용합니다.

 

3-way-merge

2-way-merge vs 3-way-merge

병합을 할 때 3-way-merge는 base와 현재 브랜치 그리고 병합할 브랜치 3개를 비교하여 공통된 데이터base에서 바뀐 데이터를 자동으로 결정해주기 때문에 base를 제외하고 비교하여 공통된 데이터만 결정해주는 2-way-merge보다  항상 conflict가 더 적게 나는 것을 알 수 있습니다.

 

위의 예시에서 Me = H, Base = B, Other = E 라고 할 수 있습니다.

 

그리고 Fast-Forward Merge가 가능한 상태에서 git merge 명령에 --no-ff 옵션을 주면 강제로 Merge Commit을 생성하게 할 수 있습니다.

Squash & Merge

Squash & Merge

Squash는 여러개의 커밋을 하나의 커밋으로 합치는 것을 의미합니다. Squash Merge는 병합할 브랜치의 모든 커밋을 하나의 커밋으로 Squash한 새로운 커밋을 Base 브랜치에 추가하는 방식으로 병합하는 것을 의미합니다.

 

Squash를 하게 되면 모든 커밋 이력이 하나의 커밋으로 합쳐지며 사라진다는 점을 주의해야합니다.

$ git checkout main
$ git merge --squash my-branch
$ git commit -m "squash & merge"

 

Rebase & Merge

Rebase를 알아보기 전에 Base가 무엇인지 알아봅시다. my-branch  main 브랜치의 A 커밋에서 분기되었다고 하자. 이때, my-branch 의 Base는 A 커밋입니다.

 

그렇다면, Rebase는 무엇일까? 말 그대로 Base를 다시 설정한다는 의미입니다. 그럼 Base를 어디로 다시 설정할까? my-branch 가 분기된 main 브랜치의 최신 커밋입니다.

 

base를 변경 한 이후 base의 변경사항을 적용하여 새로운 커밋 F', G', H'으로 생성합니다. 이 때 충돌이 일어난 부분(F')부터 하나씩 해결해 나가야 합니다. 이 후 원해의 브랜치인 F G H는 dangling되어 가비지 콜렉션의 대상이 됩니다.

 

rebase 과정이 끝나면 마치 C이후에 F G H 과정이 일어난 것처럼 보입니다.

 

Rebase를 하면 커밋들의 Base가 변경되므로 Commit Hash 또한 변경 될 수 있습니다. 이로 인해 Force Push를 해야할 경우도 있으니 주의해야합니다.

 

$ git checkout my-branch
$ git rebase main
$ git checkout main
$ git merge my-branch

명령 순서를 보면 알겠지만, 결과적으로 Fast-Forward Merge를 사용하는 것을 확인할 수 있다.

 

참조

https://hudi.blog/git-merge-squash-rebase/

 

 

** 틀린 내용이 있을 시 지적해 주시면 감사하겠습니다.