Git 선형 히스토리 가이드: Rebase + Fast-Forward Merge

임기호·2025년 8월 19일

적용 사유

기존에 양방향 머지 (메인을 내 브랜치에 머지 → 다시 내 브랜치를 메인에 머지)로 인해 머지 커밋이 불필요하게 쌓이고
브랜치 라인이 분기/교차하면서 히스토리가 꼬이는 문제가 발생.
리뷰/추적 난이도가 올라가고, 릴리스 노트 및 CI 추적이 지저분해져
선형(리니어) 히스토리 전략(Rebase + FF-merge) 으로 전환/정착함.


TL;DR

  • 기능 브랜치는 항상 최신 main 위로 rebase 한다.
  • main에 합칠 때는 --ff-onlyFast-Forward merge (머지 커밋 없음).
  • 원격에 올린 기능 브랜치 강제 푸시는 --force-with-lease 로 안전하게.
  • 이미 여러 명이 공유하는 브랜치는 rebase 금지.

Rebase란?

내 브랜치의 커밋들을 다른 기준(base)의 끝으로 옮겨 다시 재생(replay) 하는 것.

(전)
main:    A──B──C
feature:         └─ x ─ y

main이 D까지 진행됨

rebase 후(feature를 main 뒤로)
main:    A──B──C──D
feature:              └─ x' ─ y'   (#는 바뀌지만 내용은 동일)
  • merge: 두 줄기를 합쳐 머지 커밋(M) 생성 → 분기 흔적이 남음.
  • rebase: 내 커밋을 최신 main 뒤로 옮김 → 선형(일자) 히스토리.

장점: 로그가 깔끔, 리뷰/추적/git bisect/리버트 쉬움.
주의: 커밋 SHA가 바뀌므로 개인(feature) 브랜치에서만 사용. (공유 브랜치 rebase 금지)


전역 설정(한 번만)

git config --global pull.rebase true       # pull 시 merge 대신 rebase
git config --global rebase.autoStash true  # rebase 전 변경 자동 스태시
git config --global fetch.prune true       # 삭제된 원격 브랜치 자동 정리

선택: 로그 가독성 향상 alias

git config --global alias.lg "log --oneline --graph --decorate --all"

일일 워크플로우 (Rebase + FF-merge)

1) 브랜치 생성 & 작업

git switch -c feature/x
# ... 작업 ...
git add -A
git commit -m "feat: ~"
# 필요 시 반복

2) 머지 직전 최신 main 위로 rebase

git fetch origin
git rebase origin/main
# 충돌 시 해결 → add → continue
git add -A
git rebase --continue
# 너무 꼬이면 되돌리기
# git rebase --abort

이미 원격에 feature/x를 푸시했다면, 커밋 해시가 바뀌므로 안전 강제 푸시:

git push -u origin feature/x --force-with-lease

3) main에 Fast-Forward 머지

git switch main
git fetch origin
git merge --ff-only feature/x    # 머지 커밋 없이 붙이기
git push origin main

4) 정리

git branch -d feature/x
git push origin :feature/x

Squash Merge (대안)

메인에는 기능당 1커밋만 남기고 싶다면:

git fetch origin
git rebase origin/main

git switch main
git fetch origin
git merge --squash feature/x
git commit -m "feat: X 구현 (요약)"
git push origin main

GitHub/GitLab PR/MR UI의 Squash and merge 를 사용해도 동일.


커밋 메시지 규칙(예시)

  • Conventional Commits 권장:
    feat:, fix:, refactor:, chore:, docs:, test:
  • 메인 합치기 전 인터랙티브 rebase로 WIP/잡음 커밋 정리:
git fetch origin
git rebase -i origin/main   # pick/squash/fixup로 의미 단위 정리

하지 말아야 할 것

  • 메인을 내 브랜치에 merge → 다시 내 브랜치를 메인에 merge (양방향 머지 금지)
  • 다수가 공유/베이스로 사용하는 브랜치를 rebase
  • git pull 기본 merge 사용(머지 커밋 누적) → 전역 설정으로 방지

트러블슈팅 & 복구

  • rebase 중 문제 발생:

    git rebase --abort
  • 이전 상태로 되돌리기(최근 이동 이력 조회):

    git reflog
    git reset --hard HEAD@{1}   # 직전 상태로
  • 강제 푸시는 항상 안전 옵션:

    git push --force-with-lease

    --force 대신 --force-with-lease 사용: 동료 커밋 덮어쓰기 방지


팀 운영 팁

  • PR/MR 규칙
    • Merge 전 반드시 rebase origin/main 완료 상태로 제출
    • Merge 전략은 FF-only 또는 Squash 로 고정
  • CI
    • Rebased 브랜치 기준으로 CI 통과 확인 → 메인에 FF-merge
  • 브랜치 네이밍
    • feature/, fix/, chore/ 접두사 등 일관화

체크리스트

  • pull.rebase=true 설정됨
  • 기능 브랜치에서 항상 rebase origin/main
  • 메인 병합은 merge --ff-only (또는 Squash)
  • 불필요한 양방향 merge 금지
  • 강제 푸시는 --force-with-lease
  • PR 전 rebase -i로 커밋 정리

왜 이 방식이 좋은가?

  • 히스토리 직선화: git log --graph 가 단순 → 변경 추적 용이
  • 리뷰 효율↑: 기능 범위가 명확, bisect/리버트 쉬움
  • 머지 커밋 폭증 방지: CI 및 릴리스 노트가 깔끔

부록: 예시 명령 전체 흐름

# 작업 시작
git switch -c feature/x
# ... edit ...
git add -A
git commit -m "feat: add X"

# 최신 main 위로 올리기
git fetch origin
git rebase origin/main

# (원격에 브랜치 올렸던 경우)
git push -u origin feature/x --force-with-lease

# 메인에 합치기 (FF-only)
git switch main
git fetch origin
git merge --ff-only feature/x
git push origin main

# 정리
git branch -d feature/x
git push origin :feature/x

0개의 댓글