- Published on
Git rebase 충돌 자동해결 - rerere 설정·복구
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 브랜치에서 같은 파일을 건드리는 일이 잦으면 git rebase 는 거의 필연적으로 충돌을 만듭니다. 문제는 충돌 자체가 아니라, 비슷한 충돌을 여러 번 반복해서 해결하게 된다는 점입니다. 예를 들어 기능 브랜치를 오래 끌다가 메인 브랜치를 여러 번 따라가거나, 리베이스 도중 커밋을 쪼개고 순서를 바꾸면 동일한 충돌이 다시 등장합니다.
Git에는 이 반복 작업을 줄이기 위한 기능이 있습니다. 바로 rerere 입니다. 이름은 reuse recorded resolution 의 약자로, 한 번 해결한 충돌의 해결 결과를 기록해두었다가 다음에 유사한 충돌이 발생하면 자동으로 적용해줍니다.
이 글에서는 rerere 의 동작 방식, 설정 방법, 리베이스 중 실제 사용 흐름, 그리고 기록이 꼬였을 때 복구/초기화하는 방법까지 한 번에 정리합니다.
rerere가 해결해주는 문제
rerere 가 특히 유용한 상황은 아래와 같습니다.
- 장수 브랜치에서
rebase를 여러 번 수행하며 같은 충돌을 반복 - 커밋을
rebase -i로 정리(스쿼시, 픽 순서 변경)하면서 동일한 충돌이 재등장 - 체리픽/리베이스를 오가며 같은 패치가 여러 번 적용되는 흐름
- 대규모 리팩터링 중 충돌 해결 패턴이 거의 동일한 경우
반대로, 매번 충돌 양상이 크게 달라지는 파일(예: 자동 생성 코드, 포맷터가 자주 바꾸는 영역)에서는 기대 효과가 낮을 수 있습니다.
rerere 동작 원리(핵심만)
rerere 는 충돌이 발생했을 때 아래를 수행합니다.
- 충돌 난 파일의 충돌 전후 컨텍스트(공통 조상, ours, theirs) 를 기반으로 충돌 상태를 식별
- 사용자가 충돌을 해결하고
git add하면, 그 해결 결과를.git/rr-cache에 기록 - 이후 유사한 충돌이 다시 나타나면, 기록된 해결 결과를 찾아 워킹 트리에 자동 적용
중요한 점은, rerere 는 “커밋 단위”가 아니라 “충돌 조각(hunk) 단위”로 재사용을 시도한다는 것입니다. 그래서 같은 파일이라도 충돌 주변 문맥이 바뀌면 적용이 실패할 수 있습니다.
rerere 활성화(전역/저장소)
전역 설정(추천)
개인 개발 환경에서 항상 켜두는 방식입니다.
git config --global rerere.enabled true
선택 옵션으로 자동 업데이트도 켤 수 있습니다.
git config --global rerere.autoupdate true
rerere.autoupdate가true이면, rerere가 해결안을 적용한 뒤 해당 파일을 자동으로 스테이징(git add)까지 해주는 흐름이 더 잘 맞습니다.- 팀 규칙에 따라 자동 스테이징이 부담이라면
false로 두고 수동git add를 유지해도 됩니다.
특정 저장소에서만 켜기
git config rerere.enabled true
git config rerere.autoupdate true
rebase 중 rerere 사용 흐름(실전)
아래는 rebase 중 충돌이 났을 때 rerere가 어떻게 개입하는지의 전형적인 흐름입니다.
1) 리베이스 시작
git checkout feature/something
git fetch origin
git rebase origin/main
충돌이 나면 Git이 멈추고 충돌 파일을 표시합니다.
git status
2) 첫 번째 충돌은 평소처럼 해결
충돌 마커를 보고 수동으로 해결한 뒤:
git add path/to/file
git rebase --continue
이 시점에 rerere는 “이 충돌 패턴의 해결 결과”를 기록합니다.
3) 같은 패턴의 충돌이 다시 나오면 자동 적용
리베이스 중간에 유사한 충돌이 또 나오면, rerere가 기록을 찾아 적용합니다. rerere.autoupdate 를 켰다면 스테이징까지 되어 있을 수 있습니다.
확인은 아래처럼 합니다.
git status
만약 자동 적용된 파일이 있다면, 내용이 의도대로인지 꼭 확인하세요.
git diff
검증 후 계속 진행합니다.
git rebase --continue
rerere 기록 상태 확인과 디버깅
rerere가 어떤 파일을 기록/적용했는지 보기
git rerere status
기록된 해결안을 적용 시도(수동 트리거)
자동 적용이 기대대로 안 되는 경우, 수동으로 적용을 시도할 수 있습니다.
git rerere
rr-cache 위치
기록은 기본적으로 아래에 쌓입니다.
.git/rr-cache/
여기에는 충돌 조각별로 디렉터리가 생기고, 충돌 전후 버전 및 해결 결과가 저장됩니다.
rerere가 "자동해결"을 못하는 대표적인 이유
충돌 주변 문맥이 달라짐
- 같은 파일이라도 라인 이동/대규모 포맷 변경으로 인해 hunk 매칭이 실패할 수 있습니다.
한 번도 정상적으로 기록된 적이 없음
- 충돌을 해결했지만
git add를 하지 않고 다른 방식으로 진행(예: 체크아웃으로 덮어씀)하면 기록이 안 남습니다.
- 충돌을 해결했지만
기록이 오염됨(잘못된 해결을 기록)
- 급하게 해결하고 넘어갔다가, 그 해결이 다음 충돌에 그대로 재적용되며 문제를 키울 수 있습니다.
이 글의 후반부는 바로 3번을 다룹니다. “잘못 기록된 rerere를 어떻게 복구/초기화할 것인가”가 실무에서 꽤 중요합니다.
rerere 기록이 꼬였을 때: 복구/초기화 전략
1) 현재 리베이스 자체를 안전하게 되돌리기
우선 rerere 문제가 아니라 리베이스가 꼬인 것처럼 보일 때는, 리베이스를 중단하고 원상 복구하는 게 가장 안전합니다.
git rebase --abort
이후 브랜치 상태를 확인하고 다시 시도합니다.
2) 잘못 적용된 해결안만 되돌리고 다시 해결하기
rerere가 적용한 결과가 마음에 들지 않으면, 해당 파일을 충돌 상태로 되돌린 뒤 다시 해결하면 됩니다.
- 파일을 리베이스 진행 전 상태로 되돌리는 접근(상황별로 다름)
가장 흔한 패턴은, 충돌 파일을 다시 충돌 상태로 만들기보다는 “현재 단계에서 올바른 최종 결과”로 고친 후 git add 를 다시 하는 것입니다. rerere는 새로운 해결을 다시 기록할 수 있습니다.
# 파일을 올바르게 수정 후
git add path/to/file
그리고 계속 진행:
git rebase --continue
3) 특정 저장소의 rerere 기록을 통째로 초기화
“이 저장소에서 rerere 캐시가 전반적으로 오염됐다”면, .git/rr-cache 를 삭제하여 초기화할 수 있습니다.
rm -rf .git/rr-cache
그 다음, rerere는 다시 처음부터 학습합니다.
주의사항:
- 이 작업은 해당 로컬 저장소에서만 영향이 있습니다.
- 이후 반복 충돌 자동 적용 이점이 잠시 사라집니다.
4) rerere 기능 자체를 끄고 다시 켜기
기록을 지우기 전, 일시적으로 기능을 꺼서 원인 분리를 할 수도 있습니다.
git config rerere.enabled false
문제 해결 후 다시 켭니다.
git config rerere.enabled true
5) reflog 로 리베이스 전 커밋으로 복구
리베이스를 이미 끝냈는데 “결과가 이상하다”면, reflog 로 리베이스 전 지점으로 돌아갈 수 있습니다.
git reflog
원하는 시점의 해시로 리셋:
git reset --hard <commit-hash>
위 명령의 <commit-hash> 는 인라인 코드로 감쌌습니다. MDX 환경에서는 부등호가 그대로 노출되면 문제가 될 수 있어, 이런 표기는 항상 백틱 처리하는 습관이 안전합니다.
팀에서 rerere를 어떻게 운영할까
rerere 기록은 기본적으로 .git 아래 로컬에 저장되며, 원격 저장소로 공유되지 않습니다. 즉 “개인 생산성 기능”으로 보는 게 일반적입니다.
다만 팀 차원에서 고려할 포인트가 있습니다.
1) 리베이스 문화와의 궁합
- 리베이스를 적극적으로 쓰는 팀일수록
rerere효과가 큽니다. - 머지 중심 팀에서도 체리픽/핫픽스가 잦으면 도움이 됩니다.
2) 자동 스테이징(autoupdate) 정책
- 개인은
true가 편하지만, 실수로 스테이징된 채 넘어가는 것을 경계하는 팀이라면false가 나을 수 있습니다. - 타협안은 “개발자는 켜되,
rebase --continue전git diff로 확인”을 체크리스트화하는 것입니다.
3) 포맷터/정렬 도구와의 상호작용
코드 포맷터가 한 번에 대규모 라인 이동을 만들면 rerere 매칭이 깨질 수 있습니다. 리베이스 직전/직후에 포맷 커밋을 분리하거나, 포맷 변경을 메인 브랜치에 먼저 반영한 뒤 기능 브랜치를 따라가게 하는 전략이 충돌 비용을 줄입니다.
실전 예시: 반복 충돌을 rerere로 줄이는 리베이스 루틴
아래는 장수 브랜치에서 주기적으로 메인을 따라갈 때 추천하는 루틴입니다.
# 1) rerere 켜기(최초 1회)
git config --global rerere.enabled true
git config --global rerere.autoupdate true
# 2) 최신 메인 기준으로 리베이스
git fetch origin
git rebase origin/main
# 3) 충돌 발생 시
# - 첫 충돌은 정확히 해결하고 add
# - 이후 유사 충돌은 rerere가 자동 적용하므로 diff로 검증
git status
git diff
# 4) 완료 후 히스토리 점검
git log --oneline --decorate -n 20
핵심은 “처음 충돌을 제대로 해결해 rerere에 좋은 데이터를 먹인다”입니다. rerere는 마법이 아니라 캐시 기반 재사용이므로, 첫 기록의 품질이 곧 자동해결 품질입니다.
자주 묻는 질문
Q1. rerere를 켜면 충돌이 아예 안 나나요?
아니요. 충돌은 그대로 납니다. 다만 과거에 해결한 충돌과 유사한 패턴이면, 해결 결과를 자동으로 적용해 수동 작업량을 줄여줍니다.
Q2. rerere가 적용한 결과를 믿어도 되나요?
반드시 git diff 로 확인하는 습관이 필요합니다. 특히 리팩터링/대규모 변경 시에는 “유사해 보이지만 다른 의미”의 충돌이 생길 수 있습니다.
Q3. 로컬 rr-cache를 백업해두면 도움이 되나요?
개인적으로는 도움이 됩니다. OS 재설치나 개발 환경 초기화 시 rr-cache가 사라지면 학습이 초기화되기 때문입니다. 다만 팀 공유는 기본 설계가 아니어서, 공유하려면 별도 정책/도구가 필요합니다.
마무리: rerere는 리베이스의 반복 비용을 줄이는 보험
git rebase 를 자주 쓰는 개발자에게 충돌은 피할 수 없는 비용입니다. rerere 는 그 비용 중 “반복되는 수작업”을 줄여주는 매우 실용적인 기능입니다. 특히 장수 브랜치, 커밋 정리, 체리픽이 많은 레포에서는 체감이 큽니다.
다만 자동화 기능인 만큼, 잘못 기록된 해결이 누적되면 오히려 혼란을 키울 수 있습니다. 이때는 .git/rr-cache 초기화, rebase --abort, reflog 복구 같은 안전장치를 함께 기억해두면 운영이 훨씬 편해집니다.
추가로, CI나 배포 파이프라인에서 권한/인증 이슈로 작업이 꼬이는 경우도 비슷하게 “원인 분리와 복구 루틴”이 중요합니다. 관련해서는 GitHub Actions OIDC로 AWS 배포 권한 오류 해결 글도 함께 참고하면 문제 해결 흐름을 정리하는 데 도움이 됩니다.