Rebasing

2019년 09월 10일

리베이스는 머지랑 비슷한 개념이지만 조금 다르다.

머지랑 리베이스는 다른 브랜치의 작업 내용을 합친다는 면에서 비슷하다. 내가 이해한 바로는 주요하게 다른 점은 크게 2가지이다.

  1. 머지는 fast-forward가 아닌 이상 두 개의 브랜치로 갈라진 모양이 남게 된다. 반면 리베이스는 하나의 linear한 히스토리로 남게 된다.
  2. 머지는 merge commit을 필요로 한다. 즉 머지하기 위해서는 커밋을 반드시 해야되는데 별 의미없는 커밋메세지만 남기기 십상이다. 리베이스를 하면 이 merge commit이 필요 없다.

그럼 언제 머지를 하고 언제 리베이스를 하지?

여러 명의 사람이 같이 작업을 할 때에는 리베이스가 추천된다고 한다.

여러 커미터가 있을 때에 머지를 사용하게 되면 깃 히스토리가 복잡해지고, 그러면 깃해 디버깅하는 작업 또한 매우 어려워진다. 브랜치가 여러 갈래로 나뉘어 있으면 히스토리를 파악하기도 어렵고 의미 없는 머지 커밋이 난무하면 더욱 디버깅이 어려울 것이기 때문이다.

따라서 혼자 작업을 하거나, 믿을 수 있는 커미터 소수끼리 작업할 때에만 머지 워크플로우를 사용하는 것이 적합하다. (하지만 이것은 그룹마다 다를 수 있는 부분이다)

리베이스는 어떻게 이루어지지?

master 브랜치와 test 브랜치가 있다고 하자. master 브랜치에서도 변경사항이 있고 test 브랜치에서도 변경사항이 있다.

이 경우 머지를 하게 되면 동일한 부분이 수정된 경우 컨플릭트가 나고, 컨플릭트를 해결하면 두 갈라진 브랜치가 하나로 합쳐지는 히스토리가 남게 된다. 또한 머지 커밋을 남겨야 한다.

리베이스를 할 경우, 내가 베이스로 삼고 싶은 브랜치를 정해야 된다. master브랜치를 베이스로 삼아 리베이스를 하고 싶다면 테스트 브랜치에서 git rebase master 라고 해야 한다.

이렇게 되면 마스터를 기본으로, test 브랜치의 변경사항이 마스터에 더해지는 형태가 된다. 머지를 할 때에는 마스터와 테스트 브랜치가 분기되며 공통의 조상을 갖는 형태로 갈라지는데, 이 경우에는 테스트 브랜치의 조상이 마스터 브랜치의 마지막 커밋이 된다. 즉 마스터 브랜치를 베이스로 그 위에 테스트 브랜치의 커밋을 끼얹는(?) 형태가 된다. 만약 마스터 브랜치와 테스트 브랜치 간에 겹치는 커밋이 있었다면 이는 삭제되고 고유한 테스트 브랜치의 커밋만 기존 마스터 브랜치의 커밋 위에 더해진다.

컨플릭트가 난 경우에도 별도의 머지 커밋에서 해결하는 것이 아니라, 그냥 기존의 커밋에 저장된다.

git rebase master 하면 HEAD는 여전히 테스트 브랜치를 가리키고 있는 채로, master 커밋에 test 커밋을 끼얹은 형태가 된다. 즉 master 위에 test를 붙이는 건 성공했으나 아직 test 브랜치에서만 이것이 완료된 것이다. 아직까지 마스터 브랜치에는 반영되지 않았으므로 git merge test 를 하여 fast-forward 로 병합하면 된다.

만약 여러 커미터가 있는 상황에서 내가 오리지널 레포에 컨트리뷰트를 하고 싶으면, 먼저 내 별도의 오리진 브랜치에서 작업을 한 뒤에 rebase를 하고 풀리퀘를 날리면 깔끔하게 내 변경사항을 업데이트할 수 있는 것이다.