안 그래도 최근 Git Flow를 배우며 rebase가 헷갈렸는데 마침 이번 위클리 페이퍼 주제가 rebase를 다루게 됐다. (사실 나 같은 초보자는 아직 팀의 리포에서 merge만 해볼 뿐, rebase는 한 적이 없다.)
rebase와 merge를 쉽게 이해하기 위해 예시도 열심히 작성했으니 나 같은 초보들에게 도움이 되기를.
git rebase와 git merge의 차이점을 설명하고, 각각 어떤 상황에서 사용하는 것이 적절한지 설명해주세요.
우선 각 개념을 살펴보자.
더 익숙한 머지를 먼저 살펴보는 게 좋을 것 같다.
git merge란?
말 그대로 합치는 것이다. 보통 머지를 쓰는 경우 다음과 같다.
0. develop 브랜치로부터 feature1, feature2 브랜치를 생성, 분기한다.
1. feature1, feature2 브랜치에서 각자 작업한다.
2. 작업이 완료되어 feature1 작업 내용을 develop 브랜치로 합친다.
3. feature2 작업 내용을 develop 브랜치로 합친다.
참고한 git 문서에서는 각 커밋이 원래 내용에 합쳐진다는 의미로
화살표가 이전 커밋을 향하지만
시간의 흐름에 따라 생각해보고 싶어서 내 그림에서는 다음 커밋을 향한다.
현재 원격 저장소에 커밋이 다음과 같이 존재하고, develop 브랜치는 가장 최신 커밋에 있다.

develop 브랜치로부터 feature1, feature2 브랜치를 만든다.
$ git checkout -b feature1
$ git checkout -b feature2

feature1, feature2 브랜치에서 각각 작업을 하고 커밋을 한다. develop 브랜치에서보다 더 많은 작업을 하고 커밋을 했기 때문에 feature 브랜치들은 앞으로 나아간다.
$ git commit -m "feature1"
$ git commit -m "feature2"

feature1에서 C3 커밋 내용을 develop 브랜치에 합친다.
$ git checkout develop
$ git merge feature1
feature1 브랜치는 develop이 가리키던 C2 커밋에서 기반하였기 때문에 develop 브랜치에서는 단순히 C3 커밋 내용을 추가하기만 하면 되므로, develop 브랜치 포인터는 feature1과 같이 C3 커밋을 가리킨다. 이렇게 단순히 앞으로 이동하는 것을 Fast forward 방식이라고 한다.

feature2 브랜치에서 추가 작업을 하고, 커밋을 해도
develop, feature1과는 전혀 관계가 없다.
$ git checkout feature2
$ git commit -m "feature2:C5"

이제 feature2 브랜치를 develop에 합쳐보자.
$ git checkout develop
$ git merge feature2
Fast forward 때처럼 간단히 합칠 순 없다. feature2는 develop과는 다른 히스토리를 쌓았기 때문이다. 이때는 각 브랜치가 가리키는 커밋 두 개와, 두 브랜치의 공통 조상을 이용하여 3-way Merge를 한다.
develop 브랜치의 포인터가 최신 커밋 C5로 옮겨가는 게 아니라, 공통 조상 C2, develop 브랜치의 현재 위치 C4, feature2 브랜치에서 머지하고자 하는 C5, 이 세 커밋을 git에서 적절히 merge하고(깃허브가 알아서 해준다), 이를 성공하면 새로운 별도의 커밋 C6을 만든다.
그리고 develop 브랜치는 이 C6을 가리킨다.

그럼 최종적으로 develop 브랜치에 히스토리를 살펴보면 다음과 같이 된다.
가장 처음 커밋인 C0부터 가장 최신 커밋인 C6까지의 모든 커밋을 다 담고 있다고 보면 된다.
C0 -> C1 -> C2 -> C3 -> C4 -> C5 -> C6

git rebase란?
re"base"라는 이름에서 알 수 있듯 브랜치의 베이스를 새롭게 설정한다는 뜻이다.
동료 개발자가 공유 브랜치에 새로운 커밋을 올리고, 그것을 내 브랜치에 반영해야 할 때, rebase를 사용한다면 최신 커밋을 브랜치에 반영할 수 있다.
다음과 같은 상황을 가정해보자.
develop 브랜치의 C1 커밋 시점에서 feature1, feature2 브랜치로 각각 분기하여 작업을 이어 나간다.
이때 각 브랜치의 베이스는?

feature1의 작업이 끝나 develop에 merge하였다. feature1은 develop의 최신 커밋으로부터 이어진 브랜치이므로 Fast forward 방식이다.
$ git checkout develop
$ git merge feature1

feature2에서 작업하던 개발자가 새롭게 업데이트된 develop의 내용을 반영하고 싶다면, 즉 feature2가 develop의 커밋을 기반으로 다시 작성되길 원한다면
feature2의 베이스를 develop의 최신 커밋으로 옮기면 된다.
= feature2를 develop 위로 올린다.
$ git checkout feature2
$ git rebase develop
이러면 merge를 하지 않았는데도, feature2가 develop의 내용을 가지게 된다.

만약 feature2에서 한 번 더 커밋을 작업을 마무리한 후
develop에 이 작업 내용을 합치고 싶다면 develop에서 merge를 하면 된다. feature2의 베이스가 develop의 최신 커밋이므로 Fast forward 방식이다.
$ git checkout develop
$ git merge feature2

이때 merge 대신 물론 rebase를 해도 된다. 이때는 develop의 베이스를 feature2로 하면 된다.
feature2의 커밋 히스토리이다.
베이스였던 C1으로부터 develop의 최신 커밋인 C2, C3을 포함하게 됐다.

develop의 커밋 히스토리이다.
feature2가 Fast forward 방식으로 합쳐져 feature2의 최신 커밋으로 옮겨갔다.

브랜치가 다음과 같은 상황이라고 가정하자. 모든 커밋은 push되어 있다.
A --- B --- C (origin/main)
\
D --- E (feature)
여기서 feature를 main으로 rebase하면 아래처럼 된다.
A --- B --- C (origin/main)
\
D' --- E' (feature)
D와 E는 rebase 전과 내용이 만약 달라지지 않았더라도 커밋의 ID는 다르다. D와 E 커밋은 사라진 것이다.
만약 rebase한 나 말고 다른 사람이 이미 D와 E에서 작업 중이었다면?
리모트의 히스토리가 변경되면서 기존의 D와 E 커밋이 사라졌기 때문에, 다른 개발자가 git pull을 시도할 때 충돌이 발생한다.
merge와 rebase를 단순하게 나타내면 아래와 같다. 결과물은 같지만 도달하는 과정이 다르다.
merge는 두 브랜치가 합쳐졌다는 게 명확히 드러나고, rebase는 히스토리가 직렬되어 있다.

브랜치가 많아지면 많아질수록 그 차이가 더 명확하다.

git merge
git rebase
참고자료
그림: 나
코드잇 스프린트 강의 노트
Git 브랜치 - 브랜치와 Merge 의 기초
Git 브랜치 - Rebase 하기
[Git] Git Rebase 에 대해 자세히 알아보자
[Git] Git Rebase 란? / 쉽게 이해하기 / 예시