1. rebase
rebase는 merge처럼 병합하는 작업이지만, 커밋 이력을 다룰 수 있다는 점에서 차이가 있는데요. ( merge와 rebase 비교 - 참고 )
불필요한 merge 이력을 남기지 않기 때문에, Git은 rebase를 통해 병합할 것을 권장하고 있습니다.
하지만 이것은 회사마다 정책이 다를 것이기 때문에 회사에서 사용하는 방식을 따르면 됩니다.
rebase로 병합을 하면 충돌이 발생하더라도 fast-forward 방식의 병합이 이루어지기 때문에 히스토리가 깔끔하게 관리된다는 장점이 있고,
또한 --interactive 옵션을 사용하면 local에서 히스토리를 조작할 수도 있습니다.
개인적으로는 local에서 --interactive로 히스토리를 깔끔하게 관리한 후, push하는 방법을 자주 사용하고 있습니다.
기능마다 커밋이 있어야 버그잡기가 편한데, 불필요한 커밋이 많으면 찾기가 힘들더라구요.
이제 rebase를 통해 병합하는 방법과 --interactive 옵션을 추가해서 커밋이력을 어떻게 관리하는지에 대해 알아보겠습니다.
2. rebase 병합 방식 ( Merge vs Rebase )
rebase의 병합방식을 살펴보기 위해서는 merge와 비교해보는게 좋습니다.
먼저 git merge 방식입니다.
브랜치 brchA, brchB를 생성해서 2개의 커밋을 작성했습니다.
그리고 brchB에서 brchA를 merge했고, 충돌난 부분을 제거하여 커밋을 한 후, 로그를 살펴봤습니다.
커밋 로그를 보니, 총 4개의 커밋 이력이 있네요.
이것이 일반적인 merge 했을 때 커밋의 이력 모습입니다.
다음은 git rebase 방식입니다.
마찬가지로 브랜치 brchA, brchB를 생성해서 2개의 커밋을 작성했고, brchB에서 brchA를 rebase를 실행했습니다.
마찬가지로 충돌난 부분을 제거하여 커밋을 한 후, 로그를 살펴봤습니다.
이번에는 커밋 로그를 보니, 총 3개의 커밋 이력이 있네요.
"brch B에서 커밋" <--- 이 메시지가 없습니다.
즉, git rebase 방식은 자신의 마지막 커밋 기록을 없앤 후, 병합 후에 작성한 커밋 기록을 남긴다는 것을 확인할 수 있습니다.
이 방식은 다음의 --interactive 옵션을 통해 대화형으로 살펴보면 쉽게 이해할 수 있습니다.
3. --interactive 옵션
rebase 명령어의 --interactive 옵션을 사용하면, 커밋 로그를 조작할 수 있습니다.
즉, 불필요한 커밋 이력을 제거해서 필요한 커밋들만 남길 수 있습니다.
물론 그 커밋에서 작업했던 내용들은 그대로 유지하면서요.
이제 --interactive 옵션을 통해 커밋 히스토리를 관린하는 방법에 대해 알아보겠습니다.
이 과정은 위에서 살펴본 rebase 병합 방식과 매핑하여 생각해볼 수도 있습니다.
1) 초기 커밋 히스토리
초기 커밋 이력 히스토리입니다.
2) rebase --interactive {커밋ID}
중간에 있는 두번째, 세번째 커밋을 제거하려고 합니다.
그러면 다음과 같이 첫번째 커밋ID( 2462291 )로 rebase 하면 됩니다.
# git rebase --interactive 2462291
이 명령어를 실행하면 아래의 에디터( vi 편집기 )가 열립니다.
편집기에 주석으로 되어 있는 Commands에 명령어에 대한 설명이 나와 있습니다.
제가 할 것은 squash라는 것인데요, squash는 이전 커밋과 합쳐서 커밋을 하도록 실행하는 명령어입니다.
아래과 같이 네번째 커밋( 6837557 ), 세번째 커밋( 94af9ac )의 pick을 squash로 바꾸면,
6837557와 94af9ac를 병합할 때, 6837557의 커밋 내용을 유지하고
94af9ac와 두번째 커밋( 90b3dc4 )를 병합할 때, 94af9ac의 커밋 내용을 유지한다는 의미가 됩니다.
즉, 첫번째 커밋( 2462291 )을 병합할 때 까지 중간에 있는 커밋들이 연쇄적으로 병합이 이루어지는데, 병합을 어떤 방식으로 할 것인지를 명시하는 것입니다.
또한 90b3dc4는 squash를 사용할 수 없는데, 그 이유는 명령어를 실행할 때 대상 커밋인 2462291와 rebase하도록 했기 때문입니다.
위의 2. rebase 병합방식 에서도 brchA가 남겨진 이유가 그것입니다.
따라서 90b3dc4는 pick으로 그냥 뒀습니다.
다른 명령어인 pick은 그냥 그 커밋을 그대로 사용한다는 것이고, drop은 그 커밋을 버린다는 의미입니다.
6837557, 94af9ac 두 커밋을 squash로 수정한 후 편집기를 저장하고 종료합니다. ( esc + :wq! + enter )
그러면 아래와 같이 다시 편집기가 열립니다.
이번에 열린 편집기는 커밋 메시지를 어떻게 남길 것인지를 명시하는 것입니다.
주석 처리(#)가 되어 있지 않은 메시지들이 커밋 메시지에 기록됩니다.
모두 남기고 싶지 않다면, 메시지를 모두 지우고 새롭게 작성하면 됩니다.
메시지를 지우지 않더라도 local repository에서 log를 확인해보면 메시지가 않보이는데요.
그런데 github에 push를 해보면, 메시지들이 남게됩니다.
편집기를 저장하고 종료하도록 합니다.
4) 히스토리 확인
마지막으로 히스토리가 잘 지워졌는지 로그를 확인보겠습니다.
이상으로 rebase에 대해 알아보았습니다.
rebase를 통해 브랜치를 병합할 수도 있고, 커밋 로그를 깔끔하게 정리할 수 있는데요.
기본 원리는 똑같은 것 같습니다.
병합할 때 rebase를 사용할 것인지 merge를 사용할 것인지는 동료들과 상의하면 될 것 같습니다.