- Published on
Git rebase 충돌을 자동 재사용 - rerere 설정법
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 브랜치에서 같은 파일을 자주 건드리는 팀이라면 git rebase 중 충돌(conflict)은 피할 수 없습니다. 문제는 같은 종류의 충돌을 매번 다시 푼다는 데 있습니다. 예를 들어, 장기 브랜치(feature)가 메인(main)에서 여러 번 리베이스될 때, 동일한 부분(헤더 import 정렬, 포맷팅, 공통 유틸 함수 시그니처 변경 등)에서 거의 같은 충돌이 반복됩니다.
Git에는 이런 반복 노동을 줄이기 위한 기능이 있습니다. 바로 rerere(reuse recorded resolution) 입니다. 한 번 충돌을 해결하면 Git이 그 해결 결과를 기록해 두었다가, 다음에 동일/유사한 충돌 패턴이 나타나면 자동으로 해결안을 재적용합니다. 이 글에서는 rerere가 동작하는 원리, rebase에서의 실제 사용 흐름, 팀/CI에서의 운영 방식, 그리고 흔한 함정까지 실전 관점에서 정리합니다.
rerere란 무엇이고 왜 rebase에 특히 유용한가
rerere는 “충돌난 파일의 충돌 조각(conflict hunks)”을 기반으로 충돌 전후의 컨텍스트를 해시로 기록하고, 사용자가 손으로 충돌을 해결해 커밋(혹은 rebase continue)할 때 그 해결 결과를 저장합니다. 이후 같은 충돌 조각이 다시 등장하면 Git이 .git/rr-cache/에 저장된 기록을 찾아 자동으로 머지 결과를 만들어 줍니다.
특히 rebase는 다음 이유로 rerere 효용이 큽니다.
- rebase는 커밋을 순서대로 재적용하므로, 앞 커밋에서 해결한 충돌이 뒤 커밋에서 또 발생하기 쉽습니다.
- 장기 브랜치가 main의 변경을 주기적으로 따라갈 때, 거의 동일한 충돌을 주기적으로 반복합니다.
- squash/reword/fixup을 섞어 히스토리를 정리할수록 동일 파일을 여러 번 건드려 충돌 재발 확률이 올라갑니다.
rerere 활성화(로컬) — 가장 안전한 시작
1) 현재 저장소에서만 켜기
git config rerere.enabled true
이 설정은 해당 저장소의 .git/config에만 적용됩니다. 먼저 로컬에서 효과를 검증하기에 가장 안전합니다.
2) 모든 저장소에서 기본으로 켜기(권장)
git config --global rerere.enabled true
팀에서 rebase를 자주 쓰고 충돌이 반복된다면 전역 설정으로 켜두는 편이 생산성이 좋습니다.
3) 자동 업데이트 옵션(rerere.autoupdate)
rerere가 충돌 해결안을 찾으면, 워킹 트리에 그 결과를 반영할지 여부를 제어합니다.
git config --global rerere.autoupdate true
true: 가능한 경우 자동으로 워킹 트리에 적용하고 스테이지 업데이트까지 시도합니다(상황에 따라 다름).false: 해결안 후보를 기록만 하고, 사용자가 직접 적용/확인해야 합니다.
실무에서는 autoupdate=true가 편하지만, 코드 스타일/포맷팅 툴이 강하게 개입하는 저장소라면 초기에 false로 두고 신뢰도를 확인한 뒤 켜는 것도 방법입니다.
rebase에서 rerere가 실제로 동작하는 흐름
rerere는 “충돌이 발생했을 때 자동으로 마법처럼 해결”되는 것이 아니라, 한 번은 사람이 해결해야 기록이 쌓이고, 그 다음부터 재사용됩니다.
시나리오: main을 따라가며 feature를 주기적으로 rebase
- feature 브랜치에서 rebase 수행
git checkout feature
git fetch origin
git rebase origin/main
- 충돌 발생 → 사람이 해결
git status
# conflict 난 파일 열어서 <<<<<<< ======= >>>>>>> 마커 해결
git add path/to/conflicted-file
- rebase 계속 진행(이 시점에 rerere가 해결안을 기록)
git rebase --continue
- 이후 다른 커밋을 재적용하는 과정에서 유사 충돌이 다시 발생하면, rerere가 기록을 찾아 자동으로 적용합니다.
이때 로그에 다음과 같은 메시지가 보일 수 있습니다.
Resolved '파일명' using previous resolution.- 또는 rerere 관련 메시지
rerere가 적용됐는지 확인하는 팁
git rerere status
- rerere가 기록/적용한 파일들을 확인할 수 있습니다.
또한 rebase 도중이라면:
git status
- 충돌이 “완전히 해소되어 add만 하면 되는 상태”인지
- 혹은 여전히 충돌 마커가 남았는지
를 확인하세요. rerere가 적용했더라도 100% 정답을 보장하지 않으므로 최종 검증은 필요합니다.
rerere 캐시의 정체: .git/rr-cache
rerere의 핵심 데이터는 저장소 내부의 다음 경로에 쌓입니다.
.git/rr-cache/
여기에는 충돌 조각의 식별자(해시)별로 디렉토리가 생기고, 대체로 다음 성격의 파일들이 저장됩니다.
- 충돌 당시의 “preimage”(충돌 마커 포함 상태)
- 사람이 해결한 “postimage”(해결 결과)
이 구조 덕분에 rerere는 “같은 충돌 조각”을 만나면 postimage를 재적용할 수 있습니다.
자주 쓰는 rerere 관련 명령어 모음
rerere 기록/적용 상태 보기
git rerere status
rerere가 가진 기록 목록 보기
git rerere
# 보통은 자동으로 호출되지만, 수동 실행도 가능
특정 충돌 기록 삭제(캐시 정리)
정확한 디렉토리 단위 삭제는 상황에 따라 다르지만, 원칙은 .git/rr-cache에서 해당 항목을 제거하면 됩니다. 다만 직접 삭제는 조심스럽게 하세요.
더 안전한 접근은 “잘못된 자동해결이 반복될 때” 해당 충돌을 다시 수동으로 올바르게 해결하고 기록을 덮어쓰는 것입니다.
실전 운영 팁: rerere를 ‘제대로’ 쓰는 방법
1) 충돌 해결 후에는 반드시 테스트/빌드로 검증
rerere는 텍스트 기반 재적용이므로, 다음 같은 경우 “컴파일은 되지만 의미가 틀린” 결과를 만들 수 있습니다.
- 함수 시그니처가 바뀌었는데 호출부가 미묘하게 잘못 합쳐짐
- import 순서/alias가 충돌 해결 과정에서 깨짐
- JSON/YAML에서 키가 중복되거나 들여쓰기가 망가짐
따라서 rebase 완료 후 최소한 다음을 권장합니다.
# 예시
./gradlew test
# 또는
npm test
2) 포맷터/린터가 강한 저장소는 rerere 기록이 더 가치 있음
pre-commit 훅이나 CI에서 포맷팅을 강제하면, 충돌 해결이 “사실상 정형화된 패턴”이 됩니다. 이런 경우 rerere는 특히 효율적입니다. 다만 포맷터 버전이 바뀌면 해결 결과가 달라질 수 있으니, 툴 체인을 고정(lock)하는 편이 좋습니다.
3) merge보다 rebase에서 체감이 큰 이유를 팀에 공유
팀 내에서 “rebase는 충돌 지옥”이라는 인식이 있으면, rerere를 켠 뒤 체감 개선(반복 충돌 자동해결)을 사례로 공유하는 것이 도입에 도움이 됩니다.
참고로 CI/운영 관점에서 반복 오류를 줄이는 접근은 Git 충돌뿐 아니라 인프라 트러블슈팅에서도 동일합니다. 예를 들어 캐시가 기대대로 동작하지 않는 원인을 체계적으로 쪼개는 방식은 GitHub Actions 캐시 안 먹힘 원인 7가지 같은 글의 문제 분해 방식과 결이 비슷합니다.
팀/CI에서 rerere를 공유할 수 있을까?
결론부터 말하면, 기본적으로 rerere 캐시는 로컬 저장소 내부 데이터이며, 일반적으로 원격 저장소에 공유하지 않습니다. .git/rr-cache는 버전 관리 대상이 아니고, 개인 작업 환경에 종속되기 때문입니다.
다만 다음과 같은 “공유 비슷한 운영”은 가능합니다.
- 충돌이 자주 나는 장기 브랜치의 담당자가 rerere로 반복 충돌을 빠르게 정리해 rebase를 끝내고, 결과를 push한다.
- 다른 개발자는 이미 정리된 히스토리를 pull/merge/rebase하여 충돌 빈도를 줄인다.
즉, rerere 자체를 공유하기보다는 충돌을 정리한 결과(커밋 히스토리)를 공유하는 방식이 현실적입니다.
흔한 함정과 디버깅 체크리스트
1) “rerere 켰는데 왜 자동 해결이 안 되지?”
- 처음 발생한 충돌은 당연히 사람이 풀어야 합니다(학습 데이터가 없음).
- 충돌 조각이 충분히 동일하지 않으면(컨텍스트가 달라짐) 매칭이 안 됩니다.
- 파일이 CRLF/LF 변환, 대규모 리포맷으로 라인이 크게 바뀌면 매칭률이 떨어집니다.
확인 명령:
git config --show-origin --get rerere.enabled
git config --show-origin --get rerere.autoupdate
git rerere status
2) “자동 적용됐는데 결과가 이상하다”
- rerere는 ‘이전의 내 해결’을 재사용합니다. 이전 해결이 잘못됐으면 계속 잘못됩니다.
- 그 사이 요구사항/코드 구조가 바뀌어 “그때의 해결”이 더 이상 맞지 않을 수 있습니다.
대응:
- 해당 충돌을 올바르게 다시 해결하고 기록을 갱신
- 필요하면
.git/rr-cache를 정리(주의해서)
3) rebase 도중 중단/재시도와의 관계
rebase를 하다가 중단하면 다음을 자주 씁니다.
git rebase --abort
# 또는
git rebase --continue
# 또는
git rebase --skip
rerere는 “충돌 해결 후 continue” 과정에서 기록이 쌓이므로, 충돌을 풀다가 abort만 반복하면 학습이 덜 될 수 있습니다. 물론 이미 기록된 캐시는 유지됩니다.
추천 설정 조합(개발자 로컬 기준)
아래 조합이 가장 무난합니다.
git config --global rerere.enabled true
git config --global rerere.autoupdate true
그리고 rebase를 자주 한다면, 충돌이 났을 때 “일단 침착하게 한 번 제대로 풀고 테스트까지 통과시키는 습관”이 rerere의 효율을 극대화합니다.
마무리: rerere는 ‘충돌을 없애는 기능’이 아니라 ‘반복을 줄이는 기능’
rerere는 만능 자동 병합기가 아닙니다. 하지만 rebase에서 반복되는 충돌을 다루는 데는 매우 현실적인 도구입니다. 한 번 잘 해결해 기록해 두면, 같은 유형의 충돌이 다시 나타날 때 해결 시간을 분 단위에서 초 단위로 줄여줍니다.
정리하면 다음 3가지만 기억하면 됩니다.
rerere.enabled=true로 켠다.- 충돌은 처음엔 사람이 정확히 해결하고
rebase --continue로 기록을 남긴다. - 자동 적용 결과도 항상 테스트로 검증한다.