[GitHub 100일 챌린지] Day 46 - Fast-Forward Merge
[GitHub 100일 챌린지] Day 46 - Fast-Forward Merge
100일 챌린지 Day 46 - 가장 간단한 브랜치 병합 방식인 Fast-Forward를 배웁니다.
배울 내용
- Fast-Forward 병합이란
- Fast-Forward 병합 실습
- Fast-Forward vs 일반 병합
Topic1. Fast-Forward 병합이란
Fast-Forward는 가장 단순한 형태의 브랜치 병합입니다.
Fast-Forward의 개념
“빨리 감기” 병합:
gitGraph
commit id: "C1"
commit id: "C2"
branch feature
checkout feature
commit id: "C3"
commit id: "C4"
checkout main
merge feature tag: "Fast-Forward!"
작동 원리:
1
2
3
4
5
6
병합 전:
main → C2
feature → C2 → C3 → C4
병합 후:
main → C2 → C3 → C4 (feature와 동일!)
Fast-Forward가 가능한 조건:
- main 브랜치에 새로운 커밋이 없음
- feature 브랜치가 main보다 앞서 있음
- 일직선상에 커밋이 쌓여 있음
Fast-Forward vs 병합 커밋
Fast-Forward (빨리 감기):
1
2
3
4
5
6
7
8
C1 ← C2 ← C3 ← C4
↑ ↑
main feature
병합 후:
C1 ← C2 ← C3 ← C4
↑
main, feature
일반 병합 (Merge Commit):
1
2
3
4
5
C3 ← C4
↗ ↘
C1 ← C2 M (병합 커밋)
↑ ↑
main merged
해보기: Fast-Forward 조건 확인
시나리오: Fast-Forward가 가능한 상황
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
# 프로젝트 초기화
mkdir ff-merge-demo
cd ff-merge-demo
git init
# 초기 커밋
echo "# Project" > README.md
git add README.md
git commit -m "C1: Initial commit"
echo "v1.0" > VERSION
git add VERSION
git commit -m "C2: Add version file"
# 현재 main의 위치 확인
git log --oneline
# C2 Add version file
# C1 Initial commit
# feature 브랜치 생성
git checkout -b feature/add-docs
# feature에서 작업
echo "# Documentation" > DOCS.md
git add DOCS.md
git commit -m "C3: Add documentation"
echo "# More docs" >> DOCS.md
git add DOCS.md
git commit -m "C4: Update documentation"
# 브랜치 상태 확인
git log --oneline --all --graph
# 출력:
* C4 (HEAD -> feature/add-docs) Update documentation
* C3 Add documentation
* C2 (main) Add version file
* C1 Initial commit
# main은 C2에 머물러 있음!
# feature는 C2 → C3 → C4로 일직선!
# ✅ Fast-Forward 가능!
결과
Fast-Forward 가능 조건 확인:
1
2
3
4
✅ main이 C2에 머물러 있음
✅ feature가 main의 연장선상
✅ 일직선 히스토리
✅ 충돌 없음
Fast-Forward 불가능 상황:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# main에서 새 작업 발생
git checkout main
echo "hotfix" > FIX.md
git add FIX.md
git commit -m "C5: Hotfix on main"
# 이제 구조:
# C3 ← C4 (feature)
# ↗
# C2
# ↘
# C5 (main)
# ❌ Fast-Forward 불가! (main이 움직였음)
Topic2. Fast-Forward 병합 실습
실제로 Fast-Forward 병합을 수행해봅니다.
기본 Fast-Forward 병합
병합 명령어:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# main으로 전환
git checkout main
# feature 브랜치 병합
git merge feature/add-docs
# 출력:
Updating C2..C4
Fast-forward
DOCS.md | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 DOCS.md
# "Fast-forward" 메시지 확인!
병합 후 상태:
1
2
3
4
5
6
7
8
9
10
# 히스토리 확인
git log --oneline
# 출력:
C4 (HEAD -> main, feature/add-docs) Update documentation
C3 Add documentation
C2 Add version file
C1 Initial commit
# main과 feature가 같은 커밋을 가리킴!
그래픽으로 확인:
1
2
3
4
5
6
7
8
9
git log --oneline --all --graph
# 출력:
* C4 (HEAD -> main, feature/add-docs) Update documentation
* C3 Add documentation
* C2 Add version file
* C1 Initial commit
# 일직선 히스토리!
Fast-Forward 병합 과정
단계별 이해:
1단계: 병합 전:
1
2
main → C2
feature → C2 → C3 → C4
2단계: git merge 실행:
1
2
git checkout main
git merge feature/add-docs
3단계: main 포인터만 이동:
1
main → C2 → C3 → C4 ← feature
4단계: 완료:
1
main, feature → C2 → C3 → C4
해보기: 완전한 Fast-Forward 워크플로우
실무 시나리오: 새 기능 개발 및 병합
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# === 초기 설정 ===
mkdir login-feature
cd login-feature
git init
echo "# MyApp v1.0" > README.md
git add README.md
git commit -m "Initial release"
# === 기능 브랜치 생성 ===
git checkout -b feature/login
# === 로그인 기능 개발 ===
# 커밋 1: HTML
cat > login.html << 'EOF'
<!DOCTYPE html>
<html>
<body>
<form id="loginForm">
<input type="email" name="email" placeholder="Email">
<input type="password" name="password" placeholder="Password">
<button type="submit">Login</button>
</form>
</body>
</html>
EOF
git add login.html
git commit -m "feat: Add login HTML form"
# 커밋 2: JavaScript
cat > login.js << 'EOF'
async function handleLogin(email, password) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
return response.json();
}
EOF
git add login.js
git commit -m "feat: Add login JavaScript logic"
# 커밋 3: CSS
cat > login.css << 'EOF'
#loginForm {
max-width: 400px;
margin: 50px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
EOF
git add login.css
git commit -m "style: Add login form styles"
# === 병합 전 확인 ===
# main 상태 확인
git checkout main
git log --oneline
# 출력:
# a1b2c3d Initial release
# feature 상태 확인
git checkout feature/login
git log --oneline
# 출력:
# d4e5f6g style: Add login form styles
# c3d4e5f feat: Add login JavaScript logic
# b2c3d4e feat: Add login HTML form
# a1b2c3d Initial release
# === Fast-Forward 병합 ===
git checkout main
git merge feature/login
# 출력:
Updating a1b2c3d..d4e5f6g
Fast-forward
login.css | 6 ++++++
login.html | 9 +++++++++
login.js | 8 ++++++++
3 files changed, 23 insertions(+)
# === 병합 후 확인 ===
git log --oneline --graph
# 출력:
* d4e5f6g (HEAD -> main, feature/login) style: Add login form styles
* c3d4e5f feat: Add login JavaScript logic
* b2c3d4e feat: Add login HTML form
* a1b2c3d Initial release
# === 브랜치 정리 ===
git branch -d feature/login
# 출력:
Deleted branch feature/login (was d4e5f6g).
결과
Fast-Forward 병합의 특징:
gitGraph
commit id: "Initial"
branch feature/login
checkout feature/login
commit id: "HTML form"
commit id: "JS logic"
commit id: "CSS styles"
checkout main
merge feature/login tag: "FF"
장점:
1
2
3
4
✅ 깔끔한 일직선 히스토리
✅ 별도의 병합 커밋 없음
✅ 이해하기 쉬운 구조
✅ 간단한 되돌리기
Topic3. Fast-Forward vs 일반 병합
언제 Fast-Forward를 사용하고, 언제 일반 병합을 사용하나요?
Fast-Forward 장단점
장점:
1
2
3
4
5
6
7
8
9
10
11
✅ 단순한 히스토리
- 일직선으로 읽기 쉬움
- git log가 깔끔함
✅ 빠른 처리
- 포인터만 이동
- 새 커밋 생성 안 함
✅ 쉬운 이해
- 초보자도 이해하기 쉬움
- 복잡도 낮음
단점:
1
2
3
4
5
6
7
❌ 브랜치 정보 손실
- 어디서 브랜치했는지 불명확
- 기능 단위 구분 어려움
❌ 되돌리기 어려움
- 어떤 커밋들이 한 기능인지 파악 곤란
- revert 시 여러 커밋 되돌려야 함
–no-ff 옵션 (병합 커밋 강제)
Fast-Forward 막고 병합 커밋 생성:
1
2
3
4
5
6
7
# 일반 Fast-Forward
git merge feature/payment
# → 포인터만 이동
# 병합 커밋 강제 생성
git merge --no-ff feature/payment
# → 병합 커밋 생성!
시각적 차이:
1
2
3
4
5
6
7
8
9
10
11
12
# Fast-Forward
* C4 (main, feature)
* C3
* C2
# --no-ff
* M (main) Merge feature into main
|\
| * C4 (feature)
| * C3
|/
* C2
실전 사용 전략
Fast-Forward 사용 (추천):
1
2
3
4
✅ 개인 프로젝트
✅ 작은 버그 수정
✅ 문서 업데이트
✅ 단순한 기능 추가
–no-ff 사용 (추천):
1
2
3
4
✅ 팀 프로젝트
✅ 중요한 기능 개발
✅ 릴리스 브랜치
✅ 기능 단위 추적 필요
해보기: –no-ff 옵션 실습
상황: 팀 프로젝트에서 기능 단위 추적
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
# === 설정 ===
mkdir team-project
cd team-project
git init
echo "# Team App" > README.md
git add README.md
git commit -m "Initial commit"
# === Feature 1: 검색 기능 ===
git checkout -b feature/search
echo "search.js" > search.js
git add search.js
git commit -m "Add search functionality"
echo "search.css" > search.css
git add search.css
git commit -m "Add search styles"
# === --no-ff로 병합 ===
git checkout main
git merge --no-ff feature/search -m "Merge feature/search into main"
# 출력:
Merge made by the 'recursive' strategy.
search.css | 0
search.js | 0
2 files changed, 0 insertions(+), 0 deletions(-)
# === Feature 2: 알림 기능 ===
git checkout -b feature/notification
echo "notify.js" > notify.js
git add notify.js
git commit -m "Add notification system"
# === --no-ff로 병합 ===
git checkout main
git merge --no-ff feature/notification -m "Merge feature/notification into main"
# === 히스토리 확인 ===
git log --oneline --graph --all
# 출력:
* M2 (HEAD -> main) Merge feature/notification into main
|\
| * N1 (feature/notification) Add notification system
|/
* M1 Merge feature/search into main
|\
| * S2 (feature/search) Add search styles
| * S1 Add search functionality
|/
* I1 Initial commit
# 기능 단위로 명확하게 구분됨!
기본 동작 변경
항상 –no-ff 사용하도록 설정:
1
2
3
4
5
6
7
8
9
10
11
12
13
# 전역 설정
git config --global merge.ff false
# 또는 프로젝트별
git config merge.ff false
# 확인
git config --get merge.ff
# false
# 이제 기본적으로 병합 커밋 생성
git merge feature/new-feature
# → 자동으로 --no-ff 적용됨
설정 해제:
1
2
# 기본값으로 되돌리기
git config --global --unset merge.ff
결과
전략 비교표:
| 상황 | Fast-Forward | –no-ff |
|---|---|---|
| 개인 프로젝트 | ✅ 추천 | ❌ 불필요 |
| 팀 협업 | ❌ 비추천 | ✅ 추천 |
| 핫픽스 | ✅ 빠른 적용 | ⚠️ 선택적 |
| 기능 개발 | ❌ 비추천 | ✅ 추천 |
| 실험적 변경 | ✅ 간단 | ❌ 과함 |
| 릴리스 병합 | ❌ 기록 필요 | ✅ 필수 |
권장 사항:
1
2
3
4
5
6
7
8
9
10
11
1. 팀 프로젝트
→ git config merge.ff false 설정
→ 모든 기능을 명확히 추적
2. 개인 프로젝트
→ 기본 Fast-Forward 사용
→ 중요 기능만 --no-ff
3. 오픈소스
→ --no-ff 사용
→ 기여자 기록 보존
정리
오늘 배운 내용:
1. Fast-Forward 병합:
- 포인터만 이동하는 간단한 병합
- 일직선 히스토리 유지
- 조건: main이 움직이지 않아야 함
2. Fast-Forward 실습:
1
2
3
git checkout main
git merge feature/branch
# → Fast-forward 메시지 확인
3. –no-ff 옵션:
1
2
3
git merge --no-ff feature/branch
# → 병합 커밋 강제 생성
# → 기능 단위 추적 가능
4. 사용 전략:
- 개인/단순: Fast-Forward ✅
- 팀/중요: –no-ff ✅
다음 단계: Day 47에서 3-way 병합을 배웁니다.
완료 체크:
- Fast-Forward 병합의 개념을 이해했다
- Fast-Forward 병합을 수행할 수 있다
- –no-ff 옵션의 차이를 안다
- 상황별 병합 전략을 선택할 수 있다
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
