- Published on
Git rebase 충돌 최소화 - rerere·autosquash 실전
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 브랜치에서 같은 파일을 자주 만지는 팀이라면, git rebase는 히스토리를 깔끔하게 만드는 대신 충돌 비용을 지불하게 됩니다. 특히 장수 브랜치(long-lived branch)나, 리뷰 반영을 위해 같은 구간을 여러 번 고치는 작업에서는 “비슷한 충돌을 계속 다시 푸는” 상황이 반복됩니다.
이 글은 그 반복을 줄이는 두 가지 무기, rerere와 autosquash를 실전 관점에서 묶어 설명합니다.
rerere는 “한 번 해결한 충돌”의 해결 결과를 기록해두고, 다음에 같은 충돌이 나오면 자동으로 재적용합니다.autosquash는fixup!/squash!커밋을 기준 커밋 옆으로 자동 배치해, 인터랙티브 리베이스에서 정리 비용을 줄입니다.
둘을 같이 쓰면, “충돌 해결”과 “커밋 정리”가 동시에 자동화되어 rebase의 체감 난이도가 크게 내려갑니다.
rebase 충돌이 반복되는 구조부터 이해하기
rebase는 내 커밋들을 다른 베이스 위로 “다시 재생(replay)”합니다. 즉, 내 커밋이 N개면 패치 적용이 N번 일어나고, 그 과정에서 충돌이 발생할 수 있습니다.
반복 충돌은 보통 다음 패턴에서 발생합니다.
- 같은 파일(특히 설정, 라우팅, 공통 컴포넌트)을 여러 브랜치가 동시에 수정
- 리뷰 반영으로 “같은 줄 근처”를 여러 번 수정하며 커밋이 누적
- 장수 브랜치가 메인 브랜치와 멀어져, 동일 충돌이
rebase때마다 재현
이때 rerere는 “충돌 해결 결과”를 기억해 재사용하고, autosquash는 “리뷰 반영 커밋”을 자동 정리해 rebase 횟수와 실수 가능성을 함께 줄입니다.
rerere: 한 번 푼 충돌을 다시 풀지 않기
rerere는 reuse recorded resolution의 약자입니다. 충돌이 발생했을 때 사람이 해결한 결과를 Git이 기록해두고, 이후 동일하거나 충분히 유사한 충돌이 다시 발생하면 그 해결을 자동으로 적용합니다.
rerere 활성화
전역으로 켜두는 편이 일반적으로 유리합니다.
# 전역 활성화
git config --global rerere.enabled true
# 자동으로 staging까지 하고 싶다면(팀 정책에 따라 선택)
git config --global rerere.autoupdate true
rerere.enabled가 핵심입니다.rerere.autoupdate는 재적용된 해결을 자동으로git add상태로 만들어줍니다. 편하지만, 자동 적용이 항상 정답은 아니므로 팀 합의가 있으면 켜는 것을 권합니다.
rerere가 실제로 동작하는 흐름
- rebase 중 충돌 발생
git rebase main
충돌 파일을 열어 수동 해결
해결 후 staging
git add path/to/conflicted-file
- rebase 계속
git rebase --continue
이때 rerere는 충돌의 “이전 상태(충돌 마커 포함 상태)”와 “해결된 결과”를 쌍으로 저장합니다. 다음 번에 유사 충돌이 나오면 자동으로 해결본을 적용합니다.
rerere 상태 확인과 관리
rerere가 어떤 충돌을 기억하고 있는지 보려면 다음을 사용합니다.
git rerere status
기록된 해결을 확인하려면:
git rerere diff
기록을 삭제하고 싶다면(잘못된 해결을 학습했거나, 정책상 기록을 비우고 싶을 때):
# 특정 항목 삭제는 내부 구조를 알아야 해서 번거롭습니다.
# 안전한 방법은 rerere 캐시 디렉터리를 통째로 비우는 것입니다.
rm -rf .git/rr-cache
주의할 점:
rr-cache는 저장소 로컬에 있습니다. 즉, 개인 PC에서 학습한 해결이 자동으로 팀에 공유되지는 않습니다.- 다만 동일 개발자가 같은 저장소에서 반복 rebase를 할 때 효과가 매우 큽니다.
rerere를 특히 추천하는 상황
- 메인 브랜치가 빠르게 변하고, 기능 브랜치가 며칠 이상 지속되는 팀
- 대규모 리팩터링 중에 같은 파일에서 충돌이 반복되는 경우
git rebase --rebase-merges같은 복잡한 rebase를 자주 수행하는 경우
autosquash: fixup과 squash로 커밋 정리를 자동화하기
리뷰를 받다 보면 “이 커밋에 오타 수정만 추가”, “이 커밋에 테스트만 추가” 같은 후속 커밋이 생깁니다. 이를 매번 인터랙티브 리베이스에서 손으로 옮기고 squash하는 과정은 번거롭고 실수도 잦습니다.
autosquash는 커밋 메시지가 fixup! 대상커밋메시지 또는 squash! 대상커밋메시지 형태라면, 인터랙티브 리베이스 시작 시점에 자동으로 대상 커밋 바로 아래로 이동시키고 액션도 자동 지정합니다.
fixup 커밋 만들기
가장 안전하고 편한 방법은 --fixup 옵션입니다.
# 특정 커밋에 대한 fixup 커밋 생성
git commit --fixup <commit-hash>
위 명령은 커밋 메시지를 자동으로 fixup! ... 형태로 만들어줍니다.
이미 커밋을 만들어버렸다면 메시지를 수정해도 됩니다.
git commit --amend
# 메시지를 fixup! ... 형태로 변경
MDX 렌더링 환경에서 commit-hash 같은 표기는 문제 없지만, 꺾쇠는 반드시 코드로 감싸야 합니다. 위 예시의 <commit-hash>는 코드 블록 내부이므로 안전합니다.
autosquash로 인터랙티브 리베이스 실행
# 기준 브랜치(main)까지의 내 커밋을 정리
git rebase -i --autosquash main
그러면 편집기가 열릴 때, fixup! 커밋들이 자동으로 타겟 커밋 아래로 이동하고 pick이 fixup으로 바뀌어 있습니다.
autosquash를 기본값으로 켜기
매번 옵션을 붙이기 싫다면:
git config --global rebase.autosquash true
이후에는 git rebase -i main만 해도 autosquash가 적용됩니다.
rerere와 autosquash를 같이 쓸 때의 시너지
둘은 서로 다른 문제를 해결합니다.
autosquash는 “불필요한 커밋 개수”와 “정리 작업”을 줄여 rebase 자체를 단순화합니다.rerere는 rebase 과정에서 발생하는 “반복 충돌 해결”을 자동화합니다.
함께 쓰면 다음 효과가 큽니다.
- 리뷰 반영 커밋이 정리되어 rebase 대상 커밋 수가 줄어듭니다.
- 그럼 충돌이 날 수 있는 패치 적용 횟수도 줄어듭니다.
- 남은 충돌은
rerere가 재사용해 해결 시간을 더 줄입니다.
즉, 충돌 빈도와 충돌 해결 비용을 동시에 낮춥니다.
실전 워크플로 예시
다음은 메인 브랜치가 빠르게 변하는 팀에서 자주 쓰는 패턴입니다.
1) 기능 브랜치에서 작업하며 fixup으로 리뷰 반영
# 기능 개발
...
git commit -m "Add payment validation"
# 리뷰에서 지적된 부분을 같은 커밋에 붙이고 싶을 때
git add .
git commit --fixup HEAD
# 또 다른 지적은 특정 커밋에 붙이기
git commit --fixup <some-commit-hash>
2) 최신 main을 반영하며 rebase
git fetch origin
git rebase origin/main
충돌이 나면 해결하고 계속 진행합니다. 이때 rerere가 켜져 있으면 다음번 유사 충돌에서 자동 해결될 가능성이 높습니다.
3) PR 올리기 전 커밋 정리
git rebase -i --autosquash origin/main
fixup! 커밋이 자동으로 정리되고, 히스토리가 깔끔해집니다.
4) 강제 푸시는 안전장치와 함께
rebase 후에는 히스토리가 바뀌므로 푸시가 필요합니다.
git push --force-with-lease
--force대신--force-with-lease를 권합니다. 원격이 내가 예상한 상태일 때만 강제 푸시가 진행되어 사고를 줄입니다.
자주 하는 실수와 예방책
rerere가 “틀린 해결”을 재적용하는 경우
충돌이 “겉으로 비슷하지만 의미가 다른” 상황이면, rerere가 과거 해결을 적용해 논리 버그를 만들 수 있습니다.
예방책:
- 자동 적용된 파일이라도 diff를 꼭 확인
git status
git diff
- 이상하면
git checkout -- path/to/file로 되돌린 뒤 수동 해결 - 반복적으로 잘못 학습되면
.git/rr-cache를 비우고 다시 학습
autosquash가 엉뚱한 타겟에 붙는 경우
fixup!은 커밋 메시지를 기반으로 매칭합니다. 메시지가 바뀌었거나, 유사한 메시지가 여러 개면 의도와 다르게 붙을 수 있습니다.
예방책:
git commit --fixup <hash>를 우선 사용(메시지 의존도를 낮춤)- 인터랙티브 리베이스 화면에서 최종 순서를 사람이 한번 검토
팀에서 rebase 정책이 섞여 혼란이 생기는 경우
- 어떤 팀원은 merge, 어떤 팀원은 rebase를 선호하면 히스토리 규칙이 흔들립니다.
- 특히 PR 단계에서 “커밋을 정리해 달라”는 요구가 반복되면 생산성이 떨어집니다.
권장:
- 개인 브랜치에서는 rebase + autosquash를 기본으로
- 공유 브랜치(여러 명이 함께 푸시하는 브랜치)에서는 rebase를 제한하거나, 강제 푸시 규칙을 명확히
리베이스가 자주 실패하는 CI 환경에서의 팁
리베이스 자체는 로컬에서 이뤄지지만, 결과적으로 충돌/히스토리 정리가 덜 된 브랜치는 CI를 불안정하게 만들 수 있습니다. 예를 들어 캐시가 꼬인 상태에서 여러 번 강제 푸시가 반복되면 증상이 더 복잡해 보이기도 합니다.
- CI 캐시가 문제를 가리는 상황은 GitLab CI 캐시 꼬임 - 빌드 완전 초기화 가이드처럼 “원인을 분리”해 보는 접근이 도움이 됩니다.
- 재시도/백오프처럼 자동화가 사람의 반복 작업을 줄이는 패턴은 Git 워크플로에도 그대로 적용됩니다. 유사한 관점의 글로 OpenAI 429 RateLimitError 재시도·백오프 설계를 함께 참고해도 좋습니다.
추천 설정 요약
개인 개발 환경 기준으로, 다음 조합이 가장 무난합니다.
# 충돌 해결 재사용
git config --global rerere.enabled true
# autosquash 기본 적용
git config --global rebase.autosquash true
# rebase 후 강제 푸시는 항상 안전하게(습관)
# git push --force-with-lease
선택 옵션:
# rerere가 적용한 결과를 자동 stage
git config --global rerere.autoupdate true
마무리
git rebase를 “충돌이 무서운 명령”에서 “히스토리를 다듬는 일상 도구”로 바꾸는 핵심은 반복 작업을 줄이는 것입니다. rerere는 충돌 해결을 학습해 재사용하고, autosquash는 리뷰 반영 커밋을 자동으로 정리해 rebase의 복잡도를 낮춥니다.
둘을 함께 켜두면, 같은 충돌을 여러 번 푸는 시간과 커밋 정리에 쓰는 집중력이 크게 줄어듭니다. 그 절약된 에너지를 코드 품질과 설계에 쓰는 것이, 결국 팀 생산성을 가장 크게 올립니다.