(Feat. git pull --rebase, Cherry-pick 정리 브랜치, PR 운영 방식)
협업을 하다 보면 개발 브랜치(develop)에 기능 브랜치를 merge하면서
불필요한 merge commit들이 쌓이고 히스토리가 너무 복잡해지는 경우가
자주 발생한다.
특히 다음과 같은 상황이 흔하다.
이 글에서는 실제 협업 환경에서 히스토리를 항상 깔끔하게 유지하는 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이 매우 복잡해진다.
feauture 브랜치에서 develop을 따라가고 싶다면 반드시 merge가 아닌
rebase로 업데이트해야 한다.git pull --rebase origin developor
git fetch origin -> git rebase origin developrebase는 feature 브랜치의 변경사항을 develop 위로 다시 배치 하는 방식이다.
그래프는 아래와 같이 변한다.A --- B --- C --- X --- Y장점:
- merge commit X
- 히스토리 직관적
- PR이 깔끔
- 충돌이 조기에 발견되어 해결 쉬움
1️⃣ feature 브랜치를 생성하고 작업
git checkout -b feature/login2️⃣ develop이 바뀔 때마다 rebase 기반으로 최신화
git pull --rebase origin develop3️⃣ 작업 후 push
처음은git push origin feature/loginrebase 이후에는 대부분
git push --force-with-lease을 사용한다.
(⚠️ feature 브랜치는 개인 브랜치라 force push 해도 안전함)
리뷰어는 PR 브랜치를 로컬로 가져와서 반드시 확인해야한다.
git fetch origin git checkout feature/login git pull origin feature/login확인할 것들:
* 커밋이 깔끔한가? * 불필요한 merge commit은 없는가? * develop에서 정상적으로 분기했는가? * 테스트 코드는 통과하는가?히스토리 확인:
git log --oneline --graph --decorate
⚒️ 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가 쉬움 * 배포 시 기능 단위로 명확하게 포함 내용 확인 가능
기본 브랜치가 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
이렇게 하면 꼬였던 히스토리를 완전히 새 것처럼 깔끔하게 초기화할 수 있다.
🔥 개인(feature) 브랜치는 자유롭게 rebase 해도 된다.
-> 나만 쓰는 브랜치라 히스토리 바뀌어도 OK
❌ develop / main 같은 공용 브랜치는 절대 rebase 금지
-> 공용 브랜치를 rebase하면 모든 팀원 히스토리가 꼬인다.

Git 협업에서 가장 중요한 건 히스토리를 선형(linear)으로 유지하는 것이다.
* PR 리뷰 시간 감소 * 충돌 감소 * revert(되돌리기), 배포가 쉬움 * 팀 전체 생산성 증가앞으로 각 팀원이
git pull --rebase origin develop만 습관적으로 해줘도 Git 흐름은 믿을 수 없을 정도로 깔끔해진다.



