GitHub의 Merge, Squash and Merge, Rebase and Merge 정확히 이해하기

등록일 2017.08.10 조회수 33487

Git-Logo-2Color.png

GitHub의 새 버전에서 merge, squash and merge, rebase and merge 세 종류의 merge를 모두 지원하기 시작했습니다. 각 머지 방식에 따라 커밋 히스토리가 천차만별로 달라지는데요, 어떤 경우에 어떤 머지를 사용하는 것이 좋은지 공유하고자 각 머지에 대해 설명해 드리려고 합니다.

Screen Shot 2017-05-29 at 10.59.17 AM.png

그래프로

각 머지를 그래프로 표현하면 아래와 같습니다.

  • Merge (a, b, c 를 refer 하는 m 커밋 노드 생성, m은 parent로 Init, c 를 가짐)

Screen Shot 2017-05-29 at 12.15.48 PM.png

  • Squash and Merge (a, b, c 를 합쳐서 새로운 커밋으로 만들고, 머지 대상 브렌치에 추가, 'a,b,c' 커밋은 parent를 Init 하나만 가짐.)

Screen Shot 2017-05-29 at 12.15.51 PM.png

  • Rebase and Merge (a, b, c 를 심리스하게 머지 대상 브렌치로 추가, 각 커밋들은 모두 parent를 하나씩만 가짐.)

Screen Shot 2017-05-29 at 12.15.55 PM.png

메인 브렌치의 관점에서

메인 브렌치의 커밋을 통해 머지된 커밋들이 어떤 형상을 가진지 비교해보면 아래와 같습니다.

  • Merge : 커밋 m에서부터 뒤로 되돌아가면서 부모를 모두 찾아 브렌치를 구성. 커밋 m은 부모로 c, Init을 가지고 있으며, c는 b, b는 a, a는 Init을 다시 부모로 가짐. 이 형상을 모두 backtrace 하여, Init -> a -> b -> c -> m이라는 구조를 만들고 이 구조가 모두 히스토리에 남음.

Screen Shot 2017-05-29 at 11.51.45 AM.png

  • Squash and Merge : 커밋 'a,b,c' 는 Init만을 부모로 가진 단일 커밋. 작업했던 브렌치의 a, b, c 커밋들은 머지 후의 메인 브렌치 커밋 Init, 'a,b,c' 와 아무런 연관을 가지지 않음.

Screen Shot 2017-05-29 at 11.51.54 AM.png

  • Rebase and Merge : 커밋 a, b, c 의 관계를 그대로 유지한 채, 메인 브렌치에 그대로 추가. 커밋 a는 부모로 커밋 e를 가짐. Rebase and Merge 작업 후에는, 작업했던 브렌치의 a, b, c 커밋들은 머지 후의 메인 브렌치의 Init, d, e, a, b, c 커밋들과 연관 관계를 가지지 않음.

Screen Shot 2017-05-29 at 11.52.08 AM.png

사용 예시

Git Flow 를 따른다고 했을 때, 아래와 같이 정리할 수 있습니다.

  • develop - feature 브렌치간 머지 : Squash and Merge가 유용합니다. feature의 복잡하고 지저분한 커밋 히스토리를 모두 묶어 완전 새로운 커밋으로 develop 브렌치에 추가하여, develop 브렌치에서 독자적으로 관리할 수 있기 때문입니다. 일반적으로 머지 후에 feature 브렌치를 삭제해버리는 점을 떠올려 보면, feature 브렌치의 커밋 히스토리를 모두 develop 브렌치에 직접 연관 지어 남길 필요가 없습니다.

  • master - develop 브렌치간 머지 : Rebase and Merge가 유용합니다. develop의 내용을 master에 추가할 때에는 별도의 새로운 커밋을 생성할 이유가 없기 때문입니다.

  • hotfix - develop, hotfix - master 브렌치간 머지 : Merge 또는 Squash and Merge 모두 유용합니다. 때에 따라 골라 사용하면 좋을 것 같습니다. hotfix 브렌치 작업의 각 커밋 히스토리가 모두 남아야 하는 경우 Merge, 필요 없는 경우 Squash and Merge를 사용하면 됩니다.

보너스

두 브렌치간 Rebase는 위와 같은 관점으로 사용할 수 있지만, cli의 interactive rebase (ex, git rebase -i HEAD~5)를 사용하면 단일 브렌치 내에서 rebase를 사용하여 커밋 히스토리를 정리할 수 있습니다.

  • reword 키워드를 사용하면 커밋 메시지를 변경할 수 있습니다.
  • squash 키워드를 사용하면 여러 커밋을 하나로 묶을 수 있습니다.

예를 들어, 아래와 같이 cli에서 작업 대상 브렌치에서 git rebase -i HEAD~5를 입력하고, 아래처럼 reword, squash를 적절히 사용하면,

Screen Shot 2017-05-29 at 12.34.53 PM.png

그래프로 표현하면 아래와 같습니다.

Screen Shot 2017-05-29 at 12.31.06 PM.png

기존의 커밋 히스토리인 아래 히스토리가

Screen Shot 2017-05-29 at 12.35.41 PM.png

아래처럼 변경됩니다. (reword, squash 모두 커밋 메시지를 임의로 변경할 수 있습니다. 자세히 적진 않았지만, 아래 reword, squash 작업 후의 커밋 메시지들은 모두 제가 임의로 작성한 것입니다.)

Screen Shot 2017-05-29 at 12.35.49 PM.png

즉, rebase를 다른 브렌치 간의 머지하는 용도 이외에도, 단일 브렌치를 정리하는데에도 사용할 수 있습니다.

작성자

  • 김솔 데이터인프라개발팀

    안녕하세요 개발자입니다. 취미 시간에도 개발합니다.

"404" 존재하지 않는 페이지 입니다.