← 블로그로 돌아가기

Git rebase vs merge: 언제 무엇을 사용할까

tutorial git

변경사항을 통합하는 두 가지 방법

Git branch로 작업할 때, 한 branch의 변경사항을 다른 branch로 가져와야 하는 시점이 옵니다. Git은 이를 위한 두 가지 주요 전략을 제공합니다: mergerebase. 둘 다 동일한 최종 결과를 달성합니다 -- branch에 모든 최신 변경사항이 포함됩니다 -- 하지만 근본적으로 다른 방식으로 수행하며, 올바른 것을 선택하는 것이 프로젝트의 이력과 팀의 workflow에 중요합니다.

Merge의 동작 방식

merge는 두 branch를 가져와 새로운 merge commit을 생성하여 결합합니다. 이 merge commit에는 두 개의 부모가 있습니다: 현재 branch의 끝과 통합하려는 branch의 끝입니다.

git checkout feature/login
git merge main

이후, 기능 branch에는 merge commit으로 연결된 main의 모든 변경사항이 포함됩니다. 두 branch의 이력은 실제 발생한 그대로 정확히 보존됩니다. commit 그래프를 보면 두 개발 라인이 merge 지점에서 수렴하는 것을 볼 수 있습니다.

merge의 주요 특성:

  • 비파괴적. 기존 commit이 변경되지 않습니다. 이력은 실제로 일어난 것 그대로입니다.
  • Merge commit을 생성. 이 추가 commit이 두 이력을 하나로 묶습니다.
  • 맥락을 보존. branch가 언제 생성되고 언제 다시 merge되었는지 항상 확인할 수 있습니다.

Fast-forward merge

branch가 대상에서 분기하지 않은 경우(branch를 생성한 이후 대상에 새로운 commit이 없는 경우), Git은 기본적으로 fast-forward merge를 수행합니다. 단순히 branch 포인터를 앞으로 이동시킵니다. 필요하지 않으므로 merge commit이 생성되지 않습니다. 이 경우에도 merge commit을 강제할 수 있습니다:

git merge --no-ff feature/login

merge가 사소한 것이더라도 작업이 별도의 branch에서 이루어졌다는 사실을 보존하고 싶을 때 유용합니다.

Rebase의 동작 방식

rebase는 다른 접근법을 취합니다. merge commit을 생성하는 대신, 다른 branch 위에 commit을 재적용합니다. 결과는 대상 branch의 최신 시점에서 작업을 시작한 것처럼 보이는 선형 이력입니다.

git checkout feature/login
git rebase main

내부에서 일어나는 일:

  • Git이 두 branch의 공통 조상을 찾습니다.
  • branch의 commit을 임시로 제거합니다.
  • branch 포인터를 main의 끝으로 이동합니다.
  • commit을 하나씩 그 위에 재적용합니다.

결과 이력은 완벽하게 선형입니다. merge commit 없이, 그래프에서 분기하고 수렴하는 선 없이. main의 최신 변경사항 이후에 모든 코드를 작성한 것처럼 보입니다. 실제로는 그렇지 않더라도.

rebase의 주요 특성:

  • 선형 이력을 생성. commit 그래프가 깔끔하고 읽기 쉽습니다.
  • Commit 해시를 재작성. 재적용된 commit은 내용이 동일하더라도 새로운 SHA 해시를 받습니다.
  • Merge commit 없음. branch가 추가 commit 없이 깔끔하게 통합됩니다.

Merge를 사용해야 할 때

merge는 여러 상황에서 더 안전하고 간단한 선택입니다:

  • 공유 branch. 여러 사람이 같은 branch에서 작업할 때, merge는 다른 사람이 의존하는 commit을 재작성하지 않고 모든 사람의 이력을 보존합니다.
  • 이력 보존이 중요할 때. 변경사항이 정확히 언제 어떻게 통합되었는지 추적해야 하는 프로젝트에서, merge는 완전하고 변경되지 않은 기록을 제공합니다.
  • 장기 branch 통합. 릴리스 branch를 main에 merge하거나, 크게 분기한 두 branch를 결합할 때, merge commit이 통합 지점을 명확하게 표시합니다.
  • 단순함을 원할 때. merge는 개념적으로 더 쉽습니다. 특히 Git을 처음 접하는 개발자에게 문제가 발생할 가능성이 적습니다.

Rebase를 사용해야 할 때

rebase는 깔끔하고 선형적인 프로젝트 이력을 원할 때 빛납니다:

  • 기능 branch 업데이트. 기능을 main에 merge하기 전에, 최신 main 위에 rebase하면 merge commit 없이 직접 적용할 수 있는 깔끔한 commit 세트를 얻을 수 있습니다.
  • 깔끔한 이력 유지. 선형 이력은 git log로 탐색하기 쉽고, 버그를 추적할 때 bisect하기 쉽고, pull request에서 리뷰하기 쉽습니다.
  • 로컬 정리. 작업하면서 작은 증분 commit을 만들었다면, branch를 공유하기 전에 rebase를 사용하여 정리할 수 있습니다.

Rebase의 황금률

공유 branch에 push된 commit은 절대 rebase하지 마세요.

이것은 기억해야 할 가장 중요한 규칙입니다. rebase는 commit 해시를 재작성하므로, 원래 commit을 기반으로 작업한 다른 사람들에게 문제가 발생합니다. 그들의 이력이 rebase된 이력과 더 이상 일치하지 않아 commit 중복, 충돌, 혼란이 발생합니다.

규칙은 간단합니다: 다른 사람이 여러분의 commit을 pull했을 수 있다면, rebase하지 마세요. 자신의 로컬 branch에서만, 또는 자신이 유일한 기여자인 branch에서만 rebase를 사용하세요.

실수로 공유 branch를 rebase한 경우, 팀의 다른 개발자들이 분기된 이력을 처리해야 합니다. 이는 일반적으로 force-push(원격을 덮어씀)와 다른 모든 사람이 로컬 복사본을 reset하는 것을 의미합니다. 혼란을 초래하며 피할 수 있는 상황입니다.

인터랙티브 Rebase: 정밀한 이력 재작성

인터랙티브 rebase(git rebase -i)는 단순한 commit 이동을 넘어섭니다. commit 이력 자체를 수정할 수 있습니다:

git rebase -i HEAD~5

최근 5개 commit의 목록이 열리며, 다음을 할 수 있습니다:

  • pick -- commit을 그대로 유지
  • reword -- commit 메시지 변경
  • edit -- commit을 수정하기 위해 일시 정지
  • squash -- 이전 commit과 결합
  • fixup -- squash와 같지만 commit 메시지 폐기
  • drop -- commit을 완전히 제거
  • reorder -- 줄을 재배열하여 순서 변경

인터랙티브 rebase는 merge 전에 지저분한 branch를 정리하는 데 강력합니다. "오타 수정" commit을 부모에 squash하고, 불명확한 메시지를 다시 작성하고, commit을 논리적인 스토리가 되도록 재배열할 수 있습니다.

실용적인 워크플로우

많은 팀이 두 전략의 장점을 결합한 접근법을 사용합니다:

  1. main에서 기능 branch를 생성합니다.
  2. 작업하면서 기능 branch를 main 위에 주기적으로 rebase하여 최신 상태를 유지합니다.
  3. Pull request를 열기 전에 인터랙티브 rebase를 사용하여 commit을 정리합니다.
  4. 기능 branch를 main에 merge합니다 (종종 통합 지점을 표시하기 위해 merge commit을 사용).

이를 통해 기능 branch에서는 깔끔하고 선형적인 이력을, main에서는 명확한 merge 지점을 얻을 수 있습니다. 대부분의 팀에 잘 맞는 실용적인 절충안입니다.

GitSquid에서의 Rebase와 Merge

GitSquid는 인터페이스에서 직접 merge와 rebase를 모두 지원합니다. commit 그래프의 branch 레이블에서 컨텍스트 메뉴를 통해 branch를 merge할 수 있습니다. rebase의 경우, GitSquid에는 터미널에서 텍스트 파일을 편집하는 대신 드래그 앤 클릭으로 commit을 재배열, squash, fixup, reword, drop할 수 있는 비주얼 인터랙티브 rebase 에디터가 포함되어 있습니다. 이를 통해 커맨드라인 버전이 어렵게 느껴지더라도 인터랙티브 rebase를 쉽게 사용할 수 있습니다.

요약

Merge Rebase
이력 비선형, branch 보존 선형, 깔끔
Commit 해시 변경 없음 재작성됨
Merge commit 예 (fast-forward 제외) 아니오
공유 branch에서 안전 아니오
최적 용도 공유 작업 통합 기능 branch 정리

merge도 rebase도 보편적으로 더 나은 것은 없습니다. 서로 다른 상황을 위한 도구입니다. 각각이 이력에 어떤 영향을 미치는지 이해하고, rebase의 황금률을 따르며, 상황에 맞는 것을 선택하세요. 미래의 자신이 git log를 읽을 때 감사할 것입니다.