Git Merge와 Rebase

DongHwan·2021년 8월 28일
0

Git

목록 보기
4/12

git에서 서로다른 브렌치를 하나로 합치는 방법 중에 Merge와 Rebase가 있다.

Merge

Merge는 다른 브렌치의 커밋 이력들을 내 브렌치로 병합하는데, 이 때 기존의 커밋들은 그대로 가져오면서 새로운 커밋을 만들어 브렌치를 병합한다.
위 그림은 main 브렌치가 C4 커밋을 가리키고 있을 때 git merge develop을 한 모습이다.
보이는 바와 같이 C6이라는 새로운 커밋이 만들어지면서 두 브렌치가 병합되었다. 또한, 기존의 커밋들은 변경된 점 없이 그대로 있는 것을 볼 수 있다.

Merge의 가장 큰 장점 중 하나는 병합하는 과정이 간단하다는 것이다. 한번의 merge 명령어로 브렌치의 병합이 가능하고, 이 과정에서 파일들의 conflict만 해결해주면 된다. 그런데 Merge의 단점 중 하나로 커밋 이력이 지저분해진다는 것이 있다.
위 그림은 main 브렌치에서 develop 브렌치를 만든 뒤, 각자의 브렌치에서 커밋을 하였다.

커밋을 한 순서 시간상으로 C1, C2, C3, C4 순인데, 이 것을 Merge하면 main 브렌치의 커밋 이력 순서 역시 C1, C2, C3, C4가 된다. 이것이 문제가 될 수 있는 상황은 여러명이 기능별로 다른 브렌치를 만들어 작업을 하였다. 그런데 이 결과물들을 Merge해버리니 서로의 커밋 이력들이 섞여있어서 구분하기가 어려워진다.

또 다른 단점 중 하나로는 Merge Commit이 생긴다는 점이다. 물론 이것이 무조건적인 단점으로 볼 수는 없지만, 버전과 이력을 관리한다는 Git의 목적상 불필요해 보일 수 있다.

Rebase

Rebase를 사용하면 이러한 문제를 해결할 수 있다.
Rebase는 이름에서 유추할 수 있듯이, Re + Base로 Base를 변경한다. 즉, 현재 브렌치의 Base를 다른 브렌치/커밋으로 옮길 수 있는 명령어이다.

위 상황에서 main과 develop의 공통 base는 C1이다. 이 때, git rebase main을 한다면 develop의 base가 main이 된다.

위처럼 develop 브렌치가 마치 현재의 main 브렌치 위치에서 시작된 것처럼 커밋이 만들어진다.

다른 예제를 보자
위 그림에서 d1과 d2의 공통 base는 C5이고, main과 d1, d2의 공통 base는 C1이다.

처음 상황에서 git rebase main을 하였다면 위 그림처럼 된다. 공통 base인 C1에서부터 차이가 나는 C4, C5, C8, C9가 옮겨진 것을 볼 수 있다.

이번에는 처음 상황에서 git rebase d1을 하였다. 공통 base인 C5에서부터 차이가 나는 C8, C9가 옮겨진 것을 볼 수 있다.

위 사례들에서 알 수 있듯이, Rebase는 두 브렌치가 분기된 시점에서부터 차이가 나는 커밋들을 한 브렌치 뒤로 붙이는 것을 볼 수 있다. 이런식으로 한 브렌치의 커밋 이력들을 다른 브렌치 뒤로 차례대로 붙여주기 때문에, 커밋 이력이 깔끔해진다. 단순히 깔끔해져서 좋다는 것이 아니라 커밋 이력들을 기능별로 붙여서 보여줄 수 있다는 것이 좋은 것이다.

Rebase에서 커밋은 새로 만들어진다.

추가로 알아두어야 할 것이 Rebase를 하면 기존의 커밋들이 이동되는 것이 아니라 새로운 커밋들이 만들어진다. 바로 위 그림을 보면 C8, C9는 그대로 남아있되, C8'와 C9'가 새로 생기어 d1 브렌치 뒤에 붙은 것을 알 수 있다. Git의 내부 구조를 알면 쉽게 이해가 가능한데, Commit 객체는 부모 커밋 객체를 가리키고 있다. 그 말은 내용물(Blob, Tree)이 완전히 동일하더라도 부모 객체가 다르면 다른 커밋이라는 뜻이다. 그렇기 때문에 Rebase를 할 때는 새로운 커밋이 생겨난다는 것을 알아야 한다.

이것을 왜 알아두어야 하냐면, 추후 오픈소스 프로젝트나 기업 프로젝트에서 PR을 보낼 일이 있을 때 이 PR이 merge and rebase 방식으로 병합한다면 문제가 발생할 여지가 있다. PR이 병합이 되면, PR에 있던 기존의 커밋들은 새로운 커밋으로 만들어져 병합이 된다. PR에 있던 기존의 커밋들은 Fork한 레포지토리와 내 로컬 커밋들과 동일할 것인데, 만약 이 상태에서 그대로 개발을 진행한다면 어떻게 될까? 위에서 Rebase는 공통된 Base로부터 차이가 나는 커밋들을 병합한다고 했는데, 내 로컬 커밋(기존의 커밋)들과 프로젝트에 병합된 커밋(새로운 커밋)들은 서로 다르다. 즉, 병합하는 과정에서 문제가 발생한다.
그래서 이런 경우에는 적절한 동기화를 해준 뒤 다시 작업을 해야하며, 이 같은 문제로 Rebase는 일반적으로 공개 저장소에서는 사용을 자제해야 한다고 한다. 이에 대해서는 나중에 글을 다시 작성해서 정리해야겠다.

Rebase의 내부 동작

Rebase가 내부에서 동작하는 방식은 Base가 될 타겟 커밋에서 이동할 커밋들을 처음부터 하나씩 새로 커밋한다. 즉, 위 사진에서 git rebase main을 하면, 타겟 커밋인 C3에서 이동할 커밋인 C4, C5가 차례대로 새로 커밋이 된다. 이 커밋 과정에서 Conflict가 발생하는 부분은 유저가 해결해주는 방식으로 진행되는 것이다.

참고 자료

Git Rebase 활용하기
Git - Rebase 하기
[Git] Pull Request를 보내기 전에, Rebase를 해야 할까요 혹은 merge commit을 만들어야 할까요?
Git Rebase 제대로 알고 쓰자

profile
날 어떻게 한줄로 소개해~

0개의 댓글