Published on

Git rebase 충돌 자동해결 - rerere 실무 가이드

Authors

서로 다른 브랜치에서 같은 파일을 자주 만지는 팀이라면 git rebase는 생산성을 올리는 도구인 동시에, 반복 충돌의 늪이 되기도 합니다. 특히 장수 브랜치(long-lived branch)나, 릴리즈 브랜치와 기능 브랜치를 오가며 체리픽/리베이스를 반복하는 흐름에서는 “어제도 풀었던 그 충돌”을 오늘 또 푸는 일이 흔합니다.

이때 Git의 rerere(reuse recorded resolution)는 꽤 강력한 해법입니다. 한 번 해결한 충돌을 Git이 기록해두고, 다음에 동일/유사한 충돌이 발생하면 해결 결과를 자동으로 재적용합니다. 즉, 사람이 반복해서 하던 머지/리베이스 충돌 해결을 Git이 재사용하게 만드는 기능입니다.

아래에서는 rerere의 동작 원리, 설정, 실무 운영 패턴, 그리고 “자동화가 오히려 위험해지는 순간”까지 정리합니다.

rerere란 무엇인가: ‘충돌 해결을 캐시’하는 Git

rerere는 충돌이 발생했을 때 만들어지는 **충돌 전 상태(ours/theirs)**와 사용자가 선택한 해결 결과를 쌍으로 저장합니다. 이후 Git이 동일한 충돌 패턴을 감지하면, 저장된 해결 결과를 워킹트리에 적용해 충돌을 줄입니다.

핵심 포인트는 다음과 같습니다.

  • 충돌이 발생해야 학습합니다. (충돌이 없으면 기록할 것도 없음)
  • 한 번 사람이 해결하면, 다음부터 Git이 해결안을 재적용합니다.
  • rebase뿐 아니라 merge, cherry-pick 등 충돌이 생기는 대부분의 작업에서 동작합니다.

반복 충돌의 대표 사례는 다음과 같습니다.

  • package-lock.json, Podfile.lock처럼 자동 생성/정렬되는 파일
  • 설정 파일에서 동일 라인이 여러 브랜치에서 자주 수정되는 경우
  • 리팩토링 브랜치와 기능 브랜치가 장기간 병렬로 진행되는 경우

예를 들어 iOS에서 Podfile.lock 충돌은 빈번한데, 이런 유형은 한 번 해결 방식이 정해지면 반복되는 경향이 큽니다. (관련해서는 Flutter iOS 빌드 실패 - Podfile.lock 충돌 해결 가이드도 함께 참고하면 맥락이 잘 맞습니다.)

rerere 켜기: 전역 설정 vs 저장소 설정

전역으로 켜기(추천)

대부분 개발자 PC에서는 전역으로 켜도 이점이 큽니다.

git config --global rerere.enabled true

추가로 자동으로 적용까지 하게 하려면(대부분 기본 동작이지만 명시적으로):

git config --global rerere.autoupdate true
  • rerere.enabled: 기록/재사용 기능 활성화
  • rerere.autoupdate: 재사용 가능한 해결안이 있으면, 인덱스에 자동 업데이트해 충돌을 더 빨리 정리

특정 저장소에서만 켜기

레포 성격상(예: 매우 민감한 리포지토리) 전역 적용이 부담되면 레포 단위로 켭니다.

git config rerere.enabled true
git config rerere.autoupdate true

실무 시나리오: rebase 중 충돌을 ‘학습’시키고 자동화하기

가장 흔한 흐름은 다음과 같습니다.

  1. rebase 수행 중 충돌 발생
  2. 사람이 충돌 해결
  3. git add로 해결된 파일 스테이징
  4. git rebase --continue
  5. 이후 동일한 충돌이 다시 나타나면 Git이 자동으로 해결을 적용

예시: 기능 브랜치를 main 위로 rebase

git checkout feature/login
git fetch origin
git rebase origin/main

충돌이 나면 파일을 열어 해결하고:

git status
# both modified: src/auth.ts

# 충돌 해결 후

git add src/auth.ts
git rebase --continue

이때 rerere가 켜져 있다면 Git은 다음을 수행합니다.

  • 충돌 당시의 ours/theirs 조각과 최종 해결본을 기록
  • 다음에 유사한 충돌이 재현되면 자동으로 해결본을 적용

rerere가 실제로 적용됐는지 확인

rebase 도중 “자동으로 해결을 적용했다”는 메시지가 보이기도 하지만, 명시적으로 확인하고 싶다면:

git rerere status

또는 기록된 해결안을 보고 싶다면:

git rerere diff

상황에 따라 rerere diff는 “어떤 충돌에 대해 어떤 해결이 재사용되려 하는지”를 파악하는 데 도움이 됩니다.

rerere 저장 위치와 팀 공유 전략

rerere 기록은 기본적으로 로컬 저장소의 .git/rr-cache/ 아래에 저장됩니다. 즉, 아무 설정 없이 쓰면 “내 PC에서만 똑똑해지는 기능”입니다.

실무에서는 두 가지 전략이 있습니다.

1) 개인 생산성 도구로만 사용(가장 안전)

  • 장점: 팀 정책/보안/일관성 고려가 거의 필요 없음
  • 단점: 팀 전체가 같은 충돌을 반복해서 겪을 수 있음

대부분 조직에서 이 방식만으로도 체감이 큽니다. 특히 lockfile이나 기계 생성 파일 충돌은 개인 단위로도 반복 빈도가 높습니다.

2) rr-cache를 팀에 공유(주의해서)

rr-cache를 버전 관리에 올려 공유하는 방식은 가능은 하지만, 다음 이슈가 있습니다.

  • 레포마다 충돌 패턴이 다르고, 잘못된 해결이 전파될 수 있음
  • “이 해결이 항상 옳다”는 보장이 없는데 자동 적용되면 위험
  • 개인별 Git 버전/설정 차이로 재현성이 흔들릴 수 있음

그래서 보통은 공유를 기본값으로 두지 않고, 아래처럼 제한적으로 접근합니다.

  • 특정 디렉토리(예: lockfile)에서만 공유를 고려
  • CI에서 rebase/merge를 수행하는 봇 계정에만 rr-cache를 유지(캐시 볼륨)
  • 공유 전에는 반드시 코드리뷰/검증을 거친 해결만 축적

rerere가 특히 잘 먹히는 충돌 유형

1) lockfile / 정렬 파일

  • package-lock.json, yarn.lock, pnpm-lock.yaml
  • Podfile.lock
  • 코드 포맷터가 정렬한 import/order 변경

이런 파일은 충돌이 “문맥적으로 동일”하게 반복되는 경우가 많아 rerere가 잘 재사용합니다.

2) 반복되는 리팩토링 충돌

예를 들어 src/api/client.ts를 리팩토링한 브랜치와, 그 파일을 계속 수정하는 기능 브랜치가 오랫동안 분기되어 있으면 충돌이 연속적으로 발생합니다. rerere는 “한 번 정한 합의(해결 방식)”를 계속 재적용할 수 있어 피로도를 줄입니다.

3) 체리픽을 반복하는 릴리즈 운영

릴리즈 브랜치에 핫픽스를 여러 개 체리픽하고, 다시 main에 역체리픽/리베이스하는 과정에서 같은 충돌이 반복됩니다. 이때 rerere는 운영 비용을 크게 줄입니다.

주의점: 자동 해결이 ‘항상’ 정답은 아니다

rerere는 문맥을 이해하지 않습니다. 충돌 패턴이 유사하면 해결을 적용할 뿐입니다. 그래서 아래 케이스에서는 특히 조심해야 합니다.

1) 해결 방식이 상황에 따라 달라져야 하는 충돌

예:

  • 특정 플래그 값은 릴리즈마다 달라야 함
  • 환경별 설정이 브랜치 정책에 따라 달라야 함

이런 충돌을 rerere가 예전 해결로 덮어버리면, 빌드/런타임에서 더 큰 문제가 터질 수 있습니다.

2) “충돌은 같아 보이지만 의미가 바뀐” 경우

리팩토링으로 함수 시그니처가 바뀌었는데, 과거 해결안을 그대로 적용하면 컴파일은 되더라도 로직이 틀어질 수 있습니다.

3) 자동 적용 후 검증을 생략하는 습관

rerere가 적용됐더라도 최소한 다음은 확인하는 습관이 좋습니다.

git diff --stat
# 또는
npm test
# 또는
make test

성능/캐시 관점에서 “어떤 변경이 재사용되는지”를 이해하는 습관은 다른 영역에서도 도움이 됩니다. 예를 들어 Docker에서 캐시가 왜 무효화되는지 이해하면 빌드 시간을 줄일 수 있듯이(Docker 빌드 캐시가 무효화되는 원인 7가지), rerere도 “무엇이 재사용되고 무엇이 새로 발생하는지”를 이해할수록 효과가 커집니다.

실전 운영 팁: rebase 워크플로우에 rerere를 녹이는 법

1) rebase 전에 rerere를 켰는지 확인

git config --get rerere.enabled

출력이 없다면 꺼진 상태일 수 있습니다.

2) 충돌 해결 후에는 ‘작게’ 커밋/continue

충돌 해결을 한 번에 너무 많이 쌓아두면, rerere가 학습하더라도 나중에 원인 파악이 어려워집니다. rebase 중에는 충돌 단위를 작게 유지하고, 각 단계에서 테스트를 돌리는 편이 안전합니다.

3) “이 충돌은 자동화하면 위험하다”를 분류

팀 내에서 다음과 같은 파일은 rerere 적용 후 더 엄격히 리뷰하는 규칙을 둘 수 있습니다.

  • 권한/인증 관련 설정
  • 배포 파이프라인 YAML
  • DB 마이그레이션

특히 인증/권한/토큰 영역은 사소한 충돌 해결 실수가 큰 장애로 이어질 수 있습니다. (예: 토큰 만료/권한 문제 트러블슈팅 맥락은 AWS STS 토큰 만료로 403? IRSA·AssumeRole 점검 같은 글과 결이 비슷합니다.)

자주 쓰는 명령 모음

rerere 켜기

git config --global rerere.enabled true
git config --global rerere.autoupdate true

rerere 상태/차이 확인

git rerere status
git rerere diff

rebase 중 충돌 해결 루틴

git rebase origin/main
# 충돌 해결

git add <resolved-files>
git rebase --continue

기록 초기화(문제 해결안이 잘못 학습됐을 때)

특정 충돌 해결이 잘못 저장되어 계속 재적용된다면, 로컬 rr-cache를 지우는 선택지도 있습니다. 다만 이는 “학습 데이터 전체 삭제”라 신중해야 합니다.

rm -rf .git/rr-cache

레포 전체가 아니라 특정 항목만 지우는 것도 가능하지만(해시 디렉토리 단위), 실무에서는 원인 파악이 어려우면 전체 삭제가 더 빠른 경우도 있습니다. 삭제 후에는 다시 충돌을 한 번 해결해 올바른 해결안을 재학습시키면 됩니다.

마무리: rerere는 ‘반복 충돌’을 줄이는 가장 현실적인 자동화

rerere는 화려한 도구가 아니라, 반복되는 고통을 조용히 줄여주는 자동화에 가깝습니다. rebase를 자주 쓰는 팀일수록, 그리고 lockfile/리팩토링 충돌이 잦을수록 효과가 큽니다.

정리하면:

  • rerere.enabled=true로 충돌 해결을 기록하고
  • rerere.autoupdate=true로 재적용을 자동화하며
  • 자동 적용 후에도 테스트/리뷰로 의미적 정합성을 확인하면

rebase 충돌 처리 시간이 눈에 띄게 줄어듭니다.

다음에 “또 이 충돌이네…”라는 생각이 들 때, rerere를 켜두었는지부터 확인해보면 좋습니다.