# Pull Request를 보내기 전에, Rebase를 해야 할까요 혹은 merge commit을 만들어야 할까요?

# Rebase vs Merge commit

목적: PR을 보내기 전에 내가 보낼 브랜치가 master와 fast-forward(컨플릭트 없이 바로 머지될 수 있는 상태)상태가 되도록 만든다.

그런데 매번 이렇게 할 필요는 없고,

  1. PR을 보낼 브랜치가 master보다 너무 옛날 상태일때나
  2. GitHub에서 PR을 보냈더니 'merge conflict warning'이 페이지에서 보일 때 (같은 코드가 고쳐졌을때 자동으로 보임) 만 하면 된다.

# 방법 1. (내 브랜치에 먼저 머지 후 풀리퀘)

  • master의 최신 상태를 내 브랜치에 merge시킨다.
  • master와 내가 똑같은 파일을 고쳤다면 conflict가 날 것이다. 그럼 해결한다.
  • 해결해서 만들어진 merge commit을 push한다 (merge commit이 새로 하나 생김)
  • 장점: 한 번의 'merge'만으로 쉽게 해결할 수 있다.
  • 단점: merge commit이 생겨서 깔끔하지 않다. 코드 수정한 의미있는 커밋만 보고싶을텐데 말이다.

# 방법 2. (리베이스 후 풀리퀘)

  • master의 최신 상태를 base로 해서 내 브랜치를 rebase한다.
  • rebase의 원리는, 내가 원하는 커밋을 base로 해서 내 브랜치가 마치 그 커밋에서 딴 것처럼 기록을 조작하는 것이다.
  • 내부에서 돌아가는 방식은, 내가 원래 딴 커밋에서부터 내가 목표하는 base커밋까지 하나씩 옮겨가면서 새로 커밋을 하는것이다.
(원래상태)

[3시커밋 --- 4시커밋 --- 5시커밋] 
  ㄴ--- 내브랜치커밋
  
(5시커밋을 베이스로 리베이스를 실행한다)
[3시커밋 --- 4시커밋 --- 5시커밋] 
              ㄴ--- 내브랜치커밋 // 한 커밋씩 옮겨가며 commit한다. 컨플릭이 나면 고쳐준다.
              
(Continue rebase를 누른다)
[3시커밋 --- 4시커밋 --- 5시커밋] 
                        ㄴ--- 내브랜치커밋 // 목표하는 5시커밋까지 왔다. 컨플릭이 나면 고쳐준다

  • 모두 완료되었으니 push를 해야하는데, 히스토리를 조작하는 위험한 작업이므로 force옵션을 넣어 push해야한다.
  • 결과: 내브랜치커밋이 master의 최신 상태인 5시커밋에서 딴 것처럼 히스토리가 조작된다. 그래서 내 브랜치에서 master로 Pull Request를 보냈을 때 fast-forward(컨플릭트 없이 바로 머지할 수 있는) 상태가 된다.
  • 장점: merge commit없이 깔끔한 커밋 히스토리를 만들 수 있다.
  • 단점: 만약 중간에 코드 컨플릭트가 나면 그 사이에 있는 커밋들 모두에서 컨플릭트를 수정해줘야 할 수 있다. 귀찮다.

# 언제 무엇을 써야하나?

  • Type 0. master에서 딴지 그리 오래 되지 않은 브랜치: 그냥 PR을 보내본다. conflict warning이 보이면 그 때 2번이나 3번 방법을 쓴다
  • Type 1. 내 브랜치에 커밋이 엄청 많다. 그리고 master랑 비슷한 코드를 만져서 컨플릭트가 날 가능성이 높다: 방법 1(내 브랜치에 먼저 머지 후 풀리퀘)을 사용한다.
  • Type 2. 내 브랜치에 커밋이 그리 많진 않다. 깔끔한 커밋 히스토리를 남기고 싶다(오픈소스 등): 방법 2(rebase)를 사용한다.