09. 리베이스(Rebase)
- 리베이스가 무엇이고 병합과 어떻게 다른지 이해한다
- 리베이스로 이력을 깔끔하게 정리하는 법을 익힌다
- 리베이스 충돌을 해결하고 취소하는 법을 안다
- 리베이스의 황금률(공유된 커밋에 쓰지 말 것)을 반드시 기억한다
9.1 리베이스란?
병합(merge)이 두 갈래를 "합쳐서 새 커밋을 만드는" 것이라면, 리베이스(rebase)는 "내 브랜치의 출발점(base)을 옮겨 붙이는 것"입니다. 이름 그대로 re-base(기반을 다시 잡다)입니다.
리베이스 전 — feature는 C에서 갈라져 있고, main은 G까지 전진:
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
branch feature
checkout feature
commit id: "D"
commit id: "E"
checkout main
commit id: "F"
commit id: "G"
리베이스 후 — feature의 출발점이 C에서 G로 옮겨져, D·E가 G 뒤에 새 커밋(D'·E')으로 다시 쌓임:
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "F"
commit id: "G"
branch feature
checkout feature
commit id: "D'"
commit id: "E'"
feature의 커밋들(D, E)을 떼어내서, main의 최신 커밋(G) 뒤에 새 커밋(D', E')으로 다시 쌓습니다. 결과적으로 이력이 한 줄로 곧게 펴집니다.
9.2 리베이스 vs 병합 — 무엇이 다른가?
같은 두 브랜치를 합칠 때, 결과 이력의 모양이 다릅니다.
병합(merge)의 이력
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
branch feature
checkout feature
commit id: "D"
commit id: "E"
checkout main
commit id: "F"
commit id: "G"
merge feature id: "M"
- 갈라지고 합쳐진 실제 역사가 그대로 보존됩니다.
- 병합 커밋이 추가되어 이력이 "그물망"처럼 됩니다.
리베이스(rebase)의 이력
gitGraph
commit id: "A"
commit id: "B"
commit id: "C"
commit id: "F"
commit id: "G"
commit id: "D'"
commit id: "E'"
- 마치 처음부터 순서대로 작업한 것처럼 깔끔한 직선이 됩니다.
- 병합 커밋이 없습니다.
| 병합(merge) | 리베이스(rebase) | |
|---|---|---|
| 이력 모양 | 갈래가 보이는 그물망 | 곧은 직선 |
| 병합 커밋 | 생김 | 안 생김 |
| 원본 커밋 | 그대로 유지 | 새로 만들어짐(해시 변경) |
| 실제 역사 | 사실대로 보존 | 다시 쓰여짐 |
| 적합한 상황 | 협업 메인 브랜치 | 개인 브랜치 정리 |
9.3 리베이스 명령어와 실습
# feature 브랜치를 main 위로 다시 쌓기 git switch feature # 옮길 브랜치로 이동 git rebase main # main을 기준으로 재배치
Successfully rebased and updated refs/heads/feature.
이제 feature는 main의 최신 커밋 뒤에 자기 커밋들을 새로 쌓았습니다. 확인:
git log --oneline --graph
이후 main에서 feature를 병합하면 fast-forward로 깔끔하게 끝납니다.
git switch main git merge feature # 직선이므로 fast-forward
git rebase main은 "현재 브랜치를 main 위에 다시 쌓는다"는 뜻입니다. 그래서 옮기려는 브랜치(feature)로 먼저 이동한 뒤 실행합니다. (merge와 시작 위치가 반대라는 점에 주의!)9.4 리베이스 충돌 해결
리베이스도 커밋을 하나씩 다시 적용하는 과정이라, 같은 부분을 건드렸다면 충돌이 납니다. 다만 해결 흐름이 merge와 조금 다릅니다.
git rebase main
CONFLICT (content): Merge conflict in app.js error: could not apply a1b2c3d... Add feature
해결 절차:
# 1. 충돌 파일을 열어 <<< === >>> 를 정리 (merge와 동일) # 2. 해결한 파일을 add git add app.js # 3. 병합처럼 commit 하지 않는다! 대신 계속 진행: git rebase --continue # (이 커밋을 건너뛰고 싶으면) git rebase --skip # (도저히 안 되겠으면 통째로 취소) git rebase --abort
| 명령 | 의미 |
|---|---|
git rebase --continue | 충돌 해결 후 다음 커밋으로 진행 |
git rebase --skip | 현재 커밋을 건너뛰기 |
git rebase --abort | 리베이스 전체 취소(원상 복귀) |
git commit으로 마무리하지만, rebase 충돌은 git rebase --continue로 이어갑니다. 여러 커밋을 재적용하다 보면 충돌이 여러 번 날 수도 있으니, 그때마다 해결 → --continue를 반복합니다.막혔을 때 git rebase --abort는 언제나 안전한 탈출구입니다. 기억해두세요.
9.5 대화형 리베이스 — 커밋 수정·합치기
-i(interactive) 옵션을 쓰면 과거 커밋들을 정리할 수 있습니다. 지저분한 커밋 여러 개를 깔끔하게 다듬는 강력한 도구입니다.
# 최근 3개 커밋을 대화형으로 정리 git rebase -i HEAD~3
에디터가 열리고 다음과 같은 목록이 나옵니다.
pick a1b2c3d Add login form pick b2c3d4e Fix typo pick c3d4e5f Fix another typo
각 줄 앞의 pick을 다음 명령어로 바꿔 편집합니다.
| 명령 | 의미 |
|---|---|
pick | 커밋 그대로 사용 |
reword | 커밋 메시지만 수정 |
edit | 커밋 내용 수정 |
squash | 이전 커밋과 합치기(메시지 합침) |
fixup | 이전 커밋과 합치되 메시지 버림 |
drop | 커밋 삭제 |
예: 사소한 오타 수정 커밋 2개를 첫 커밋에 합치기
pick a1b2c3d Add login form fixup b2c3d4e Fix typo fixup c3d4e5f Fix another typo
저장하고 닫으면 3개 커밋이 1개로 깔끔하게 합쳐집니다. "Fix typo" 같은 잡음 커밋을 정리해 의미 있는 단위로 만들 수 있습니다.
9.6 리베이스의 황금률 ⚠️ (가장 중요!)
### 🚨 이미 공유한(push한) 커밋은 절대 리베이스하지 마라.
리베이스는 커밋을 새로 만듭니다(해시가 바뀝니다). 즉 원본 커밋을 버리고 다른 커밋으로 대체하는 것입니다.
내 컴퓨터에만 있는 커밋이라면 문제없습니다. 하지만 이미 원격에 push해서 동료가 그 커밋을 받아간 상태라면 재앙이 됩니다.
나: (X) 커밋을 리베이스 → (X') 새 커밋으로 교체
동료: 여전히 옛날 (X) 커밋을 기준으로 작업 중
↓
역사가 어긋나 충돌과 중복 커밋이 대량 발생! 😱
정리하면
| 상황 | 리베이스 사용 |
|---|---|
| 내 로컬에만 있는 커밋 | ✅ 마음껏 정리 OK |
| 이미 push한 개인 브랜치 (혼자만 사용) | ⚠️ 가능하나 force push 필요, 주의 |
| 여러 명이 공유하는 브랜치(main 등) | ❌ 절대 금지 |
부득이하게 push한 개인 브랜치를 리베이스했다면, 일반 push는 거부되고 강제 push가 필요합니다. 이때도 안전한 옵션을 쓰세요.
git push --force-with-lease # 그냥 --force보다 안전 (남의 작업 덮어쓰기 방지)
9.7 이 장에서 배운 것 (요약)
- 리베이스 = 브랜치의 출발점(base)을 옮겨 이력을 직선으로 정리
- merge는 역사 보존(그물망), rebase는 역사 정리(직선)
git switch feature→git rebase main(옮길 브랜치에서 실행)- 충돌 시: 해결 →
git add→git rebase --continue(commit 아님!) - 탈출구:
git rebase --abort git rebase -i로 커밋 합치기(squash/fixup)·메시지 수정(reword)- 황금률: 공유한(push한) 커밋은 리베이스 금지 — 어쩔 수 없으면
--force-with-lease
✍️ 확인 문제
- merge와 rebase의 이력 모양은 각각 어떻게 다른가요?
- 리베이스 충돌을 해결한 뒤 입력하는 명령은 (
git commit이 아니라) 무엇인가요? - 리베이스를 절대 하면 안 되는 상황은?
다음 장에서는 커밋을 되돌리는 두 가지 방법, 리셋(Reset)과 리버트(Revert)를 배웁니다. → 10_리셋과리버트.md