
Git에서는 main 이라는 큰 줄기의 개발 흐름에서 여러 독립적인 개발 라인을 자유롭게 생성할 수 있다.
위 그림처럼, 각자의 브랜치는 main 이라는 큰 프로젝트를 개발하는건 동일하지만, feature, hotfix 등과 같은 다른 기능을 맡아 각자 작업하고, 작업이 끝나면 다시 큰 줄기인 main 으로 합쳐진다.
이때, 각자의 브랜치가 개별적인 작업을 마치고 main 으로, 또는 다른 branch로 합쳐지는 것을 branch merge 라고 한다.
한 브랜치에서 작업 후 더 이상의 커밋을 하지 않고 다른 브랜치에서 작업을 이어가는 경우, 위 그림과 같은 직선 경로가 생기게 된다. 이때 merge 를 진행하면 브랜치 간의 히스토리가 선형적으로 이어지며, 특정 브랜치의 커밋이 다른 브랜치의 최신 커밋으로 이동하게 된다. 선형적인 히스토리가 유지되고, 불필요하게 merge 되는 커밋이 없기 때문에 충돌 걱정 또한 없다는 것이 장점이다. 하지만, merge 하는 경우는 보통 이렇게 단순하지는 않다.
fast-forward merge 와 다르게 기존의 브랜치에서도 커밋이 이어지고, 다른 브랜치에서도 커밋이 이어졌다고 생각해보자. 그러면 서로 다른 내용이 작성된 커밋이 존재할 것이고, 결국 이를 병합(merge) 하는 과정이 필요하다. 위의 그림에서 A+B 의 파일에는 어떤 내용이 들어가게 될지 알아보자.
위의 표는 이전 그림의 premium 브랜치와 master 브랜치가 병합되는 과정에서, 어떤 브랜치의 커밋 내용이 적용될 것인지를 나타낸다. 기본적으로, merge 가 일어나는 경우에 적용기준은 base 로부터의 변화이다. 여기서 base는 두 브랜치가 갈라진 분기된 커밋을 말한다. 위의 표를 보면, case1, 2, 3 에서 base 로 부터 변화가 생겨난 브랜치의 커밋을 우선 적용하는 것을 볼 수 있다. 이는 기존 커밋에서 새로운 작업이 진행되었음을 나타내기 때문에 작업이 이루어진 쪽을 선택하는 것이다. 그런데 case4 에서는 두 브랜치의 커밋 모두 변화가 생겼기 때문에 충돌이 발생한다. 이러한 경우, 직접 개발자가 파일을 열어 충돌된 내용을 확인하고, 모두 지우거나, 모두를 적용하거나, 한쪽만 적용하거나, 아니면 아예 다른 내용을 적용하는 등 적절한 조치를 취하면 충돌은 해결된다. 다행히도 git 에서는 충돌이 발생하면, 충돌이 발생한 파일과 코드를 친절하게 표시해주기 때문에 해결은 크게 어렵지 않다.위와 같은 병합 과정은 기본적으로 커밋이 사라지지 않고 모두 남기 때문에, 프로젝트의 진행사항을 모두 확인하고 추적하기가 쉽다. 따라서 git 을 처음 사용하는 개발자로서는 가장 유용할 수 있다. 하지만, 커밋 히스토리가 매우 복잡해질 수 있다는 단점도 있다.
위 그림에서 feature 의 브랜치의 3rd, 4th, 5th 커밋 3개가 main 의 feature/f1 커밋 하나로 병합되고, 기존의 커밋들은 사라진 모습을 볼 수 있다. 이처럼 머지할 브랜치의 커밋을 전부 하나로 합친 뒤, 타겟 브랜치에 커밋하는 방식을 Squash and Merge 방식이라고 한다. git merge 커맨드에 --squash 옵션을 추가하면 사용할 수 있다.
위 그림과 같이, merge 하려는 브랜치를 타겟 브랜치에 재위치(rebase)시켜, 마치 원래 한 브랜치였던 것처럼 병합하는 방식을 Rebase and Merge 라고 한다. merge 커밋이 남지 않기를 원하는 경우에 사용하면 좋다. Squash 방식에 비해 작업했던 커밋도 남기 때문에 추후에 문제가 생기더라도 추적이 가능하다. 또, 브랜치의 커밋이 그대로 타겟 브랜치에 겹쳐지기 때문에, 커밋 히스토리를 한 줄로 깔끔하게 만들 수 있다.git rebase -i Head~<n> 커맨드를 통해 커밋메시지를 수정하기도 한다.