포스트

[GitHub 100일 챌린지] Day 49 - Rebase 이해하기

[GitHub 100일 챌린지] Day 49 - Rebase 이해하기

100일 챌린지 Day 49 - Git Rebase로 깔끔한 커밋 히스토리를 만드는 방법을 배웁니다.

배울 내용

  1. Rebase란
  2. Rebase 실습
  3. Merge vs Rebase

Topic1. Rebase란

커밋 히스토리를 재작성하여 선형으로 만드는 방법입니다.

Rebase의 개념

Merge와의 차이:

gitGraph
    commit id: "C1"
    commit id: "C2"
    branch feature
    checkout feature
    commit id: "C3"
    checkout main
    commit id: "C4"

Merge 결과:

gitGraph
    commit id: "C1"
    commit id: "C2"
    branch feature
    checkout feature
    commit id: "C3"
    checkout main
    commit id: "C4"
    merge feature tag: "M (Merge Commit)"

Rebase 결과:

gitGraph
    commit id: "C1"
    commit id: "C2"
    commit id: "C4 (main)"
    commit id: "C3' (feature rebased)"

히스토리 비교:

1
2
3
4
5
6
7
8
9
10
11
Merge:
C1 ← C2 ← C4 ← M
      ↑         ↗
      └─ C3 ──┘
→ 병합 커밋 M 생성
→ 히스토리 분기됨

Rebase:
C1 ← C2 ← C4 ← C3'
→ C3를 C4 뒤로 이동
→ 선형 히스토리

Rebase의 원리

Rebase가 하는 일:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 상황: feature 브랜치를 main에 rebase
git checkout feature
git rebase main

# Git의 내부 동작:
1. feature의 커밋들을 임시 저장 (C3)
2. feature를 main의 최신 커밋으로 이동 (C4)
3. 저장한 커밋들을 하나씩 재적용 (C3')

# 결과:
C1 ← C2 ← C4 ← C3'
              ↑
            feature

커밋이 재작성되는 과정:

1
2
3
4
5
6
7
8
9
10
11
원본 커밋 C3:
- 부모: C2
- 변경사항: add feature.js
- SHA: abc123

Rebase 후 C3':
- 부모: C4 (변경!)
- 변경사항: add feature.js (동일)
- SHA: def456 (변경!)

⚠️ SHA가 달라짐 = 새로운 커밋!

해보기: Rebase 상황 만들기

시나리오: main이 앞서 나간 상황

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 프로젝트 초기화
mkdir rebase-demo
cd rebase-demo
git init

# 초기 커밋
echo "v1.0" > VERSION
git add VERSION
git commit -m "C1: Initial version"

echo "# App" > README.md
git add README.md
git commit -m "C2: Add README"

# feature 브랜치 생성
git checkout -b feature/new-ui

# feature에서 작업
echo "UI code" > ui.js
git add ui.js
git commit -m "C3: Add new UI"

# main으로 돌아가서 작업 (main이 앞서감)
git checkout main

echo "v1.1" > VERSION
git add VERSION
git commit -m "C4: Bump version to 1.1"

# 히스토리 확인
git log --oneline --all --graph

# 출력:
* C4 (HEAD -> main) Bump version to 1.1
| * C3 (feature/new-ui) Add new UI
|/
* C2 Add README
* C1 Initial version

# feature가 main보다 뒤처짐!

결과

Rebase가 필요한 상황:

1
2
3
✅ feature 브랜치가 main보다 뒤처짐
✅ main의 최신 변경사항 필요
✅ 깔끔한 선형 히스토리 원함

언제 사용하나?:

1
2
3
4
5
6
7
8
9
10
개인 브랜치:
✅ 아직 push 안 함
✅ 나만 사용하는 브랜치
→ Rebase 사용 OK!

공유 브랜치:
❌ 이미 push 함
❌ 다른 사람이 사용 중
→ Rebase 사용 위험!
→ Merge 사용 권장

Topic2. Rebase 실습

실제로 Rebase를 수행해봅니다.

기본 Rebase

Rebase 명령어:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# feature 브랜치로 전환
git checkout feature/new-ui

# main을 기준으로 rebase
git rebase main

# 출력:
Successfully rebased and updated refs/heads/feature/new-ui.

# 히스토리 확인
git log --oneline --graph

# 출력:
* C3' (HEAD -> feature/new-ui) Add new UI
* C4 (main) Bump version to 1.1
* C2 Add README
* C1 Initial version

# 선형 히스토리!

변경사항 확인:

1
2
3
4
5
6
7
8
# Rebase 전 C3의 SHA
# abc123def

# Rebase 후 C3'의 SHA
git log --oneline -1
# def456abc

# SHA가 바뀜 = 새로운 커밋!

Interactive Rebase

커밋을 수정하며 Rebase:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 대화형 rebase
git rebase -i main

# 에디터가 열림:
pick C3 Add new UI
pick C5 Fix typo
pick C6 Update docs

# Commands:
# p, pick = 커밋 사용
# r, reword = 커밋 메시지 수정
# e, edit = 커밋 수정
# s, squash = 이전 커밋과 합치기
# f, fixup = squash와 동일, 메시지 버림
# d, drop = 커밋 삭제

커밋 합치기 (Squash):

1
2
3
4
5
6
7
8
9
10
# 여러 작은 커밋을 하나로
git rebase -i main

# 에디터에서:
pick C3 Add new UI
squash C5 Fix typo
squash C6 Update docs

# 저장하면 C3, C5, C6이 하나로 합쳐짐
# 새 커밋 메시지 작성 가능

해보기: 실전 Rebase 워크플로우

시나리오: PR 전 깔끔하게 정리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# === 초기 설정 ===
mkdir pr-rebase
cd pr-rebase
git init

echo "# Project" > README.md
git add README.md
git commit -m "Initial commit"

# main에 새 변경사항
git checkout -b feature/login

# === feature에서 지저분하게 작업 ===
echo "login form" > login.html
git add login.html
git commit -m "WIP: start login"

echo "add validation" >> login.html
git add login.html
git commit -m "add validation"

echo "fix typo" >> login.html
git add login.html
git commit -m "fix typo"

echo "add style" >> login.css
git add login.css
git commit -m "add css"

# === main에 핫픽스 ===
git checkout main
echo "v1.0.1" > VERSION
git add VERSION
git commit -m "hotfix: Bump version"

# === 히스토리 확인 ===
git checkout feature/login
git log --oneline --graph

# 출력:
* L4 add css
* L3 fix typo
* L2 add validation
* L1 WIP: start login
* I1 Initial commit

# 지저분한 히스토리!

# === Interactive Rebase로 정리 ===
git rebase -i main

# 에디터:
pick L1 WIP: start login
squash L2 add validation
squash L3 fix typo
pick L4 add css

# 저장 후 커밋 메시지 작성:
feat: Add login form with validation

- Implement login HTML form
- Add client-side validation
- Include CSS styling

# === 결과 확인 ===
git log --oneline --graph

# 출력:
* N2 (HEAD -> feature/login) add css
* N1 feat: Add login form with validation
* H1 (main) hotfix: Bump version
* I1 Initial commit

# 깔끔한 히스토리!

Rebase 충돌 해결

충돌 발생 시:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
git rebase main

# 출력:
CONFLICT (content): Merge conflict in login.html
error: could not apply L1... Add login form
hint: Resolve all conflicts manually
hint: After resolving, mark with "git add/rm <conflicted_files>"
hint: then run "git rebase --continue"

# 충돌 해결
vim login.html
# (Conflict Marker 제거)

git add login.html

# Rebase 계속
git rebase --continue

# 또는 취소
git rebase --abort

결과

Rebase 장점:

1
2
3
4
✅ 선형 히스토리 (읽기 쉬움)
✅ 깔끔한 커밋 로그
✅ PR 리뷰 쉬워짐
✅ Bisect 사용 용이

Rebase 주의사항:

1
2
3
4
⚠️ 커밋 SHA 변경됨
⚠️ 히스토리 재작성
⚠️ Push한 커밋은 rebase 금지
⚠️ 공유 브랜치는 위험

Topic3. Merge vs Rebase

두 방식의 차이와 선택 기준입니다.

Merge의 특징

Merge 동작:

1
2
3
4
5
6
7
git checkout main
git merge feature

# 결과:
C1 ← C2 ← C4 ← M
      ↑         ↗
      └─ C3 ──┘

Merge 장점:

1
2
3
4
5
✅ 히스토리 보존
✅ 작업 흐름 명확
✅ 안전함 (히스토리 변경 없음)
✅ 브랜치 작업 추적 가능
✅ 충돌 한 번만 해결

Merge 단점:

1
2
3
4
❌ 히스토리 복잡해짐
❌ 병합 커밋 많아짐
❌ 그래프 지저분
❌ Bisect 사용 어려움

Rebase의 특징

Rebase 동작:

1
2
3
4
5
git checkout feature
git rebase main

# 결과:
C1 ← C2 ← C4 ← C3'

Rebase 장점:

1
2
3
4
5
✅ 선형 히스토리
✅ 깔끔한 로그
✅ 읽기 쉬움
✅ Bisect 사용 쉬움
✅ PR 리뷰 편함

Rebase 단점:

1
2
3
4
5
❌ 히스토리 재작성
❌ 위험함 (잘못 사용 시)
❌ 충돌 여러 번 해결 가능
❌ Push 강제 필요 (force push)
❌ 공유 브랜치 위험

선택 기준

Merge를 사용하는 경우:

1
2
3
4
5
6
7
8
9
✅ 공유 브랜치 (main, develop)
✅ 공개 브랜치 (이미 push됨)
✅ 히스토리 보존 중요
✅ 팀 협업 브랜치
✅ 릴리스 브랜치

예시:
git checkout main
git merge feature/login --no-ff

Rebase를 사용하는 경우:

1
2
3
4
5
6
7
8
9
✅ 개인 브랜치 (아직 push 안함)
✅ 로컬 작업만
✅ PR 전 정리
✅ 깔끔한 히스토리 원함
✅ 작은 feature 브랜치

예시:
git checkout feature/my-work
git rebase main

해보기: 워크플로우 비교

Merge 워크플로우:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Feature 개발
git checkout -b feature/payment
# ... 작업 ...
git commit -m "Add payment"

# main에 병합
git checkout main
git merge feature/payment

# 히스토리:
*   M (main) Merge branch 'feature/payment'
|\
| * P (feature/payment) Add payment
* | H Hotfix
|/
* I Initial

# 브랜치 작업 명확히 보임

Rebase 워크플로우:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Feature 개발
git checkout -b feature/payment
# ... 작업 ...
git commit -m "Add payment"

# main 최신화 후 rebase
git checkout main
git pull

git checkout feature/payment
git rebase main

# main에 Fast-Forward 병합
git checkout main
git merge feature/payment

# 히스토리:
* P (HEAD -> main, feature/payment) Add payment
* H Hotfix
* I Initial

# 선형 히스토리

Golden Rule

절대 규칙:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❌ 절대 금지:
push한 공개 브랜치를 rebase하지 마세요!

git checkout main
git rebase feature  # ❌ 위험!

이유:
- 다른 사람이 사용 중일 수 있음
- SHA가 바뀌면 협업 깨짐
- Force push 필요
- 충돌과 혼란 발생

✅ 안전한 사용:
git checkout feature  # 개인 브랜치
git rebase main       # ✅ 안전!

팀 규칙 예시

실무 가이드라인:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. Main/Develop 브랜치
   → Merge만 사용
   → --no-ff 옵션 권장
   → 히스토리 보존

2. Feature 브랜치
   → PR 전: Rebase 사용 (정리)
   → PR 병합: Squash Merge

3. 개인 작업 브랜치
   → Rebase 자유롭게 사용
   → Push 전에만 사용

4. Hotfix 브랜치
   → Merge 사용
   → 빠른 병합 우선

결과

Merge vs Rebase 요약:

1
2
3
4
5
6
7
8
9
10
11
12
Merge:
- 안전하고 보수적
- 히스토리 보존
- 공유 브랜치에 적합

Rebase:
- 깔끔하고 공격적
- 히스토리 재작성
- 개인 브랜치에 적합

황금률:
"공개/공유 브랜치는 절대 rebase 금지!"

정리

오늘 배운 내용:

1. Rebase 개념:

  • 커밋을 다른 base로 이동
  • 선형 히스토리 생성
  • 커밋 SHA 변경됨

2. Rebase 사용법:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 기본 rebase
git checkout feature
git rebase main

# Interactive rebase
git rebase -i main

# 충돌 해결
git add <file>
git rebase --continue

# 취소
git rebase --abort

3. Merge vs Rebase:

1
2
3
4
Merge: 안전, 히스토리 보존, 공유 브랜치
Rebase: 깔끔, 히스토리 재작성, 개인 브랜치

황금률: 공개 브랜치 rebase 금지!

4. 실무 사용:

  • PR 전: Interactive rebase로 정리
  • 개인 브랜치: 자유롭게 rebase
  • 공유 브랜치: Merge만 사용

다음 단계: Day 50에서 Git Flow를 배웁니다.

완료 체크:

  • Rebase의 개념을 이해했다
  • Rebase를 수행할 수 있다
  • Merge와 Rebase의 차이를 안다
  • 언제 Rebase를 사용할지 안다
  • Rebase의 위험성을 이해했다

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.