Git merge, rebase 이해하기

Git merge, rebase 이해하기.


지난번 포스팅에서 git workspace가 어떤 구조로 이루어져있는지 살펴보았습니다. 또, 서로 다른 branch끼리의 병합에 대해서 살짝 다루었습니다.

다른 형상관리툴들과는 달리 gitbranch를 생성할 때 파일을 복사하는 것이 아니라 파일의 스냅샷만 가지고 생성하기 때문에 자원의 부담없이 branch를 만들어 사용할 수 있습니다. 이러한 장점때문에 git으로 작업을 할 때에는 다양한 용도의 branch를 만들어 사용하는데, 이번 포스팅에서는 이러한 작업에서 필수적인 branch를 병합하는 2가지 방법의 원리와 차이에 대해서 살펴보겠습니다.

Merge

branch를 병합할 때 가장 많이 쓰이는 기능입니다. 사실 mergerebase를 구분하지 않고(혹은 차이를 잘 모르고) 단순히 merge명령어만 사용해서 작업을 하는 경우도 많이 있지요. merge명령어가 어떻게 작동하는지 알기위해 지난번 포스팅을 복습하며 merge를 사용되는 몇 가지 케이스를 살펴보겠습니다.



위 이미지처럼 편의상 master branch가 있고 3개의 commit object가 있다고 가정해 보겠습니다. 이 상황에서

git checkout -b dev

명령어를 이용해서 dev branch를 생성, checkout한 후 dev branch상에서 2번 더 commit을 했을때의 object구조는 다음과 같습니다.

그리고 이 상태에서 dev branch를 master branch로 병합을 해 보면 다음과 같이 변경됩니다.

git checkout master
git merge dev


뒤쪽 commit을 가리키고 있던 master branch가 fast-forward되어 dev와 같은 branch를 가리킵니다.

이 시나리오는 정말 이상적인 commit시나리오 입니다. commit log를 보더라도 군더더기 없이 깔끔한 그래프를 그려서 보여줄 것입니다. 하지만 작업을 하다보면 여러가지 branch가 생성이 되고 프로젝트가 커질수록 merge를 하면서 지금처럼 fast-forward로만 merge가 될 수 는 없습니다.

이제 아까 시나리오에서 병합하기 전으로 돌아가서 master branch에서도 몇개의 commit이 더 발생했을 경우를 살펴보겠습니다.


이런 상황에서 master branch에 dev branch를 merge하면 fast-forward대신 다음과 같이 새로운 merge commit을 새로 생성합니다.


아래의 그림은 간단한 merge commit을 확인할 수 있는 git의 log graph입니다.


git merge dev


여기서 b8fc074 SHA-1 hash를 가지고있는 commit object에 주목해봅시다. merge commit이 생성되면서 merge graph에 필요없는 object가 나타났고, 그로인해 commit log에 필요없는 로그가 생기면서 지저분해 졌습니다. 이는 merge log의 가독성에 크게 영향을 미칩니다. 이런 불필요한 commit object의 생성이 많아지게되면 심할 경우에는 아래와같은 그래프를 생성합니다.


거의 무지개를 그리고있지요. 이런 정도가 되어버리면 merge log를 본다는 일 자체가 엄청 피곤한 일이 되어 버립니다. 그래서 우리는 최대한 이런 불필요한 commit object의 생성을 줄일 필요가 있습니다. 어떻게 할 수 있을까요?

Rebase

이럴때 우리는 rebase를 사용합니다. 처음에 제가 rebase의 의미가 대체 무엇일까 이해할 때 이름을 살펴보는게 많이 도움이 되었습니다. 말 그대로 re-base 즉, branch의 base를 다시 설정한다는 의미이죠. 이제 도대체 무슨의미인지 그림으로 보시면 이해가 빠릅니다.

다시 위와같은 상황으로 돌아와봅시다.

아까와 같은 merge commit을 생성하지 않고 branch를 병합하기 위해선 dev branch의 root commit이 'COMMIT2'에서 'COMMIT5'로 바뀌어야 합니다. 이런 작업을 가능하게 해 주는게 rebase명령어 입니다. 한 가지 유의할 점은 이 예제에서 rebase작업은 master branch가 아닌 dev branch가 변경되는 것이므로 dev branch를 checkout한 후에 진행해야 합니다.

git checkout dev
git rebase master

위의 명령을 실행하면 아래그림과 같이 dev branch의 base commit이 'COMMIT5'로 변환됩니다. 물론 이 과정에서 'COMMIT2'의 내용이 dev branch에 병합됩니다.

이제 master branch에서 dev branch를 merge해도 merge commit이 생기지 않고 fast-forward가 발생할 수 있습니다. 즉 우리는 더 깔끔하고 읽기 좋은 commit log를 남길 수 있겠지요.

결론

간단하게 개념적으로나마 mergerebase가 어떻게 동작하는지, 또 어떻게 쓰일 수 있는지 알아봤습니다. 형상관리툴은 많은 사람들이 협업하는 프로젝트에서 그 진가가 드러난다고 생각합니다. 그런측면에서 생각했을 때, 깔끔한 log관리에 신경쓰는 일은 아주 작지만 중요한 요소이겠지요. merge명령어 한가지만으로도 git이 제공하는 기능들을 사용하는데 불편함이 없지만, 내가 작업하는 프로젝트의 히스토리를 잘 정리할 수 있다면, 함께 일하는 동료 혹은 프로젝트를 이후에 열람하게되는 사람에게 더 나은 협업경험을 선사할 수 있을 것입니다.


Reference





New Multi-Channel Dynamic CMS