rebase와 merge 논쟁은 Git 워크플로에서 가장 흔한 논의 중 하나입니다. 두 명령 모두 한 브랜치의 변경사항을 다른 브랜치에 통합하지만, 근본적으로 다른 방식으로 수행합니다. 각각을 언제 사용하는지 이해하는 것이 깨끗한 프로젝트 히스토리 유지에 중요합니다.
Git Merge 작동 방식
Git merge는 두 브랜치의 히스토리를 연결하는 새로운 "머지 커밋"을 생성합니다.
git merge feature를 실행하면, Git이 공통 조상을 찾고 두 변경사항을 합친 새 커밋을 만듭니다.
A---B---C feature
/ \
D---E---F---G---H main (merge commit)
$ git checkout main
$ git merge featureGit Rebase 작동 방식
Git rebase는 커밋을 다른 브랜치 위로 이동("리플레이")합니다. 커밋 히스토리를 다시 써서 선형 시퀀스를 만듭니다.
feature 브랜치에서 git rebase main을 실행하면, Git이 각 커밋을 일시적으로 제거하고, main 최신으로 업데이트한 후, 커밋을 하나씩 위에 다시 적용합니다.
Before rebase:
A---B---C feature
/
D---E---F---G main
After rebase:
A'--B'--C' feature
/
D---E---F---G main
$ git checkout feature
$ git rebase main시각적 비교
╔═══════════════════════════════════════════╗
║ MERGE RESULT ║
║ ║
║ D---E---F---G---H main ║
║ \ / ║
║ A---B---C feature ║
║ ║
║ ✓ Preserves all commits ║
║ ✓ Shows merge point ║
║ ✗ Non-linear history ║
╚═══════════════════════════════════════════╝
╔═══════════════════════════════════════════╗
║ REBASE RESULT ║
║ ║
║ D---E---F---G---A'--B'--C' main ║
║ ║
║ ✓ Clean linear history ║
║ ✓ Easy to read ║
║ ✗ Rewrites commit hashes ║
╚═══════════════════════════════════════════╝Merge를 사용할 때
- 공개/공유 브랜치 — Merge는 히스토리를 다시 쓰지 않아 안전합니다.
- 컨텍스트 보존 — 머지 커밋이 통합 시점을 보여줍니다.
- 팀 협업 — 여러 사람이 같은 브랜치에서 작업할 때.
- 릴리스 브랜치 — 정확한 통합 지점을 보존합니다.
# Merge with merge commit (recommended for main)
$ git checkout main
$ git merge --no-ff feature
$ git push origin mainRebase를 사용할 때
- Feature 브랜치 (main에 머지 전) — 깨끗한 선형 히스토리를 만듭니다.
- 최신 상태 유지 — 머지 커밋 없이 새 변경사항을 가져옵니다.
- PR 제출 전 — 리베이스된 깨끗한 커밋은 리뷰하기 쉽습니다.
- 로컬 커밋 정리 — 인터랙티브 리베이스로 스쿼시, 재정렬, 편집.
# Update feature branch with latest main
$ git checkout feature
$ git rebase main
# If conflicts occur, resolve them, then:
$ git add .
$ git rebase --continue인터랙티브 Rebase: squash, fixup, 재정렬
인터랙티브 rebase(git rebase -i)는 Git에서 가장 강력한 기능 중 하나입니다.
$ git rebase -i HEAD~4
# Editor opens:
pick a1b2c3d Add user authentication
pick e4f5g6h Fix typo in auth
pick i7j8k9l Add password validation
pick m0n1o2p Fix lint error
# Change to:
pick a1b2c3d Add user authentication
fixup e4f5g6h Fix typo in auth # merge into previous, discard message
pick i7j8k9l Add password validation
fixup m0n1o2p Fix lint error # merge into previous, discard message
# Result: 2 clean commits instead of 4
# Commands:
# pick = use commit as-is
# squash = merge into previous commit, keep message
# fixup = merge into previous commit, discard message
# reword = use commit but edit message
# drop = remove commit entirely황금 규칙: 공개 브랜치는 절대 Rebase하지 마세요
푸시되었고 다른 사람이 사용 중인 브랜치는 rebase하면 안 됩니다.
황금 규칙: 공유 리모트에 푸시되지 않은 커밋, 또는 자신만 작업하는 브랜치만 rebase하세요.
# ❌ DANGEROUS: Rebasing a shared branch
$ git checkout main
$ git rebase feature # NEVER do this!
# ✅ SAFE: Rebasing your own feature branch
$ git checkout my-feature # only I work on this
$ git rebase main # safe!
$ git push --force-with-lease origin my-featureMerge vs Rebase: 완전 비교
| 기준 | Merge | Rebase |
|---|---|---|
| History | Non-linear, preserves branches | Linear, clean |
| Commit hashes | Preserved | Changed (new hashes) |
| Conflict resolution | Once (in merge commit) | Per commit (may resolve multiple times) |
| Traceability | High (merge commit shows context) | Medium (linear but no branch info) |
| Safety | Safe (no history rewrite) | Risky (rewrites history) |
| For shared branches | ✅ | ❌ |
| For personal branches | ✅ | ✅ |
| Reversibility | Easy (git revert) | Harder (requires reflog) |
| git bisect | Harder (non-linear) | Easier (linear history) |
일반적인 Git 워크플로
Feature Branch 워크플로
feature 브랜치 생성 → 개발 → main에 rebase → --no-ff로 머지.
$ git checkout -b feature/login
# ... develop ...
$ git rebase main # clean up history
$ git checkout main
$ git merge --no-ff feature/login # merge with commit
$ git branch -d feature/loginGitflow 워크플로
develop, feature, release, hotfix 브랜치 사용. 장기 브랜치 간에는 항상 merge.
# Always merge between long-lived branches
$ git checkout develop
$ git merge --no-ff feature/login
$ git checkout release/1.0
$ git merge --no-ff develop
$ git checkout main
$ git merge --no-ff release/1.0
$ git tag v1.0트렁크 기반 개발
짧은 수명의 feature 브랜치 (1일 미만). 자주 rebase, 빠르게 머지.
# Short-lived branch, rebase often
$ git checkout -b fix/typo
# ... quick fix ...
$ git rebase main
$ git checkout main
$ git merge fix/typo # fast-forward
$ git push위험한 시나리오
| 시나리오 | 위험 | 예방 |
|---|---|---|
| Rebase main/master | Everyone's history breaks | Never rebase main |
| Rebase shared feature branch | Collaborators face divergent history | Use merge for shared branches |
| git push --force | Overwrites remote changes | Use --force-with-lease instead |
| Wrong conflict resolution during rebase | Code loss or corruption | Review each conflict, use git rebase --abort to restart |
| Rebase branch with merge commits | Merge commits flattened, confusing | Use --rebase-merges or avoid |
자주 묻는 질문
rebase를 되돌릴 수 있나요?
네. git reflog으로 rebase 전 커밋 해시를 찾고 git reset --hard로 복원할 수 있습니다.
feature 브랜치 업데이트 시 rebase? merge?
혼자 작업하는 브랜치라면 rebase. 다른 사람도 사용 중이라면 merge.
git pull --rebase란?
머지 커밋 없이 로컬 커밋을 리모트 변경 위에 리플레이합니다.
푸시된 브랜치를 rebase하면?
force push가 필요합니다. 이전 커밋을 받은 사람은 문제가 생깁니다.
squash merge와 rebase + squash는 같은가요?
결과는 비슷하지만 메커니즘이 다릅니다.
오픈소스 기여에는 어떤 것이 좋나요?
대부분의 오픈소스 프로젝트는 리베이스된 깨끗한 커밋을 선호합니다.