깃에서 다른 사람의 코드에 내 코드를 통합할 때(integration) 쓰는 대표적인 두 가지 방법을 비교해 보고 언제 어떤 방식을 써야 하는지 알아 보려고 한다.
머지(Merge)
머지(병합, merge) 는 두 개 이상의 개발 히스토리를 하나로 합치는 작업을 의미한다. merge를 하게 되면 각각의 개발자가 작업한 히스토리가 모두 보존(preserve)된다는 특징이 있다.
예제를 한 번 살펴보자. 두 명의 개발자 Ada와 Satoshi가 각각 feature-1, feature-2를 작업한다. Ada는 작업을 완료해서 master 브랜치에 머지를 한 상태고, 이후 Satoshi가 master 브랜치는 feature-2 브랜치에 머지를 한다고 가정해 보자.
결과는 다음과 같다. Satoshi가 작업한 C5, C6 커밋 히스토리는 모두 남게 되고 C7 커밋이 추가되면서 여기에는 C4까지 수정되었던 내용들이 전부 반영이 되게 된다. 만약 master 브랜치로 feature-2를 머지하고 싶다면
git switch master
git merge feature-2
와 같이 명령하면 된다.
머지는 사용법이 단순하고 히스토리가 시계열로 남는다는 장점이 있지만, 하나의 깃에서 같이 개발하는 동료가 늘어날 수록 머지 커밋이 기하급수적으로 늘어나고 바쁜(busy) 브랜치 또는 바쁜 레포지토리에서는 노이즈가 많이 생긴다. 커밋로그도 굉장히 지저분해질 가능성이 높다.
리베이스(Rebase)
리베이스(rebase)는 브랜치(branch)의 베이스(base)를 재설정하여 다시 커밋을 재적용하는 작업을 의미한다. 브랜치는 베이스 지점을 가지고 있고 베이스에서 코드를 수정한다. 깃 히스토리를 살펴보면 베이스가 어디에 있는지를 알 수 있다.
리베이스를 수행하면 다음과 같은 결과가 나타난다.
- B 지점을 베이스로 가진 브랜치가 D, E 커밋을 진행한다.
- C 지점으로 베이스를 이동하기 위해 브랜치에서 C 지점으로 리베이스를 한다.
- C 지점으로 리베이스 되면 기존 D, E 커밋은 새롭게 정렬되어 C 지점 이후로 변경된다.
이렇게 정리를 하게 되면 D*, E* 커밋은 기존 D, E 커밋과 다른 새로운 해시 id 값을 가진 커밋으로 처리가 되며 깃 히스토리가 깔끔해 진다는 장점이 있다. 따라서 많은 사람들과 협업을 할 때 리베이스를 사용하는 것을 권장하는 팀이 많다.
리베이스를 위에 예제에서 적용해 보면 다음과 같다.
git rebase master feature-2 명령어는 master 브랜치로 feature-2 브랜치를 리베이스 한다는 의미이다. 따라서 C4 커밋 다음으로 이어서 C5, C6 커밋이 추가가 되는데 엄밀히 말하면 C5*, C6* 으로 표시해 주는 것이 맞다. 이유는 기존에 Satoshi가 feature-2 브랜치에서 작업한 C5, C6 커밋과는 다른 커밋이기 때문이다. 한 마디로 C5, C6 커밋은 master 브랜치 위에서 재 작성 되었다.
머지 vs 리베이스
우리가 지금까지 살펴본 바 정리하면 머지는 히스토리를 보존하고, 리베이스는 히스토리를 재작성한다. 그러면 각각의 장단점은 어떻게 되며, 어디에 어떤 방식을 사용하는 것이 좋을까?
변경사항 충돌 (Conflicting changes)
위의 예제에서 Satoshi가 작업한 C5, C6를 master와 합치는 과정을 다시 생각해 보자. 이 과정에서 충돌(conflicts)이 발생할 수 있다. 머지를 할 때는 충돌을 한 번 C7에서만 수정해 주면 된다. 반면 리베이스를 하게 되면 각각의 커밋(C5, C6)을 재작성 할 때 비슷한 충돌을 해결해 주어야 한다.
만약 충돌을 해결하는 것이 직관적이지 않고 너무 어렵다면, 이는 당신과 당신의 동료들이 커뮤니케이션을 충분히 하고 있지 않거나, 같은 파일을 너무 오래 작업하고 있다는 점을 시사한다.
공개된 브랜치 (Published branch)
리베이스를 할 때 또 하나 고려해 볼 만한 잠재적인 문제는 당신이 리베이스를 하려는 브랜치가 이미 원격에 저장된(published remotely) 경우에 발생할 수 있다. 이 경우 당신의 리베이스된 브랜치는 심각한 혼란을 초래할 수가 있다. 깃은 이 경우 같은 깃에서 작업하는 구성원들에게 당신의 브랜치가 동시에 앞에 있거나 뒤에 있다고 알려줄 것이다.
이러한 일이 발생한 경우 원격에서 변경된 사항들을 리베이스 플래그를 사용해서 pull 받으면 일반적으로 해결할 수 있다.
git pull --rebase
데이터 손실 (Loss of data)
리베이스는 히스토리를 재작성하기 때문에 리베이스를 할 경우 데이터 손실이 일어날 수 있다. 새로운 커밋이 재적용되면, 이전 것은 삭제된다. 이 특성은 리베이스를 굉장히 강력하게 만들어 주기도 한다. 이는 서비스 공개 전 당신의 개발 히스토리를 깔끔하게 정리할 수 있게 도와준다. 원치 않는 커밋을 지우거나, 여러 변화들을 스쿼시하거나 간단하게 커밋메시지를 업데이트 할 수 있다.
리베이스 규칙 (Rebasing Rules of Thumb)
리베이스와 관련된 자주 발생되는 이슈들을 피하기 위해서는 다음과 같은 규칙을 지키는 편이 좋다.
- 원격 저장소에 올라간 커밋은 리베이스 하지 말 것.
- 다만.. 혼자 작업을 하는 깃이면 상관없다. 안전하게 force push 할 수 있기 때문이다.
- 리베이스 전에 리베이스 하려는 브랜치 끝에서 백업 브랜치를 만들어 놓자.
- 이는 리베이스 후 결과물을 쉽게 비교할 수 있게 해주고 필요 시 리베이스 전 상태로 돌아갈 수 있게 해준다.
- 혼자 또는 작은 규모의 팀에서는 리베이스를 사용하는 편이 좋고, 큰 규모의 팀에서는 머지를 사용하는 것이 좋다. 하지만 이 역시 정답은 아니다.
결론
대부분의 개발자들은 사실 머지만 가지고 작업을 하는 경향이 있다. 최소한 자신이 작업한 내용을 잃지 않을 것이다라는 믿음을 가지고 말이다. 물론 리베이스가 편하지 않을 수도 있고, 처음에 적응은 쉽지 않겠지만 강력한 도구를 온전하게 사용하는 방법을 아는 것은 매우 중요하다. 이는 마치 엄청난 자동차를 가지고 있는데 속도가 빨라지면 위험하다는 이유로 1단 기어로만 놓고 운전하는 드라이버와 비슷하다.
리베이스를 잘 쓸 수 있게 되면, 깃에 대한 이해도가 높아진다. 그리고 전반적으로 더 나은 개발자가 될 수 있게 도와줄 것이다. 그리고 가능하면 SourceTree 같은 도구보다 GUI 도움 없이 터미널 명령어로만 깃을 사용해 보도록 하자. 이후 자동화 파이프라인을 구축하게 될 일이 있을 때 큰 도움을 줄 것이다.
레퍼런스
https://firework-ham.tistory.com/12
https://www.perforce.com/blog/vcs/git-rebase-vs-git-merge-which-better
'Prog. Langs & Tools' 카테고리의 다른 글
[패캠] 데이터 사이언티스트 하용호님 강의 요약 정리 (0) | 2021.08.10 |
---|