전체 목록
GitMedium#87

Git merge와 rebase의 차이점과 각각 어떤 상황에서 사용하면 좋은지 설명해주세요.

#Git#merge#rebase#협업
힌트

커밋 히스토리의 형태 차이를 생각해보세요.

정답 및 해설

Git merge와 rebase의 차이점과 각각 어떤 상황에서 사용하면 좋은지 설명해주세요.

Git에서 브랜치를 합치는 방법으로 mergerebase 두 가지가 있습니다. 둘 다 같은 목적(브랜치 통합)을 달성하지만, 히스토리를 다루는 방식이 완전히 다릅니다. 어떤 방법을 선택하느냐에 따라 프로젝트 커밋 히스토리의 모양과 가독성이 크게 달라집니다.

Merge란?

git merge는 두 브랜치의 변경 사항을 합쳐 새로운 merge commit을 생성합니다. 두 브랜치의 공통 조상(Base)을 찾고 3-way merge를 수행합니다.

기본 사용법

# feature 브랜치를 main에 병합
git checkout main
git merge feature/login

# 또는 --no-ff 옵션으로 fast-forward 방지 (항상 merge commit 생성)
git merge --no-ff feature/login

# squash merge: feature 브랜치의 커밋을 하나로 합쳐서 main에 적용
git merge --squash feature/login
git commit -m "feat: 로그인 기능 추가"

Merge 후 히스토리 모양

      A---B---C  feature
     /         \
D---E---F---G---H  main (H = merge commit)

merge commit(H)이 생성되어 두 브랜치가 합쳐진 지점이 명확하게 표시됩니다.

Fast-forward Merge

중간에 다른 커밋이 없는 경우, 별도의 merge commit 없이 포인터만 이동합니다.

Before:
D---E  main
     \
      A---B  feature

After (fast-forward):
D---E---A---B  main (포인터만 이동, merge commit 없음)
# fast-forward 강제 비활성화
git merge --no-ff feature

# fast-forward만 허용 (불가능하면 에러)
git merge --ff-only feature

Rebase란?

git rebase는 현재 브랜치의 커밋들을 다른 브랜치 위에 **재적용(re-apply)**합니다. 기존 커밋을 새로운 위치에 복사하여 선형(linear) 히스토리를 만듭니다.

기본 사용법

# feature 브랜치를 main 위에 rebase
git checkout feature/login
git rebase main

# rebase 중 충돌 발생 시
git rebase main
# ... 충돌 해결 후 ...
git add .
git rebase --continue

# rebase 취소
git rebase --abort

Rebase 후 히스토리 모양

Before:
      A---B---C  feature
     /
D---E---F---G  main

After rebase (feature를 main 위에 rebase):
              A'--B'--C'  feature
             /
D---E---F---G  main

A, B, C 커밋이 A', B', C'로 새로운 커밋 해시를 가진 복사본으로 재생성됩니다.

Interactive Rebase

git rebase -i는 커밋 히스토리를 직접 편집할 수 있는 강력한 도구입니다.

# 최근 3개 커밋 편집
git rebase -i HEAD~3

# 특정 커밋 이후 모두 편집
git rebase -i <commit-hash>

편집기에서 각 커밋에 명령어를 지정합니다:

pick a1b2c3 feat: 로그인 UI 추가
pick d4e5f6 fix: 오타 수정
pick g7h8i9 feat: 로그인 API 연동

# 명령어:
# pick   = 커밋 그대로 사용
# reword = 커밋 메시지 수정
# edit   = 커밋 내용 수정
# squash = 이전 커밋과 합치기 (메시지 합침)
# fixup  = 이전 커밋과 합치기 (메시지 버림)
# drop   = 커밋 삭제

커밋 squash 예시

# 3개의 WIP 커밋을 하나로 합치기
git rebase -i HEAD~3

# 편집기에서:
pick a1b2c3 feat: 로그인 기능 구현 시작
squash d4e5f6 WIP: 계속 작업 중
squash g7h8i9 WIP: 마무리
# → 하나의 깔끔한 커밋으로 합쳐짐

Merge vs Rebase 비교

항목MergeRebase
히스토리 모양비선형 (merge commit 존재)선형 (깔끔)
원본 커밋 보존O (커밋 해시 유지)X (새 해시 생성)
충돌 처리한 번 처리커밋마다 처리 가능
안전성높음 (히스토리 변경 없음)공유 브랜치에서는 위험
사용 목적협업 브랜치 통합로컬 브랜치 정리

황금 규칙: 공유 브랜치에 Rebase 금지

# ❌ 절대 하면 안 되는 것
git checkout main
git rebase feature  # main은 다른 사람과 공유 중!

# ❌ 이미 push한 브랜치를 rebase하면 안 됨
git push origin feature/login
git rebase main  # 위험! 커밋 해시가 바뀌어 다른 사람과 충돌
git push --force origin feature/login  # 더 위험!

rebase 후 force push를 하면 다른 팀원의 로컬 브랜치와 원격 브랜치 히스토리가 달라져 큰 혼란이 생깁니다.

언제 무엇을 사용할까?

Merge를 사용해야 할 때

# 1. PR(Pull Request) 병합 - 협업 브랜치에 기능 합치기
git checkout main
git merge --no-ff feature/login

# 2. 브랜치 병합 이력을 명확히 남기고 싶을 때
# 언제 어떤 기능이 합쳐졌는지 히스토리로 추적 가능

# 3. 이미 공유된 브랜치 통합
git merge develop  # main에 develop 반영

Rebase를 사용해야 할 때

# 1. 로컬 feature 브랜치를 최신 main에 맞출 때
git checkout feature/login
git rebase main  # main의 최신 변경사항을 feature에 반영

# 2. PR 전 커밋 정리 (squash, 메시지 수정)
git rebase -i HEAD~5

# 3. 선형 히스토리를 원할 때
# 히스토리가 깔끔해서 git log 읽기 쉬움

실제 워크플로우 예시

Git Flow에서의 활용

# feature 브랜치 작업 시작
git checkout -b feature/payment develop

# ... 작업 후 ...

# develop의 최신 변경사항을 feature에 반영 (rebase 사용)
git fetch origin
git rebase origin/develop

# 충돌 해결 후 PR 생성
git push origin feature/payment

# PR 승인 후 develop에 병합 (merge 사용, --no-ff)
# GitHub/GitLab에서 "Merge pull request" 클릭

커밋 정리 후 PR 제출

git checkout feature/login
# 여러 WIP 커밋이 있는 상태

# 커밋 정리
git rebase -i HEAD~4
# squash로 의미 있는 단위로 합치기

# 깔끔한 커밋으로 PR 제출
git push origin feature/login

정리

상황권장 방법이유
PR을 main/develop에 병합merge --no-ff병합 이력 보존, 롤백 쉬움
로컬 feature를 최신 main에 맞추기rebase선형 히스토리, 충돌 조기 해결
WIP 커밋 정리rebase -i깔끔한 PR 커밋 히스토리
이미 push된 공유 브랜치mergerebase는 히스토리 재작성으로 위험
hotfix를 여러 브랜치에 반영cherry-pick특정 커밋만 선택적 적용

핵심 원칙: "rebase는 로컬에서, merge는 공유 브랜치에서" 를 기억하면 됩니다.