모르는게 많은 개발자

[Git] Branch 병합 전략(Merge, Rebase, Squash) 개념/예제 본문

GIT

[Git] Branch 병합 전략(Merge, Rebase, Squash) 개념/예제

Awdsd 2021. 6. 25. 20:04
반응형

이번 포스팅에서는  Git 브랜치 병합 전략에 대해 포스팅하려 한다. 평소에 Git을 사용하며 Merge만 거의 사용해서 브랜치를 합쳤는데 이렇게 하니 히스토리가 지저분해진 것을 보고 Rebase와 Squash에 대해 제대로 알고 사용하고자 정리해놓으려한다.


브랜치 병합 전략에는 3가지가 있다.

1. Merge
2. Rebase Merge
3. Squash Merge

1. Merge

먼저 가장 기본 병합 방법인 Merge에 대해 알아보자.

Merge에는 여러가지 방식이 있지만 크게는 두가지의 방식이 많이 사용된다.

Fast-Forward
3-Way-Merge

 

Fast-Forward

먼저 아래의 Commit 히스토리를 보자.

master 브랜치에서 생성된 A 브랜치가 두 번의 Commit을 한 상태이다.

이 상태에서 A 브랜치를 master에 Merge를 한다면 master의 위치가 A로 바로 이동하는 것을 확인할 수 있다.

이처럼 A브랜치를 Merge할 때 조상 브랜치인 Master에 변경점이 없다면 Master브랜치를 바로 A브랜치로 이동해서 Merge하는 것을 Fast-Forward라 한다.

 

3-Way-Merge

이번에는 Fast-Forward랑 다르게 아래처럼 A브랜치와 Master 브랜치 둘다 변경사항이 있을 경우에 Merge하는 가장 일반적으로 경우이다.

위의 상태에서 A브랜치를 master브랜치에 Merge하면 아래와 같은 결과가 나온다.

3-Way-Merge는 각 브랜치의 최신 Commit과 공통 조상(Base) 커밋 ('A1 생성') 을 비교하고 새로운 Commit을 만들어 Merge하는 전략이다.

아래 표는 3-Way-Merge의 Merge 과정이다.

A 브랜치 Base master 브랜치 Merge
Code1 변경 Code1 Code1 A 브랜치 Code1 적용
Code2 Code2 Code2 변경 master 브랜치 Code2 적용
Code3 변경 Code3 Code3 변경 충돌(Conflict) 발생

위 표를 보면 조상(Base) Commit 기준으로 A 브랜치에서 Code1을 변경하고 master 브랜치에서 변경을 안했으면 A의 작업이 반영되고, 그 반대인 master 브랜치가 작업한 Code3도 반영된다. 하지만 Code2는 A, master 모두 변경했기 떄문에 충돌 가능성이 생긴다.

이러한 비교 과정을 거쳐 dev 브랜치의 작업내용이 Merge Commit에서 적용되어 master에 Merge된다.

 

Merge의 특징은 다음과 같다.

  • 변경 내용의 커밋 내역이 모두 그대로 남는다.
  • Merge시 Merge Commit이 새로 생긴다.

이러한 특징때문에 불필요한 Commit 내역(Merge Commit)이 생겨 히스토리가 지저분해져서 협업 과정에서 Commit 확인에 불편함이 생긴다.(수십명이 하나의 Git 저장소를 사용하고 모두가 Merge를 사용한다면...)

 

그래서 이러한 문제를 해결할 방법이 이 다음에 살펴볼 Rebase이다.


2. Rebase

Rebase란 공통 base(조상)를 가진 두 브랜치에서 하나의 브랜치의 base를 다른 브랜치의 최신 Commit을 base로 하게끔 재정렬 하는 것을 의미한다. 빠르게 예제를 보자.

위 처럼 dev, master 브랜치의 공통 base('dev4')커밋에서 dev, master 브랜치가 작업을 했다고 가정하자.

 

이 상태에서 dev를 master에 merge하면 master 브랜치에 merge Commit이 하나 생기면서 Merge가 될 것이다.

 

하지만 dev 브랜치를 master 브랜치에 Rebase를 하게 될 경우 base('dev4')부터 dev branch의 Commit('dev5', 'dev6')을 master branch의 다음 Commit으로 재정렬 한다.

$ git checkout dev
$ git rebase master

Rebase를 수행하면 위처럼 master 브랜치에 dev 브랜치 Commit이 정렬된것을 확인할 수 있다.

 

주의할 점은 master 브랜치의 위치이다. 아직 master 브랜치에서는 dev 브랜치 내역을 Merge 한것이 아니기 때문에 master 브랜치에서 dev 브랜치를 Fast-Forward-Merge 해야 한다.

$ git checkout master
$ git merge dev

Rebase를 수행할 경우 Merge와 다르게 Merge Commit이 생기지않는다. 하나의 브랜치에서 작업한 것처럼 보이므로 히스토리를 간결하게 하고 싶을 때 사용한다.

이제 Rebase를 통해 Merge Commit을 만들지 않고 히스토리를 깔끔하게 유지 할 수 있게되었다. 하지만 더 나아가 내가 작업한 Commit이 너무 많아 지저분해 보인다면 어떡할까? 이에 대한 해결방법에는 Squash가 있다.


3. Squash

Git Squash는 여러개의 Commit을 하나의 Commit으로 만들어준다.

dev 브랜치의 'dev squash', ''dev14', 'dev15' Commit을 합쳐보자. Squash를 하려면 Rebase에 -i 옵션을 이용해야한다.

$ git rebase -i [CommitID] 

위 명령어를 사용할 시 입력한 Commit Hash 다음 Commit 내역들이 표시되게 된다.

위의 'squash' CommitID를 입력하면 아래와 같은 창이 나타난다.

$ git rebase -i 56f3f1a

먼저 맨위의 3줄을 보면 'squash' Commit의 다음 Commit 내역들이 출력된 걸 볼 수 있고, 아래에는 명령어 옵션들이 써있는 것을 볼 수 있다.

 

여기서 우리는 squash 옵션을 사용해 Commit을 합칠 수가 있는데 합치고자 하는 시작 Commit에 pick옵션을 주고 합쳐질 Commit에는 squash를 입력해준다.

이 상태에서 저장하면

이러한 두번째 창이 뜨게 되는데 이 창은 합쳐진 Commit의 새로운 Commit Message를 입력해야 한다.

이렇게 입력하고 저장하면

'squash' 다음의 dev brach 커밋 내역이 합쳐진 것을 확인할 수 있다.

pick과 squash를 사용하면 하나의 커밋이 아닌 원하는 커밋 수로 압축할 수 있다.

위 처럼 pick을 두개 지정하고 squash를 두번 행하면 commit message 입력창이 두번 나오고 아래처럼 두개의 Commit으로 합칠 수 있다.

다른 옵션들

위의 git rebase -i 를 입력했을 때 아래와 같은 옵션을 볼 수 있는데 pick과 squash는 알아봤으니 아래 옵션중 reword, fixup, drop에 대해 알아보자

reword

reword는 단순히 Commit Message를 바꿀 수 있다.

fixup

fixup은 squash와 기능은 동일 하지만 커밋 메시지를 새로 쓸 수 없고 pick한 부분의 커밋 메시지로 합쳐진다.

drop

drop을 사용하면 해당 커밋을 제거할 수 있다. 물론 해당 커밋에서 변경된 작업도 원래대로 돌아간다.

 

반응형
Comments