Published on

Git rebase 충돌 자동해결 - rerere·autosquash 실전

Authors

서로 다른 브랜치를 자주 리베이스(rebase)하는 팀에서는 “매번 똑같은 충돌을 또 푸는” 일이 생각보다 큰 비용이 됩니다. 특히 장수 브랜치(long-lived feature branch), 릴리즈 브랜치, 또는 대규모 리팩터링 브랜치에서 main을 주기적으로 끌어오며 리베이스할 때 충돌 패턴이 반복되는 경우가 많습니다.

이 글에서는 Git의 rerere(reuse recorded resolution) 로 “한 번 풀었던 충돌을 다음엔 자동으로 적용”하는 방법과, autosquashfixup!/squash! 커밋을 자동 정렬해 리베이스 중 커밋 히스토리를 정돈하는 방법을 함께 다룹니다. 두 기능은 각각 독립적으로 유용하지만, 같이 쓰면 “리베이스를 빠르고, 덜 스트레스 받게” 만들어줍니다.

현업에서 CI/CD 파이프라인과 맞물려 리베이스 품질이 중요한 경우도 많습니다. 예를 들어 GitHub Actions 배포 권한/인증 이슈를 줄이려면 PR 히스토리와 리베이스 과정이 안정적이어야 하죠. 관련해서는 GitHub Actions OIDC로 AWS 배포 권한 오류 해결도 함께 참고하면 좋습니다.

rebase 충돌이 반복되는 이유

리베이스 충돌이 “반복”되는 대표적인 패턴은 다음과 같습니다.

  • 동일 파일의 동일 구간을 여러 브랜치가 계속 건드림: 예) 공통 설정 파일, 라우팅/DI 구성, CI 설정 등
  • 장수 브랜치가 주기적으로 main을 따라가며 리베이스: 충돌이 났던 구간이 main에서도 계속 변하므로 같은 류의 충돌이 재발
  • 리팩터링 브랜치: 파일 이동/이름 변경 + 코드 변경이 섞이면 충돌 해결이 반복되기 쉬움

이때 rerere가 빛을 발합니다. Git이 “충돌 당시의 양쪽 상태 + 내가 선택한 해결 결과”를 기록해두고, 다음에 비슷한 충돌이 발생하면 자동으로 해결안을 적용합니다.

rerere란? (reuse recorded resolution)

rerere는 Git에 내장된 기능으로, 충돌이 발생했을 때:

  1. 충돌의 내용을 해시(정확히는 conflict context 기반)로 식별하고
  2. 사용자가 해결한 결과를 기록한 뒤
  3. 이후 동일/유사 충돌이 다시 발생하면 자동으로 그 해결을 재적용

즉, “한 번 해결한 충돌은 다시 풀지 않게” 하는 장치입니다.

rerere 활성화(전역 권장)

git config --global rerere.enabled true
# 선택: 기록된 해결안이 적용되면 자동으로 stage까지 해줌
git config --global rerere.autoupdate true
  • rerere.enabled: 기록/재사용 기능 활성화
  • rerere.autoupdate: 재적용된 해결안을 자동으로 git add까지 처리(리베이스 흐름이 더 빨라짐)

프로젝트 단위로만 켜고 싶다면 --global 대신 저장소에서 설정하면 됩니다.

rerere가 실제로 동작하는 흐름

  1. 리베이스 중 충돌 발생
git rebase main
# conflict 발생
  1. 평소처럼 충돌 해결 후 stage
# 파일 편집으로 충돌 해결
git add path/to/file
  1. 리베이스 계속
git rebase --continue

이 과정에서 rerere는 해결 결과를 .git/rr-cache/ 아래에 저장합니다. 다음번에 같은 유형의 충돌이 발생하면, 충돌 직후 Git이 다음과 같은 메시지를 보여줄 수 있습니다.

  • Recorded resolution for ...
  • Resolved ... using previous resolution.

rerere 상태/기록 확인 팁

# rerere가 적용/기록한 충돌 목록을 확인
git rerere status

# 현재 기록된 해결안을 기반으로 다시 적용 시도
git rerere replay

# 특정 기록을 잊고 싶을 때(문제 해결안이 잘못 저장된 경우)
git rerere forget path/to/file

실전 팁: “잘못된 해결”이 기록되었을 때

rerere는 매우 유용하지만, 한 번 잘못 해결한 결과를 기록하면 이후에도 그 잘못된 해결을 반복 적용할 수 있습니다. 이럴 땐:

  1. git rerere forget <file>로 기록 제거
  2. 다시 충돌을 올바르게 해결
  3. 올바른 해결안을 새로 기록

이 루틴을 기억해두면 rerere를 더 안전하게 운영할 수 있습니다.

rerere가 특히 효과적인 케이스

  • package-lock.json, yarn.lock, pnpm-lock.yaml처럼 충돌이 잦은 잠금 파일
  • 공통 설정 파일(예: .github/workflows/*, Dockerfile, helm values.yaml)
  • 지속적으로 변경되는 “팀 공용” 모듈

반대로, 충돌이 매번 완전히 다른 맥락에서 발생한다면 rerere의 체감 효과는 낮을 수 있습니다.

autosquash란? fixup!/squash! 커밋을 자동 정렬

리베이스를 자주 하는 팀은 보통 커밋을 깔끔하게 유지하려고 합니다. 하지만 작업 중에 리뷰 피드백을 반영하다 보면 이런 커밋이 늘죠.

  • fixup! <대상 커밋 메시지>: 대상 커밋에 “내용만 합치고 메시지는 버림”
  • squash! <대상 커밋 메시지>: 대상 커밋에 “내용을 합치고 메시지 편집”

autosquash는 rebase -i(interactive rebase) 시 이 커밋들을 대상 커밋 바로 아래로 자동 이동시키고, pickfixup/squash로 자동 변환해줍니다.

autosquash 사용 준비

git config --global rebase.autosquash true

이 설정을 켜면, 이후 git rebase -i에서 --autosquash를 매번 안 붙여도 되는 경우가 많습니다(버전에 따라 동작이 조금 다를 수 있어 명시적으로 붙이는 습관도 좋습니다).

fixup 커밋 만들기(권장 워크플로)

리뷰에서 “이 커밋에 이 수정만 추가해줘” 같은 피드백이 왔을 때, 기존 커밋을 직접 amend하기보다 fixup 커밋을 쌓고 마지막에 autosquash로 정리하면 편합니다.

# 수정 작업 후

git add -A

git commit --fixup <대상커밋해시>
# 또는 메시지로 대상 커밋을 찾고 싶다면(최신 Git)
# git commit --fixup :/<대상커밋메시지일부>

그 다음 히스토리 정리:

git rebase -i --autosquash main

리베이스 편집 화면에서 Git이 자동으로 이런 형태로 정렬해줍니다.

pick   abc111  feat: add payment endpoint
fixup  def222  fixup! feat: add payment endpoint
pick   ghi333  refactor: extract validator

이제 저장/종료하면 자동으로 합쳐집니다.

squash와 fixup의 선택 기준

  • fixup: 메시지는 유지하고 “코드만” 합치고 싶을 때(대부분의 리뷰 반영)
  • squash: 커밋 메시지까지 함께 다듬어야 할 때(의미가 합쳐지는 경우)

rerere + autosquash를 함께 쓰는 리베이스 루틴

둘을 같이 쓰면 “충돌 해결은 rerere가 반복 작업을 줄이고, 커밋 정리는 autosquash가 자동화”합니다.

추천 설정 세트

# 반복 충돌 자동 재적용
git config --global rerere.enabled true
git config --global rerere.autoupdate true

# fixup/squash 자동 정렬
git config --global rebase.autosquash true

실전 예시 흐름

  1. 기능 브랜치에서 작업
  2. 리뷰 피드백 반영은 --fixup으로 쌓기
  3. main 최신화가 필요하면 리베이스
git fetch origin

git rebase origin/main
# 충돌이 나면 한 번만 잘 풀기(이후 rerere가 도와줌)

# 커밋 정리(필요 시)
git rebase -i --autosquash origin/main

포인트

  • 충돌이 났던 파일/구간이 다음 리베이스에서도 비슷하게 충돌하면 rerere가 자동 적용
  • fixup 커밋이 많아도 autosquash가 대상 커밋에 붙여 정리

주의사항과 운영 팁

1) rerere는 “머지/리베이스 전략”을 대체하지 않는다

rerere는 충돌 해결의 반복 노동을 줄이지만, 충돌 자체를 없애지는 못합니다. 충돌이 너무 잦다면:

  • 브랜치를 더 자주 main에 맞추기(rebase 빈도 증가)
  • 큰 리팩터링은 단계적으로 쪼개기
  • 공통 파일 변경을 한 곳에서만 하도록 규칙 정하기

같은 프로세스 개선이 우선일 수 있습니다.

2) 기록은 로컬에 저장된다(팀 공유 아님)

rerere의 기록은 기본적으로 .git/rr-cache에 저장되며, 보통 원격에 공유되지 않습니다. 즉, 개인 생산성 향상 도구에 가깝습니다.

팀 차원에서 충돌 해결을 공유하고 싶다면 별도의 워크플로(예: 충돌 해결 전담 브랜치/PR, 또는 리베이스 대신 머지 전략)도 검토해야 합니다.

3) autosquash는 “커밋 메시지 규율”이 있어야 빛난다

fixup!/squash!는 대상 커밋 메시지를 기반으로 매칭됩니다. 따라서:

  • 커밋 메시지를 자주 바꾸면 매칭이 꼬일 수 있음
  • 의미 없는 메시지(예: wip)는 대상 지정이 어려움

커밋 메시지 컨벤션을 어느 정도 유지하는 것이 좋습니다.

4) 강제 푸시(force push)와의 관계

리베이스는 커밋 해시를 바꾸므로, 원격 브랜치에 이미 푸시한 브랜치를 리베이스했다면 보통 --force-with-lease가 필요합니다.

git push --force-with-lease
  • --force-with-lease는 “내가 알고 있는 원격 상태에서만” 강제 푸시를 허용해 사고를 줄입니다.

문제 해결(트러블슈팅)

rerere가 적용이 안 되는 것 같다

  • rerere가 켜져 있는지 확인
git config --get rerere.enabled
  • 충돌이 “완전히 동일한 형태”로 재발하지 않으면 적용률이 떨어질 수 있습니다(컨텍스트가 달라짐).
  • 과거에 기록된 해결안이 잘못되었거나, 다른 해결을 원한다면 forget 후 다시 기록하세요.

autosquash가 정렬을 안 해준다

  • fixup!/squash! 접두어가 정확한지 확인
  • interactive rebase에서 autosquash 옵션을 명시
git rebase -i --autosquash origin/main
  • 대상 커밋 메시지가 바뀌었으면 매칭이 실패할 수 있습니다. 이때는 --fixup <hash> 방식이 더 확실합니다.

마무리: 리베이스를 “습관적으로” 빠르게 만들기

  • rerere는 반복 충돌 해결을 자동화해 리베이스의 가장 큰 고통을 줄여줍니다.
  • autosquash는 리뷰 반영 커밋을 깔끔하게 정리해 PR 품질과 히스토리 가독성을 높입니다.

두 기능은 설정 몇 줄로 체감 생산성이 크게 올라가는 편이라, 리베이스 기반 워크플로를 쓰는 팀/개인이라면 기본 장착을 추천합니다. 특히 장수 브랜치를 운영하거나, CI가 엄격한 환경에서 리베이스를 자주 수행한다면 효과가 더 큽니다.

추가로, 배포/운영 자동화 환경에서 Git 히스토리 정리가 왜 중요한지(권한/인증/파이프라인 안정성 관점)는 GitHub Actions OIDC로 AWS 배포 권한 오류 해결 글도 함께 보면 맥락을 잡는 데 도움이 됩니다.