깔끔한 Git 협업 전략: merge commit 없이 선형 히스토리 유지하기

SW·2025년 11월 27일
post-thumbnail

(Feat. git pull --rebase, Cherry-pick 정리 브랜치, PR 운영 방식)

협업을 하다 보면 개발 브랜치(develop)에 기능 브랜치를 merge하면서
불필요한 merge commit들이 쌓이고 히스토리가 너무 복잡해지는 경우가
자주 발생한다.

특히 다음과 같은 상황이 흔하다.

  • 각자 feature 브랜치를 develop에서 만들었지만 develop이 업데이트될 때마다
    merge로 따라감
  • "Merge branch 'develop' into feature/xxx" 같은 커밋이 계속 생김
  • 충돌이 PR 단계에서 한꺼번에 터짐
  • 히스토리가 망가져서 cherry-pick 또는 revert가 어려워짐

이 글에서는 실제 협업 환경에서 히스토리를 항상 깔끔하게 유지하는 Git 전략을 정리해본다.

1. 왜 Git 히스토리가 지저분해질까?

기본 git pull은 merge 방식이다.

A --- B --- C (develop)
       \
        X --- Y (feature)

feature 브랜치를 최신 develop으로 업데이트할 때

git pull origin develop

을 사용하면 다음과 같이 merge commit(M) 이 계속 생긴다.

A --- B --- C --- M
       \        \
        X --- Y  \
                  Z

개발이 길어질수록 merge commit 폭탄이 생겨 PR이 매우 복잡해진다.

2. 해결법 : git pull --rebase로 선형(linear) 히스토리 유지

feauture 브랜치에서 develop을 따라가고 싶다면 반드시 merge가 아닌
rebase로 업데이트해야 한다.

git pull --rebase origin develop

or

git fetch origin -> git rebase origin develop

rebase는 feature 브랜치의 변경사항을 develop 위로 다시 배치 하는 방식이다.
그래프는 아래와 같이 변한다.

A --- B --- C --- X --- Y

장점:

  • merge commit X
  • 히스토리 직관적
  • PR이 깔끔
  • 충돌이 조기에 발견되어 해결 쉬움

3. 실무에서의 정석 워크플로우

1️⃣ feature 브랜치를 생성하고 작업

git checkout -b feature/login

2️⃣ develop이 바뀔 때마다 rebase 기반으로 최신화

git pull --rebase origin develop

3️⃣ 작업 후 push
처음은

git push origin feature/login

rebase 이후에는 대부분

git push --force-with-lease

을 사용한다.
(⚠️ feature 브랜치는 개인 브랜치라 force push 해도 안전함)

4. PR 리뷰 시 로컬에서 확인하는 방법

리뷰어는 PR 브랜치를 로컬로 가져와서 반드시 확인해야한다.

git fetch origin
git checkout feature/login
git pull origin feature/login

확인할 것들:

* 커밋이 깔끔한가?
* 불필요한 merge commit은 없는가?
* develop에서 정상적으로 분기했는가?
* 테스트 코드는 통과하는가?

히스토리 확인:

git log --oneline --graph --decorate

5. 로컬에서 커밋 히스토리 정리 방법 (선택)

⚒️ interactive(대화형) rebase

‼️이미 원격에 공유된 브랜치에 막 사용하면 위험‼️

‼️ 원격(origin)에 아직 push 되지 않은 브랜치에서만 사용하기‼️

•	아직 나 혼자 로컬에서 작업하는 브랜치
•	다른 사람이 이 브랜치 기반으로 작업하거나 pull 하지 않은 상태
•	즉, 원격에 동일한 브랜치가 존재하지 않을 때만 사용

⚠️ 주의 — 히스토리 재작성 (history rewrite)의 위험성

•	이미 원격에 push 된 브랜치나, 팀원과 공유하는 브랜치에서는 rebase, squash, drop 절대 금지
•	사용해야 한다면 로컬 개인 브랜치, 아직 origin에 존재하지 않는 브랜치에 한정
•	--force 또는 --force-with-lease 로 push 시, 다른 사람이 만든 커밋을 덮어쓸 수 있음
•	interactive rebase 중 충돌이 생길 수 있고, 실수로 데이터를 잃을 수 있으므로 반드시 커밋 전후 확인

🧐 interactive(대화형) rebase 란?
-> “Git 히스토리를 편집할 수 있는 모드”

  • 최근 N개 커밋을 재배치/합치기
git rebase -i HEAD~N
  • N = 최근 커밋 몇 개를 편집할지 지정
  • -i = ininteractive(대화형) 모드
  • 편집기 열리면 다음과 같이 바꿈
pick aaaaaaa 기능 구현
Drop bbbbbbb 버그 수정
Squash ccccccc 스타일 수정

🧩 interactive rebase에서 할 수 있는 일

🧪 예시 1 — 여러 커밋 합쳐서 한 개로 만들기 (squash)

pick aaaaaaa 로그인 구현
squash bbbbbbb 오타 수정
squash ccccccc 버그 수정

-> 결과: aaaaaa 커밋 하나로 합쳐진다.

🧪 예시 2 — 실수로 올린 커밋 제거(drop)

pick aaaaaaa 기능 구현
drop bbbbbbb 민감한 파일 실수로 추가함
pick ccccccc 추가 작업

-> 결과: bbbbbbb 커밋 히스토리 삭제된다.

🧪 예시 3 — 커밋 메시지만 수정(reword)

reword aaaaaaa 기능 구현
pick bbbbbbb 추가 작업

→ 결과: 커밋 메시지 수정 창을 띄워줌.

GitHub에는 3가지 merge 옵션이 있다.

1) Squash and Merge (추천)
PR 내부의 모든 커밋을 한 개의 커밋으로 합쳐서 develop에 반영.
히스토리 단순하고 깔끔함.
2) Rebase and Merge
PR 커밋을 그래도 develop 위에 linear하게 올림.
커밋 구조가 이미 깔끔할 때 유리.
3) Merge Commit
필요할 때만 사용.
히스토리가 엉킴.
Squash 장점

* 기능 단위로 커밋을 1~3개로 정리 -> PR/리뷰 단순화
* 불필요한 잡다한 커밋 제거 -> 히스토리 가독성 증가
* 특정 기능만 되돌릴 때 revert가 쉬움
* 배포 시 기능 단위로 명확하게 포함 내용 확인 가능

6. 브랜치 히스토리가 이미 꼬였을 때 해결법 (꼬였을 때만 ‼️)

기본 브랜치가 merge commit으로 난장판일 경우,
"정리 브랜치(clean-up)"를 만들어 필요한 커밋만 다시 모아오는 전략을 사용한다.
1️⃣ 정리용 브랜치 생성

git checkout -b clean

2️⃣ release 기준 커밋으로 reset

git reset --hard origin/develop

3️⃣ 각자 feature 브랜치의 정상 커밋만 cherry-pick

git cherry-pick <커밋 A>
git cherry-pick <커밋 B>

4️⃣ 정리된 clean 브랜치를 develop 위로 rebase

git rebase origin/develop

5️⃣ fast-foward로 develop 반영

git checkout develop
git merge clean --ff-only
git push origin develop

이렇게 하면 꼬였던 히스토리를 완전히 새 것처럼 깔끔하게 초기화할 수 있다.

7. 팀에 적용할 때 기억해야 할 단 하나의 규칙

🔥 개인(feature) 브랜치는 자유롭게 rebase 해도 된다.
-> 나만 쓰는 브랜치라 히스토리 바뀌어도 OK
develop / main 같은 공용 브랜치는 절대 rebase 금지
-> 공용 브랜치를 rebase하면 모든 팀원 히스토리가 꼬인다.

📌 정리

🧹 마무리

Git 협업에서 가장 중요한 건 히스토리를 선형(linear)으로 유지하는 것이다.

* PR 리뷰 시간 감소
* 충돌 감소
* revert(되돌리기), 배포가 쉬움
* 팀 전체 생산성 증가

앞으로 각 팀원이

git pull --rebase origin develop
만 습관적으로 해줘도 Git 흐름은 믿을 수 없을 정도로 깔끔해진다.




profile
코딩 새싹

0개의 댓글