Sessions
입문-중급2-3시간

Git Workflow: Merge vs Rebase

Git의 핵심 워크플로우인 Merge와 Rebase의 차이를 이해하고, 실무에서 언제 어떤 것을 사용해야 하는지 배웁니다.

What You Will Learn
  • Git 브랜치와 커밋 히스토리의 이해
  • Merge의 동작 원리와 사용법
  • Rebase의 동작 원리와 단계별 절차
  • Rebase 중 충돌 해결 방법
  • Interactive Rebase로 커밋 히스토리 정리
  • 상황별 Merge/Rebase 선택 기준
Prerequisites
  • Git 기본 명령어 (add, commit, push, pull) 사용 경험
  • 브랜치 생성/이동 경험
  • 터미널/CLI 기본 사용법

핵심 개념 미리보기

Merge

두 브랜치의 히스토리를 합치며 '병합 커밋'을 생성합니다. 분기 이력이 보존되어 언제 어떤 작업을 했는지 추적할 수 있습니다.

Rebase

브랜치의 시작점을 변경하여 커밋들을 재생성합니다. 깔끔한 직선형 히스토리를 만들지만, 커밋 해시가 변경됩니다.

1
Git 기본 개념 복습
Git의 핵심 개념과 브랜치에 대해 간단히 복습합니다.

Git이란?

Git은 분산 버전 관리 시스템(DVCS)입니다. 코드의 변경 이력을 추적하고, 여러 개발자가 동시에 작업할 수 있게 해줍니다.

# Git 설치 확인
git --version

# 사용자 설정 (최초 1회)
git config --global user.name "Your Name"
git config --global user.email "your@email.com"

# 설정 확인
git config --list

브랜치(Branch)란?

브랜치는 독립적인 작업 공간입니다. main 브랜치에서 분기하여 새로운 기능을 개발하고, 완료 후 다시 합칩니다.

# 현재 브랜치 확인
git branch

# 새 브랜치 생성
git branch feature/new-feature

# 브랜치 생성과 동시에 이동
git checkout -b feature/new-feature
# 또는 (Git 2.23+)
git switch -c feature/new-feature

# 브랜치 이동
git checkout main
# 또는
git switch main

커밋 히스토리 확인

커밋 히스토리를 시각적으로 확인하는 방법입니다.

# 기본 로그 확인
git log

# 한 줄로 보기
git log --oneline

# 그래프로 보기 (브랜치 구조 파악에 유용)
git log --oneline --graph --all

# 별칭 설정 (권장)
git config --global alias.lg "log --oneline --graph --all --decorate"
git lg  # 이제 이렇게 사용 가능
2
실습 환경 준비
Merge와 Rebase를 직접 실습할 Git 저장소를 준비합니다.

실습용 저장소 생성

빈 폴더에서 새로운 Git 저장소를 만듭니다.

# 실습 폴더 생성
mkdir git-workflow-lab
cd git-workflow-lab

# Git 저장소 초기화
git init

# 초기 파일 생성
echo "# Git Workflow Lab" > README.md
echo "version: 1.0" > config.txt

# 첫 커밋
git add .
git commit -m "Initial commit"

main 브랜치에 커밋 추가

실습을 위해 main 브랜치에 몇 개의 커밋을 추가합니다.

# main 브랜치에서 작업
echo "Feature A - Step 1" >> features.txt
git add .
git commit -m "Add feature A - step 1"

echo "Feature A - Step 2" >> features.txt
git add .
git commit -m "Add feature A - step 2"

# 현재 상태 확인
git log --oneline
# 출력 예시:
# abc1234 Add feature A - step 2
# def5678 Add feature A - step 1
# 9012345 Initial commit

feature 브랜치 생성

새로운 기능 개발을 위한 브랜치를 생성합니다.

# feature 브랜치 생성 및 이동
git checkout -b feature/new-feature

# feature 브랜치에서 작업
echo "New Feature - Part 1" >> new-feature.txt
git add .
git commit -m "feat: add new feature part 1"

echo "New Feature - Part 2" >> new-feature.txt
git add .
git commit -m "feat: add new feature part 2"

# 브랜치 상태 확인
git log --oneline --graph --all

main 브랜치에 새로운 커밋 추가 (분기 상황 만들기)

실제 협업 상황처럼 main에도 새로운 커밋을 추가합니다.

# main 브랜치로 이동
git checkout main

# main에서 새로운 작업
echo "Hotfix applied" >> hotfix.txt
git add .
git commit -m "hotfix: critical bug fix"

echo "Feature B added" >> features.txt
git add .
git commit -m "Add feature B"

# 현재 브랜치 구조 확인
git log --oneline --graph --all
# 출력 예시:
#   * xyz7890 (HEAD -> main) Add feature B
#   * abc4567 hotfix: critical bug fix
# | * def1234 (feature/new-feature) feat: add new feature part 2
# | * ghi5678 feat: add new feature part 1
# |/
#   * abc1234 Add feature A - step 2
#   * def5678 Add feature A - step 1
#   * 9012345 Initial commit
3
Merge란?
두 브랜치의 히스토리를 합치는 Merge에 대해 알아봅니다.

Merge의 개념

Merge는 두 브랜치의 작업 내용을 합치면서 '병합 커밋(Merge Commit)'을 생성합니다. 브랜치의 히스토리가 그대로 보존됩니다.

# Merge의 시각적 표현

# 병합 전:
#       A---B---C  (feature)
#      /
# D---E---F---G  (main)

# Merge 후:
#       A---B---C
#      /         \
# D---E---F---G---H  (main, merge commit)

# 특징:
# - 히스토리가 분기된 모습 그대로 보존
# - 병합 커밋(H)이 새로 생성됨
# - 언제 어떤 브랜치에서 작업했는지 추적 가능

Merge 실습

feature 브랜치를 main에 merge 해봅니다.

# main 브랜치에서 실행
git checkout main

# feature 브랜치를 main에 병합
git merge feature/new-feature

# 충돌이 없다면 자동으로 병합 커밋 생성
# 에디터가 열리면 커밋 메시지 확인 후 저장

# 병합 결과 확인
git log --oneline --graph --all
# 출력 예시:
# *   abc9999 (HEAD -> main) Merge branch 'feature/new-feature'
# |\
# | * def1234 feat: add new feature part 2
# | * ghi5678 feat: add new feature part 1
# * | xyz7890 Add feature B
# * | abc4567 hotfix: critical bug fix
# |/
# * abc1234 Add feature A - step 2
# ...

Fast-forward Merge

main 브랜치에 변경사항이 없으면 Fast-forward 방식으로 병합됩니다.

# Fast-forward 상황:
#       A---B---C  (feature)
#      /
# D---E  (main)

# Fast-forward Merge 후:
# D---E---A---B---C  (main, feature)

# 실습: 새 브랜치에서 FF merge 테스트
git checkout -b feature/ff-test
echo "FF test" > ff-test.txt
git add . && git commit -m "ff test commit"

git checkout main
git merge feature/ff-test
# "Fast-forward" 메시지가 출력됨

# --no-ff 옵션으로 강제로 병합 커밋 생성
git merge --no-ff feature/another-branch
4
Rebase란?
브랜치의 시작점을 변경하는 Rebase에 대해 알아봅니다.

Rebase의 개념

Rebase는 브랜치의 베이스(시작점)를 다른 커밋으로 변경합니다. 커밋들이 '재생성'되어 깔끔한 직선형 히스토리를 만듭니다.

# Rebase의 시각적 표현

# Rebase 전:
#       A---B---C  (feature)
#      /
# D---E---F---G  (main)

# Rebase 후:
#               A'--B'--C'  (feature)
#              /
# D---E---F---G  (main)

# 특징:
# - 기존 커밋 A, B, C가 A', B', C'로 "새로 생성"됨
# - 커밋 해시가 변경됨 (중요!)
# - 깔끔한 직선형 히스토리
# - 분기 이력이 사라짐

Rebase가 동작하는 원리

Rebase는 내부적으로 다음 과정을 거칩니다.

# Rebase 동작 과정 (feature 브랜치에서 git rebase main 실행 시)

# Step 1: feature 브랜치의 커밋들을 임시 저장
#   - A, B, C 커밋의 변경사항을 임시 저장소에 보관

# Step 2: feature 브랜치를 main의 최신 커밋으로 이동
#   - feature의 HEAD가 main의 최신 커밋(G)을 가리킴

# Step 3: 임시 저장된 커밋들을 순서대로 재적용
#   - A의 변경사항 적용 → A' 커밋 생성
#   - B의 변경사항 적용 → B' 커밋 생성
#   - C의 변경사항 적용 → C' 커밋 생성

# 결과:
# D---E---F---G---A'---B'---C'  (feature)
#               (main)

왜 커밋 해시가 바뀔까?

Git 커밋의 해시는 내용뿐 아니라 부모 커밋 정보도 포함하기 때문입니다.

# Git 커밋 해시 구성 요소:
# - 커밋 메시지
# - 작성자 정보
# - 타임스탬프
# - 파일 변경사항
# - 부모 커밋의 해시  ← 이것이 핵심!

# Rebase 전 커밋 A:
# - parent: E (main에서 분기된 시점)
# - hash: abc123

# Rebase 후 커밋 A':
# - parent: G (main의 최신 커밋)  ← 부모가 바뀜!
# - hash: xyz789  ← 따라서 해시도 바뀜!

# 이것이 "커밋이 재생성된다"는 의미입니다
5
Rebase 실습 - 기본 절차
Rebase의 단계별 실습을 진행합니다.

실습 환경 재설정

Merge 실습으로 변경된 환경을 초기화하고 Rebase 실습을 준비합니다.

# 실습을 위해 새로운 브랜치 상황 만들기
# (또는 새 폴더에서 처음부터 시작)

# 방법 1: 새 폴더에서 시작
cd ..
mkdir git-rebase-lab
cd git-rebase-lab
git init

# 기본 커밋 생성
echo "Base" > base.txt
git add . && git commit -m "Initial commit"

echo "Main work 1" >> main.txt
git add . && git commit -m "main: work 1"

# feature 브랜치 생성
git checkout -b feature/rebase-test

echo "Feature work 1" > feature.txt
git add . && git commit -m "feat: work 1"

echo "Feature work 2" >> feature.txt
git add . && git commit -m "feat: work 2"

# main으로 돌아가서 추가 커밋
git checkout main
echo "Main work 2" >> main.txt
git add . && git commit -m "main: work 2"

echo "Main work 3" >> main.txt
git add . && git commit -m "main: work 3"

현재 상태 확인

Rebase 전 브랜치 구조를 확인합니다.

# 브랜치 구조 확인
git log --oneline --graph --all

# 예상 출력:
# * f5e4d3c (HEAD -> main) main: work 3
# * a1b2c3d main: work 2
# | * 9z8y7x6 (feature/rebase-test) feat: work 2
# | * 1a2b3c4 feat: work 1
# |/
# * 5d6e7f8 main: work 1
# * 0a0b0c0 Initial commit

# 현재 상황:
# - main: Initial → work1 → work2 → work3
# - feature: Initial → work1 → feat1 → feat2

Rebase 실행

feature 브랜치를 main의 최신 커밋 위로 rebase 합니다.

# 1. Rebase할 브랜치로 이동 (중요!)
git checkout feature/rebase-test

# 2. main 기준으로 rebase 실행
git rebase main

# 출력 예시:
# Successfully rebased and updated refs/heads/feature/rebase-test.

# 3. 결과 확인
git log --oneline --graph --all

# 예상 출력:
# * n3w1d2e (HEAD -> feature/rebase-test) feat: work 2
# * n3w2d3f feat: work 1
# * f5e4d3c (main) main: work 3
# * a1b2c3d main: work 2
# * 5d6e7f8 main: work 1
# * 0a0b0c0 Initial commit

# 확인: 직선형 히스토리가 됨!

Rebase 후 main에 병합

Rebase된 feature 브랜치를 main에 병합합니다.

# main으로 이동
git checkout main

# feature 브랜치 병합 (Fast-forward됨)
git merge feature/rebase-test

# 출력:
# Fast-forward
# ...

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

# 깔끔한 직선 히스토리:
# * n3w1d2e (HEAD -> main, feature/rebase-test) feat: work 2
# * n3w2d3f feat: work 1
# * f5e4d3c main: work 3
# * a1b2c3d main: work 2
# * 5d6e7f8 main: work 1
# * 0a0b0c0 Initial commit
6
Rebase 중 충돌 해결
Rebase 과정에서 발생하는 충돌을 해결하는 방법을 배웁니다.

충돌 상황 만들기

의도적으로 충돌이 발생하는 상황을 만들어봅니다.

# 새 실습 환경
mkdir git-conflict-lab && cd git-conflict-lab
git init

# 공통 파일 생성
echo "Line 1: Original" > shared.txt
echo "Line 2: Original" >> shared.txt
git add . && git commit -m "Initial: shared file"

# feature 브랜치에서 Line 1 수정
git checkout -b feature/conflict-test
sed -i '' 's/Line 1: Original/Line 1: Feature change/' shared.txt  # macOS
# Linux: sed -i 's/Line 1: Original/Line 1: Feature change/' shared.txt
git add . && git commit -m "feat: modify line 1"

# main에서도 Line 1 수정 (충돌 발생!)
git checkout main
sed -i '' 's/Line 1: Original/Line 1: Main change/' shared.txt
git add . && git commit -m "main: modify line 1"

Rebase 시 충돌 발생

Rebase를 실행하면 충돌이 발생합니다.

# feature 브랜치로 이동
git checkout feature/conflict-test

# Rebase 시도
git rebase main

# 출력:
# CONFLICT (content): Merge conflict in shared.txt
# error: could not apply abc1234... feat: modify line 1
# hint: Resolve all conflicts manually, mark them as resolved with
# hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
# hint: You can instead skip this commit: run "git rebase --skip".
# hint: To abort and get back to the state before "git rebase", run "git rebase --abort".

# 현재 상태 확인
git status
# interactive rebase in progress; onto xyz789
# ...
# Unmerged paths:
#   both modified:   shared.txt

충돌 해결하기

충돌을 수동으로 해결하고 rebase를 계속합니다.

# 1. 충돌 파일 확인
cat shared.txt

# 출력:
# <<<<<<< HEAD
# Line 1: Main change
# =======
# Line 1: Feature change
# >>>>>>> abc1234 (feat: modify line 1)
# Line 2: Original

# 2. 원하는 내용으로 수정
# 에디터로 파일을 열어 충돌 마커를 제거하고 원하는 내용 작성
# 예: 두 변경사항을 모두 반영
cat > shared.txt << 'EOF'
Line 1: Main change + Feature enhancement
Line 2: Original
EOF

# 3. 해결된 파일을 staging
git add shared.txt

# 4. Rebase 계속 진행
git rebase --continue

# 커밋 메시지 편집창이 뜨면 저장하고 닫기

# 5. 성공 메시지 확인
# Successfully rebased and updated refs/heads/feature/conflict-test.

Rebase 관련 명령어 정리

Rebase 진행 중 사용할 수 있는 명령어들입니다.

# Rebase 진행 중 사용 가능한 명령어

# 1. 충돌 해결 후 계속 진행
git rebase --continue

# 2. 현재 커밋 건너뛰기 (해당 커밋 변경사항 포기)
git rebase --skip

# 3. Rebase 완전 취소 (원래 상태로 복구)
git rebase --abort

# 4. Rebase 진행 상태 확인
git status

# 팁: 충돌 해결이 어려우면 --abort로 안전하게 취소하고
# 다시 시도할 수 있습니다.
7
Interactive Rebase
커밋 히스토리를 수정할 수 있는 Interactive Rebase를 배웁니다.

Interactive Rebase란?

커밋 순서 변경, 커밋 합치기, 커밋 메시지 수정 등 히스토리를 자유롭게 편집할 수 있습니다.

# Interactive Rebase 시작
git rebase -i HEAD~3  # 최근 3개 커밋 편집

# 또는 특정 커밋부터
git rebase -i abc1234^  # abc1234 커밋부터 현재까지

# 에디터가 열리며 다음과 같이 표시됨:
# pick abc1234 commit message 1
# pick def5678 commit message 2
# pick ghi9012 commit message 3
#
# Commands:
# p, pick = use commit (커밋 유지)
# r, reword = use commit, but edit the commit message (메시지만 수정)
# e, edit = use commit, but stop for amending (커밋 수정)
# s, squash = use commit, but meld into previous commit (이전 커밋과 합침)
# f, fixup = like squash, but discard this commit's message (합치되 메시지 버림)
# d, drop = remove commit (커밋 삭제)

커밋 합치기 (Squash)

여러 개의 작은 커밋을 하나로 합칩니다.

# 실습: WIP 커밋들을 하나로 합치기
git checkout -b feature/squash-test

echo "work1" > work.txt && git add . && git commit -m "WIP: start"
echo "work2" >> work.txt && git add . && git commit -m "WIP: continue"
echo "work3" >> work.txt && git add . && git commit -m "WIP: almost done"
echo "work4" >> work.txt && git add . && git commit -m "feat: complete feature"

# 최근 4개 커밋 합치기
git rebase -i HEAD~4

# 에디터에서 다음과 같이 수정:
# pick abc1234 WIP: start
# squash def5678 WIP: continue       # squash로 변경
# squash ghi9012 WIP: almost done    # squash로 변경
# squash jkl3456 feat: complete feature  # squash로 변경

# 저장 후, 새 커밋 메시지 작성 화면이 나타남
# 원하는 메시지로 수정 후 저장

# 결과: 4개 커밋이 1개로 합쳐짐
git log --oneline

커밋 메시지 수정 (Reword)

과거 커밋의 메시지를 수정합니다.

# 최근 3개 커밋 중 메시지 수정하기
git rebase -i HEAD~3

# 에디터에서 수정할 커밋의 'pick'을 'reword' 또는 'r'로 변경:
# pick abc1234 feat: add feature
# reword def5678 typo in comit msg    # 이 메시지 수정하고 싶음
# pick ghi9012 fix: bug fix

# 저장하면, reword 표시된 커밋에서 멈추고
# 새 메시지를 입력할 수 있는 에디터가 열림

커밋 순서 변경 및 삭제

커밋 순서를 바꾸거나 불필요한 커밋을 삭제합니다.

# 커밋 순서 변경
git rebase -i HEAD~3

# 에디터에서 줄 순서를 변경:
# 원래:
# pick abc1234 first
# pick def5678 second
# pick ghi9012 third

# 순서 변경:
# pick ghi9012 third
# pick abc1234 first
# pick def5678 second

# 커밋 삭제
# 줄을 삭제하거나 'drop' 사용:
# pick abc1234 first
# drop def5678 second  # 이 커밋 삭제
# pick ghi9012 third

# 주의: 삭제된 커밋의 변경사항도 함께 사라집니다!
8
Merge vs Rebase 비교
Merge와 Rebase의 차이점을 정리하고 언제 무엇을 사용해야 하는지 알아봅니다.

시각적 비교

같은 상황에서 Merge와 Rebase의 결과를 비교합니다.

# 초기 상태:
#       A---B---C  (feature)
#      /
# D---E---F---G  (main)

# ============== Merge 결과 ==============
#       A---B---C
#      /         \
# D---E---F---G---M  (main)
#
# - 병합 커밋(M) 생성
# - A, B, C 커밋 해시 유지
# - 분기 히스토리 보존
# - "언제 분기했고 언제 병합했는지" 추적 가능

# ============== Rebase 결과 ==============
# D---E---F---G---A'---B'---C'  (main)
#
# - 병합 커밋 없음
# - A, B, C가 A', B', C'로 재생성 (해시 변경)
# - 직선형 히스토리
# - 마치 "처음부터 main 위에서 작업한 것처럼" 보임

장단점 비교표

각 방식의 장단점을 정리합니다.

# ┌──────────────┬─────────────────────┬─────────────────────┐
# │     항목      │       Merge         │       Rebase        │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 히스토리     │ 분기 구조 유지       │ 직선형으로 정리됨    │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 커밋 해시    │ 유지됨              │ 변경됨              │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 충돌 해결    │ 한 번에 모두        │ 커밋마다 개별       │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 안전성       │ 높음 (비파괴적)      │ 주의 필요 (재작성)   │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 협업 시      │ 안전함              │ push된 커밋은 위험  │
# ├──────────────┼─────────────────────┼─────────────────────┤
# │ 추적성       │ 작업 흐름 파악 용이  │ 깔끔하지만 맥락 손실│
# └──────────────┴─────────────────────┴─────────────────────┘

언제 Merge를 사용할까?

Merge가 적합한 상황입니다.

# Merge 권장 상황:

# 1. 공유된(push된) 브랜치를 병합할 때
git checkout main
git merge feature/shared-branch  # 여러 사람이 작업한 브랜치

# 2. 병합 이력이 중요한 경우
# - "이 기능이 언제 main에 들어왔는지" 추적 필요
# - PR/MR 단위로 히스토리 구분하고 싶을 때

# 3. 팀 규칙이 Merge 기반일 때
# - GitHub Flow, GitLab Flow 등

# 4. 충돌이 복잡할 것으로 예상될 때
# - Merge는 한 번에 모든 충돌 해결
# - Rebase는 커밋마다 충돌 해결 필요

# 5. 되돌리기가 쉬워야 할 때
git revert -m 1 <merge-commit>  # 병합 커밋 되돌리기 가능

언제 Rebase를 사용할까?

Rebase가 적합한 상황입니다.

# Rebase 권장 상황:

# 1. 로컬에서만 작업한 브랜치를 정리할 때
git checkout feature/my-local-work
git rebase main  # push 전 로컬 브랜치 정리

# 2. 커밋 히스토리를 깔끔하게 유지하고 싶을 때
# - 불필요한 "WIP" 커밋 정리
# - 논리적 단위로 커밋 재구성

# 3. PR 제출 전 브랜치 업데이트
git checkout feature/my-pr
git fetch origin
git rebase origin/main  # main의 최신 변경사항 반영

# 4. Interactive rebase로 커밋 정리
git rebase -i HEAD~5  # 최근 5개 커밋 편집

# 5. 선형 히스토리를 선호하는 팀 규칙
9
Golden Rule: Push 전/후 규칙
Rebase 사용 시 반드시 지켜야 할 황금률을 배웁니다.

황금률: 이미 Push한 커밋은 Rebase하지 않는다

공유된 히스토리를 변경하면 다른 팀원에게 문제가 발생합니다.

# ⚠️ 절대 하지 말아야 할 것:

# 이미 push된 커밋을 rebase
git push origin feature/shared
# (팀원들이 이 브랜치를 pull)
git rebase main
git push --force  # 💀 다른 팀원의 작업을 날릴 수 있음!

# 왜 문제가 되는가?
# 1. 팀원이 이미 pull한 커밋들의 해시가 변경됨
# 2. 팀원이 push하려 하면 충돌 발생
# 3. 팀원의 로컬 작업이 엉킬 수 있음
# 4. 히스토리가 중복되거나 손실될 수 있음

안전한 Rebase 워크플로우

팀 협업 시 안전하게 Rebase를 사용하는 방법입니다.

# ✅ 안전한 사용법:

# 1. 로컬에서만 작업한 브랜치 (아직 push 안 함)
git checkout -b feature/new-work
# (작업...)
git rebase main  # ✅ 안전: 아직 push 안 함
git push origin feature/new-work  # 처음 push

# 2. 혼자만 사용하는 브랜치 (확실할 때만!)
git push --force-with-lease  # --force보다 안전
# --force-with-lease: 다른 사람이 push한 게 있으면 실패

# 3. Push 전에 항상 rebase로 정리하는 습관
git fetch origin
git rebase origin/main
git push origin feature/my-branch

실수로 Rebase 했을 때 복구

실수로 Rebase를 해버렸을 때 복구하는 방법입니다.

# 방법 1: git reflog 사용
git reflog
# 출력:
# abc1234 (HEAD -> feature) HEAD@{0}: rebase finished
# def5678 HEAD@{1}: rebase: feat: work 2
# ghi9012 HEAD@{2}: rebase: feat: work 1
# jkl3456 HEAD@{3}: rebase (start)
# mno7890 HEAD@{4}: commit: feat: work 2  ← rebase 전!

# rebase 이전 상태로 복구
git reset --hard mno7890

# 방법 2: ORIG_HEAD 사용 (rebase 직후에만)
git reset --hard ORIG_HEAD

# 팁: 중요한 작업 전에 백업 브랜치 만들기
git branch backup-before-rebase

팀 협업 가이드라인

팀에서 Merge/Rebase를 사용할 때 권장하는 규칙입니다.

# 추천 팀 규칙:

# 1. 개인 feature 브랜치
# - Push 전: rebase로 정리 가능
# - Push 후: merge만 사용 또는 --force-with-lease (혼자 작업 시)

# 2. 공유 브랜치 (develop, release 등)
# - 항상 merge만 사용
# - rebase 금지

# 3. main/master 브랜치
# - 직접 commit 금지
# - PR/MR을 통해서만 병합
# - Squash merge 또는 일반 merge

# 4. PR 생성 전 체크리스트
git fetch origin
git rebase origin/main       # main 최신화
git rebase -i HEAD~n         # 커밋 정리
# (필요시 push --force-with-lease)

# 5. PR 병합 후
git checkout main
git pull
git branch -d feature/completed  # 로컬 브랜치 삭제
10
실전 시나리오 실습
실제 협업 상황을 시뮬레이션하며 종합 실습합니다.

시나리오: Feature 개발 중 main 업데이트

feature 브랜치에서 작업 중 main에 새로운 변경이 생긴 상황입니다.

# 상황 설정
mkdir team-project && cd team-project
git init

echo "v1.0" > version.txt
git add . && git commit -m "Initial release v1.0"

# 당신의 feature 작업
git checkout -b feature/user-profile
echo "profile page" > profile.txt
git add . && git commit -m "feat: add profile page"
echo "profile settings" >> profile.txt
git add . && git commit -m "feat: add profile settings"

# 그 사이 팀원이 main에 작업을 push함
git checkout main
echo "v1.1" > version.txt
git add . && git commit -m "release: v1.1"
echo "hotfix applied" > hotfix.txt
git add . && git commit -m "hotfix: critical security patch"

해결 방법 1: Rebase로 깔끔하게

Push 전이라면 Rebase로 깔끔하게 정리합니다.

# feature 브랜치로 이동
git checkout feature/user-profile

# 현재 상태 확인
git log --oneline --graph --all
# * abc (main) hotfix: critical security patch
# * def release: v1.1
# | * ghi (HEAD -> feature/user-profile) feat: add profile settings
# | * jkl feat: add profile page
# |/
# * mno Initial release v1.0

# main 위로 rebase
git rebase main

# 결과 확인
git log --oneline --graph --all
# * xyz (HEAD -> feature/user-profile) feat: add profile settings
# * uvw feat: add profile page
# * abc (main) hotfix: critical security patch
# * def release: v1.1
# * mno Initial release v1.0

# main에 병합 (fast-forward)
git checkout main
git merge feature/user-profile

해결 방법 2: Merge로 안전하게

이미 Push했다면 Merge로 안전하게 병합합니다.

# 상황: feature 브랜치가 이미 push된 상태

# main의 변경사항을 feature에 merge
git checkout feature/user-profile
git merge main

# 또는 main에서 feature를 merge
git checkout main
git merge feature/user-profile

# 병합 커밋이 생성됨
git log --oneline --graph --all
# *   xyz Merge branch 'feature/user-profile'
# |\
# | * ghi feat: add profile settings
# | * jkl feat: add profile page
# * | abc hotfix: critical security patch
# * | def release: v1.1
# |/
# * mno Initial release v1.0

시나리오: PR 전 커밋 정리

여러 개의 WIP 커밋을 의미 있는 커밋으로 정리합니다.

# 현재 커밋 상태
git log --oneline
# abc WIP
# def fixed typo
# ghi WIP again  
# jkl add feature A
# mno fix lint
# pqr Initial commit

# 최근 5개 커밋을 정리
git rebase -i HEAD~5

# 에디터에서:
# pick jkl add feature A
# squash ghi WIP again        # 합침
# squash def fixed typo       # 합침  
# squash abc WIP              # 합침
# drop mno fix lint           # 삭제

# 새 커밋 메시지 작성:
# feat: implement feature A
#
# - Add main feature logic
# - Include configuration options
# - Add unit tests

# 결과
git log --oneline
# xyz feat: implement feature A
# pqr Initial commit
Quick Reference: 명령어 요약

Merge 관련

git merge <branch>           # 브랜치 병합
git merge --no-ff <branch>   # 강제로 병합 커밋 생성
git merge --abort            # 병합 취소

Rebase 관련

git rebase <branch>          # 브랜치 위로 rebase
git rebase -i HEAD~n         # Interactive rebase
git rebase --continue        # 충돌 해결 후 계속
git rebase --abort           # Rebase 취소
git rebase --skip            # 현재 커밋 건너뛰기

유용한 명령어

git log --oneline --graph --all  # 히스토리 시각화
git reflog                        # 모든 HEAD 이동 기록
git reset --hard ORIG_HEAD        # rebase 직후 복구
git push --force-with-lease       # 안전한 force push
Congratulations! 🎉

이제 Merge와 Rebase의 차이를 명확히 이해하고, 상황에 맞게 선택할 수 있게 되었습니다!

기억할 핵심 원칙:

  • Push 전: Rebase로 깔끔하게 정리
  • Push 후: Merge로 안전하게 병합
  • 공유 브랜치: 절대 Rebase 금지
  • PR 전: Interactive Rebase로 커밋 정리

Next Steps:

  • • 실제 프로젝트에서 두 방식 모두 연습하기
  • • git cherry-pick 학습하기
  • • git bisect로 버그 원인 찾기
  • • GitHub/GitLab PR 워크플로우 익히기