Published on

Git rebase 충돌 자동 해결 - rerere 실무 설정

Authors

서론

git rebase를 자주 쓰는 팀이라면 “비슷한 충돌을 또 푸는” 일이 반복됩니다. 예를 들어 develop에서 기능 브랜치를 오래 끌고 가다가 매번 같은 파일의 같은 구간이 충돌 나고, 해결 방식도 늘 동일한 경우가 많습니다. 이때 Git의 rerere(reuse recorded resolution) 기능을 켜두면, 한 번 해결한 충돌을 Git이 기록해두었다가 다음에 동일/유사 충돌이 발생했을 때 자동으로 해결안을 재적용합니다.

rerere는 마법이 아니라 “충돌 난 전/후 상태를 해시로 저장해 두고 재사용”하는 메커니즘입니다. 잘 쓰면 rebase 시간이 체감상 크게 줄어들지만, 팀 정책/리포지토리 상태에 따라 부작용도 생길 수 있어 올바른 설정과 운영 규칙이 중요합니다.

이 글에서는 rerere의 동작 원리, 개인/팀에서의 권장 설정, rebase 워크플로우에 녹이는 방법, 그리고 실무에서 자주 겪는 함정과 점검 방법을 정리합니다.

rerere가 해결하는 문제: “반복 충돌”

다음 상황에서 rerere 효과가 큽니다.

  • 장수 브랜치(오래 유지되는 feature/hotfix)에서 rebase를 반복
  • develop/main에서 리팩터링이 잦고, 기능 브랜치가 자주 따라가야 함
  • 포맷터/린터 적용으로 동일 파일의 동일 영역에서 충돌이 반복
  • 동일한 충돌 패턴이 여러 커밋에 걸쳐 연쇄적으로 발생(특히 rebase --onto)

반대로, 충돌이 매번 “의미적으로” 다르게 해결되어야 하는 영역(예: 요구사항이 바뀌어 선택지가 달라지는 로직)이라면 rerere가 자동 적용한 결과를 그대로 믿으면 위험합니다. rerere는 정답을 추론하지 않고, 과거에 사용자가 선택한 해결안을 재사용할 뿐입니다.

rerere 동작 원리(핵심만)

rerere는 충돌이 발생했을 때:

  1. 충돌 난 파일의 충돌 마커(<<<<<<<, =======, >>>>>>>) 를 포함한 상태를 수집
  2. 충돌의 “우리/그들” 버전 조각을 기반으로 ID(해시) 를 생성
  3. 사용자가 충돌을 해결하고 git add 하면, 그 해결 결과를 .git/rr-cache/에 저장
  4. 이후 동일한 충돌 ID가 다시 나타나면, 저장된 해결 결과를 워킹트리에 자동 적용

즉, rerere는 “파일 전체”가 아니라 충돌 덩어리(hunk) 단위로 재사용합니다. 그래서 파일의 다른 부분이 바뀌어도 충돌 조각이 유사하면 적용될 수 있습니다.

실무 권장 설정: 개인 기본값

1) rerere 활성화

가장 기본은 아래 한 줄입니다.

git config --global rerere.enabled true

이후 충돌을 한 번 해결하고 git add 하면 기록이 쌓입니다.

2) 자동 업데이트(권장)

rerere는 기본적으로 “적용 가능한 해결안이 있으면 적용”하지만, 상황에 따라 기록을 더 잘 쌓게 하려면 autoupdate를 켜는 편이 실무에서 편합니다.

git config --global rerere.autoupdate true
  • autoupdate=true: rerere가 해결안을 적용한 뒤, 해당 파일을 자동으로 stage까지 해주려는 동작을 포함합니다(상황에 따라 다르게 체감될 수 있음).
  • 팀에 따라 “자동 stage는 싫다”면 false로 두고, 적용만 받고 직접 검토 후 git add 하는 방식도 가능합니다.

3) rebase 시 충돌 재현을 줄이는 보조 옵션

rerere 자체 옵션은 아니지만, rebase 경험을 개선하는데 자주 같이 씁니다.

# rebase 중 stash 자동 처리(로컬 변경이 있을 때)
git config --global rebase.autoStash true

# 충돌 시 3-way merge를 더 잘 활용(상황에 따라 유용)
git config --global merge.conflictStyle zdiff3
  • merge.conflictStyle=zdiff3는 충돌 마커에 “베이스” 컨텍스트가 더 보여서, 사람이 검토할 때 실수가 줄어듭니다.

팀/조직에서의 운영 포인트: rr-cache를 공유할 것인가?

결론부터: 보통은 “공유하지 않음”이 안전

rerere 캐시는 기본적으로 .git/rr-cache/에 저장되며, Git이 자동으로 커밋/푸시하는 대상이 아닙니다. 이를 팀끼리 공유하면 모두가 같은 충돌을 더 빨리 해결할 수 있을 것 같지만, 실무에서는 다음 리스크가 있습니다.

  • 누군가의 “임시 해결”이 팀 표준처럼 전파될 수 있음
  • 충돌 해결은 종종 도메인 의사결정(어느 로직을 살릴지)이 포함되는데, 캐시 공유는 그 의사결정의 맥락을 전달하지 못함
  • 다른 브랜치/다른 히스토리에서 해시가 우연히 맞아 잘못 적용될 가능성(낮지만 0은 아님)

따라서 일반적으로는:

  • 개인 로컬에서 rerere를 활성화하고,
  • PR 리뷰/테스트로 결과를 검증하며,
  • “반복 충돌”을 개인 생산성 향상 도구로 활용

하는 접근이 무난합니다.

예외: 대규모 모노레포 + 중앙 머지 담당

중앙에서 머지/리베이스를 담당하는 소수의 인원이 있고, 충돌 해결이 표준화되어 있으며, CI가 강력한 조직이라면 rr-cache 공유를 고려할 수 있습니다. 다만 이 경우에도 rr-cache를 그대로 버전관리하기보다는 “머지 봇/전담 머신의 캐시”로 운영하는 편이 일반적입니다.

rebase 워크플로우에 rerere 녹이기

1) 기본 rebase 흐름

# 최신 main을 기준으로 feature 브랜치를 재정렬
git fetch origin
git checkout feature/my-work
git rebase origin/main

충돌이 나면:

# 충돌 해결(에디터/머지툴)
# ...

git status
# 해결 완료한 파일 stage
git add path/to/conflicted-file

# rebase 계속
git rebase --continue

이때 rerere가 켜져 있으면, 처음 한 번 해결한 충돌은 rr-cache에 기록되고, 이후 같은 패턴의 충돌이 등장하면 자동으로 적용됩니다.

2) “연쇄 충돌”에서 진가가 나오는 패턴

리베이스 중 다음 커밋에서도 똑같은 파일/구간이 다시 충돌하는 경우가 많습니다.

  • 커밋 A: 함수 시그니처 변경
  • 커밋 B: 같은 함수 호출부 수정
  • main: 이미 다른 방식으로 함수가 바뀜

이때 첫 충돌을 사람이 정확히 풀고 나면, B에서 발생하는 유사 충돌은 rerere가 상당 부분 자동으로 풀어줍니다.

3) rerere가 적용됐는지 확인하는 방법

rebase 도중 메시지로 힌트를 주는 경우도 있지만, 가장 확실한 건 상태 확인입니다.

git status
  • 충돌 파일이 “both modified”에서 사라지고 stage되어 있으면(autoupdate 켠 경우) rerere 적용 가능성이 큽니다.
  • 그래도 반드시 git diff로 결과를 확인하세요.

실무에서 자주 하는 실수와 방지책

1) “자동 해결”을 무검토로 넘김

rerere는 과거 해결안을 그대로 재사용합니다. 과거의 해결이 지금도 옳다는 보장은 없습니다.

권장 습관:

# rebase 중간중간 결과 확인
git diff

# 커밋 단위 확인(리베이스라면 HEAD가 계속 변함)
git show --stat

2) 큰 리팩터링 직후에는 캐시가 오히려 혼란을 줄 수 있음

대규모 리팩터링(파일 이동/함수 분해/포맷 전면 적용) 이후에는 충돌 패턴이 “비슷해 보이지만 의미가 달라지는” 케이스가 늘어납니다. 이 시기에는 rerere 적용 결과를 더 엄격히 리뷰하거나, 필요하면 rerere를 일시적으로 끄는 것도 방법입니다.

# 현재 리포지토리에서만 rerere 끄기
git config rerere.enabled false

3) rr-cache가 비대해짐

오래 쓰다 보면 .git/rr-cache가 커질 수 있습니다. 일반적으로 큰 문제는 아니지만, 디스크/백업 정책이 빡빡한 환경에서는 점검 대상입니다.

  • 주기적으로 .git 디렉터리 크기 확인
  • 필요 시 캐시 정리(정리 전에는 왜 정리하는지 합의가 필요)

rerere와 함께 알아두면 좋은 “되돌리기” 안전장치

rebase는 히스토리를 바꾸므로 실수했을 때 복구 루틴이 중요합니다. rerere로 충돌이 자동 적용되면 “내가 뭘 했는지” 감각이 흐려질 수 있어, 복구 방법을 더 확실히 알고 있어야 합니다.

  • rebase 후 강제 푸시까지 갔는데 꼬였을 때는 reflog가 마지막 보루입니다.
  • 관련 내용은 아래 글을 함께 보면 좋습니다.

Git rebase 후 강제푸시 충돌? reflog로 복구하기

CI/CD 환경에서의 팁: 충돌을 줄이는 운영 전략

rerere는 “충돌 해결 비용”을 줄이지만, 애초에 충돌이 덜 나게 운영하는 것도 중요합니다.

  • 브랜치 수명을 짧게: 작은 단위로 자주 머지
  • 포맷터/린터는 한 번에 몰아서 적용(대규모 포맷 커밋은 별도 PR로)
  • GitHub Actions에서 배포/머지 타이밍이 꼬이면 불필요한 리베이스가 늘어납니다. 동시성 제어도 같이 챙기면 좋습니다.

GitHub Actions 동시성 꼬임으로 배포 겹침 막기

추천 실무 설정 예시(복붙용)

아래는 “개인 개발 머신에서 rerere를 적극 활용”하는 기준의 예시입니다.

# rerere 켜기
git config --global rerere.enabled true

# 자동 적용/업데이트(원치 않으면 false)
git config --global rerere.autoupdate true

# rebase 편의
git config --global rebase.autoStash true

# 충돌 마커에 base까지 보여서 판단 쉽게
git config --global merge.conflictStyle zdiff3

# (선택) 기본 브랜치 이름에 맞게 pull 전략을 명확히
# git config --global pull.rebase true

추가로, 특정 리포지토리에서만 켜고 싶다면 --global을 빼고 해당 repo에서만 설정하면 됩니다.

결론

rerere는 rebase를 많이 하는 팀에서 “반복 충돌”을 체계적으로 줄여주는 기능입니다. 핵심은 단순합니다.

  • 한 번 제대로 해결하면
  • Git이 그 해결을 기록하고
  • 다음부터는 자동 재적용한다

다만 자동 적용은 어디까지나 과거의 선택을 재사용하는 것이므로, git diff/테스트/리뷰로 결과를 검증하는 습관이 함께 가야 합니다. 개인 환경에서 우선 활성화해 체감 효과를 확인한 뒤, 팀 워크플로우(리베이스 빈도, 브랜치 정책, CI 강도)에 맞춰 운영 규칙을 다듬는 것이 가장 현실적인 도입 방식입니다.