Published on

Git rebase 충돌 최소화 - rerere 설정과 운영 팁

Authors

서론

브랜치를 오래 끌고 가다 보면 git rebase는 피할 수 없는 선택이 됩니다. 커밋 히스토리를 깔끔하게 유지하고, 메인 브랜치의 최신 변경을 내 작업에 선형으로 얹을 수 있기 때문입니다. 하지만 rebase의 대가가 바로 충돌(conflict) 입니다. 특히 같은 파일/같은 구간에서 반복적으로 충돌이 발생하면, 해결 자체보다 같은 해결을 여러 번 하는 비용이 더 크게 느껴집니다.

이때 효과가 큰 기능이 Git의 rerere(reuse recorded resolution) 입니다. 한 번 충돌을 해결해 두면 Git이 그 해결을 기록해 두었다가, 다음에 동일/유사한 충돌이 다시 발생했을 때 자동으로 적용해 줍니다. rebase를 자주 하는 개인 개발자뿐 아니라, 장수 브랜치(long-lived branch)나 체리픽/백포트가 잦은 팀에서도 체감 효과가 큽니다.

이 글에서는 rerere의 동작 원리, 설정 방법, rebase 흐름에서의 활용, 그리고 운영 시 주의점을 코드 예제와 함께 정리합니다.

rerere란 무엇이고 왜 rebase에 특히 유리한가

rerere는 충돌이 발생했을 때 Git이 다음 두 가지를 저장하는 메커니즘입니다.

  • preimage: 충돌이 난 상태(충돌 마커가 포함된 형태)의 스냅샷
  • postimage: 사용자가 충돌을 해결한 뒤의 결과

그리고 이후 동일한 충돌(preimage와 유사한 패턴)이 다시 나타나면, Git이 postimage를 재사용하여 자동으로 충돌 해결안을 적용합니다.

rebase에서 반복 충돌이 생기는 전형적 패턴

rebase는 커밋을 하나씩 재적용합니다. 따라서 다음 상황에서 같은 충돌이 반복될 수 있습니다.

  • 커밋 A, B가 동일 파일의 인접한 라인을 건드리고, 대상 브랜치에서도 해당 구간이 바뀐 경우
  • 기능 브랜치에 “리팩터링 커밋”이 여러 개로 쪼개져 있고, 메인 브랜치에서도 비슷한 리팩터링이 진행된 경우
  • 체리픽/백포트처럼 비슷한 패치를 다른 릴리즈 브랜치에 반복 적용하는 경우

rerere를 켜두면 첫 번째 충돌만 잘 해결하면 이후는 자동 적용되는 경우가 많아, rebase의 체감 난이도가 크게 내려갑니다.

rerere 활성화: 전역/저장소 단위 설정

rerere는 기본적으로 꺼져 있습니다. 활성화 방법은 두 가지입니다.

1) 전역 설정(추천)

개발 머신에서 모든 저장소에 적용하려면:

git config --global rerere.enabled true

추가로 자동으로 스테이징까지 도와주는 옵션도 있습니다.

git config --global rerere.autoupdate true
  • rerere.autoupdate=true이면 rerere가 적용한 해결안을 자동으로 인덱스에 반영(스테이징)하려고 시도합니다.
  • 다만 팀/프로젝트 성격에 따라 “자동 스테이징이 불편”할 수 있으니, 처음에는 enabled만 켜고 적응한 뒤 켜는 것도 좋습니다.

2) 특정 저장소에서만 켜기

프로젝트 단위로만 적용하고 싶다면 --global 없이 실행합니다.

git config rerere.enabled true

설정 확인:

git config --get rerere.enabled
git config --get rerere.autoupdate

rebase에서 rerere가 실제로 동작하는 흐름

rerere는 “충돌 발생 → 해결 → 기록 → 재발 시 재사용” 흐름으로 작동합니다.

예시 시나리오

  1. rebase를 시작합니다.
git fetch origin
git rebase origin/main
  1. 충돌이 발생하면, Git은 해당 충돌 상태(preimage)를 rerere 캐시에 기록합니다.
# 충돌 발생 시 상태 확인
git status
  1. 파일을 열어 충돌을 해결합니다.
# 예: 충돌 파일을 편집기로 수정한 뒤

git add path/to/conflicted-file
  1. rebase를 계속 진행합니다.
git rebase --continue
  1. 이후 rebase 과정에서 동일/유사 충돌이 다시 발생하면, rerere가 자동으로 해결안을 적용합니다. 로그에서 흔히 다음과 같은 메시지를 볼 수 있습니다.
# (상황에 따라 출력이 다를 수 있음)
Resolved 'path/to/conflicted-file' using previous resolution.

rerere가 적용했는지 확인하는 방법

rerere의 동작은 항상 “완벽한 자동 해결”을 보장하지는 않습니다. 적용되었더라도 결과가 맞는지 확인하는 습관이 필요합니다.

# 적용 결과를 빠르게 확인
git diff

# 또는 rebase 중이라면
# (충돌이 완전히 해결되었는지, 추가 수정이 필요한지 확인)
git status

rerere 데이터는 어디에 저장되나

rerere의 해결 기록은 일반적으로 저장소의 다음 경로에 저장됩니다.

  • .git/rr-cache/

여기에는 충돌 패턴과 해결 결과가 쌓입니다. 즉, rerere는 원칙적으로 로컬 저장소의 학습 데이터이며, 기본 설정만으로는 원격에 공유되지 않습니다.

팀에서 공유할 수 있나?

가능은 하지만 신중해야 합니다.

  • rr-cache를 공유/동기화하면 팀 전체가 혜택을 볼 수 있지만
  • 잘못된 해결이 기록되면 팀 전체가 같은 잘못을 반복할 위험도 있습니다.

보통은 “개인 생산성” 도구로 쓰되, 릴리즈 브랜치 백포트처럼 반복 충돌이 확실하고 해결이 표준화된 경우에만 제한적으로 공유를 고려합니다.

실전 팁: rebase 충돌을 더 줄이는 운영 패턴

rerere는 충돌 해결의 반복을 줄여주지만, 충돌 자체를 줄이는 전략과 함께 쓰면 효과가 더 큽니다.

1) rebase 전에 최신 main을 자주 반영하기

기능 브랜치를 오래 방치하면 충돌의 폭발 반경이 커집니다.

git fetch origin
git rebase origin/main

짧은 주기로 자주 rebase하면 충돌이 “작고 국소적”이 되어 rerere의 학습 효율도 좋아집니다.

2) 충돌 해결 커밋을 만들지 말고, rebase 흐름을 유지하기

rebase 중 충돌을 해결할 때는 git commit을 새로 만들기보다 git addgit rebase --continue로 진행하는 것이 일반적입니다. rerere는 이 과정에서 해결안을 학습합니다.

# 충돌 해결 후
git add -A
git rebase --continue

3) 동일 파일에 대한 기계적 포맷팅/정렬 커밋을 분리하기

예를 들어 lint/formatter 적용 커밋이 기능 변경과 섞여 있으면 충돌이 기하급수적으로 늘어납니다.

  • 포맷팅은 별도 커밋으로 분리
  • 가능하면 메인 브랜치에서 일괄 적용 후 기능 브랜치들은 그 이후를 기반으로 작업

이렇게 하면 rerere가 해결해야 할 충돌 패턴 자체가 줄어듭니다.

rerere 사용 시 주의점(중요)

1) “자동 해결”은 “정답”이 아니다

rerere는 과거에 사용자가 선택한 해결을 재사용합니다. 하지만 코드 맥락이 바뀌었으면 과거의 해결이 더 이상 올바르지 않을 수 있습니다.

권장 체크리스트:

# rerere가 적용된 뒤에는 꼭 확인
git diff

# 테스트/빌드가 있다면 최소 단위로라도 실행
# 예: npm test, mvn test, pytest 등

2) 큰 리팩터링 이후에는 오히려 독이 될 수 있음

파일 구조가 크게 바뀌거나, 충돌 패턴이 “겉보기엔 유사하지만 의미는 달라진” 상태라면 rerere가 과거 해결을 적용해 미묘한 버그를 만들 수 있습니다.

이럴 때는 rerere 캐시를 정리하는 것도 방법입니다(아래 참고).

3) 바이너리/자동 생성 파일 충돌에는 기대치 조절

바이너리 파일, lockfile, 대규모 자동 생성 파일은 충돌 패턴이 자주 바뀌고 의미 있는 자동 해결이 어렵습니다. rerere가 도움이 되더라도 한계가 있습니다.

rerere 캐시 관리: 확인/정리 방법

상황에 따라 기록된 해결을 확인하거나 삭제하고 싶을 수 있습니다.

rerere 상태 확인

rerere가 기록/적용한 항목은 다음 명령으로 확인할 수 있습니다.

git rerere status

기록된 해결을 다시 적용해보는 명령도 있습니다.

git rerere replay

특정 시점에 캐시를 정리하고 싶다면

가장 단순한 방법은 rr-cache를 제거하는 것입니다(로컬 기록 초기화).

rm -rf .git/rr-cache

주의:

  • 이 작업은 되돌리기 어렵습니다.
  • “유용하게 학습된 해결”까지 모두 사라집니다.

함께 알면 좋은 Git 옵션: conflictstyle로 가독성 개선

rerere 자체는 충돌 해결을 재사용하는 기능이지만, 충돌을 해결하는 순간의 생산성도 중요합니다. 충돌 마커를 더 풍부하게 보여주는 설정이 도움이 됩니다.

git config --global merge.conflictstyle zdiff3
  • diff3/zdiff3는 공통 조상(base) 내용까지 보여줘서, 왜 충돌이 났는지 이해가 쉬워집니다.
  • 이해가 빨라지면 첫 해결을 더 정확히 하게 되고, 그 결과 rerere가 저장하는 postimage 품질도 좋아집니다.

운영 관점에서의 적용: 반복 작업을 줄이는 “학습형 도구”

rerere는 DevOps/플랫폼 운영처럼 반복적인 문제를 줄이는 접근과 닮았습니다. 예를 들어 장애 대응에서도 “한 번 겪은 문제를 재발 방지 문서/자동화로 바꿔” 비용을 줄입니다. 비슷한 맥락에서 다음 글들도 참고할 만합니다.

결론

git rerere는 rebase/merge에서 반복되는 충돌 해결을 학습해 재사용하는 기능입니다. 한 번 제대로 해결해두면 이후 rebase에서 같은 충돌을 자동으로 처리해 주므로, 장수 브랜치나 잦은 체리픽 환경에서 생산성 향상이 큽니다.

추천 시작 설정은 아래 두 줄입니다.

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

다만 rerere는 “자동으로 해결해 주는 마법”이 아니라 “과거 결정을 재적용하는 도구”입니다. 적용 후 git diff와 테스트로 결과를 확인하는 습관을 함께 가져가면, rebase 충돌 비용을 안정적으로 줄일 수 있습니다.