ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 충돌은 왜 rebase에서 더 자주 만날까 — merge는 한 번, rebase는 커밋마다
    IT 2026. 8. 6. 22:30
    충돌은 왜 rebase에서 더 자주 만날까 — merge는 한 번, rebase는 커밋마다

    rebase를 처음 써 본 지인이 물었다. "merge로 합칠 땐 충돌(conflict)이 한 번 났는데, 같은 브랜치를 rebase로 해 봤더니 충돌 해결을 세 번이나 시켰어. 뭔가 잘못한 거야?" 잘못한 게 아니다. 구조적으로 그렇게 설계돼 있다. merge와 rebase는 "브랜치를 합친다"는 결과가 비슷해 보여도 변경을 적용하는 단위가 달라서, 충돌을 만나는 횟수와 방식이 다르다. 이 차이를 모르면 rebase 도중 반복되는 충돌 앞에서 "git이 고장났나?" 하는 공포에 빠지기 쉽다.

    충돌이란 무엇인가 — 기계가 판단을 포기하는 지점

    먼저 충돌 자체를 정확히 하자. git은 두 변경을 합칠 때 대부분 자동으로 처리한다 — 서로 다른 파일, 또는 같은 파일의 서로 다른 영역을 고쳤다면 둘 다 반영하면 그만이다. 충돌은 같은 파일의 같은 줄을 양쪽이 다르게 고쳤을 때만 발생한다. 어느 쪽이 옳은지는 코드의 의미를 알아야 판단할 수 있고, git은 텍스트만 볼 뿐 의미를 모르므로 판단을 사람에게 넘긴다. 파일에 <<<<<<< / ======= / >>>>>>> 마커를 박아 "양쪽 버전을 나란히 뒀으니 골라라"라고 묻는 것이 충돌의 실체다. 즉 충돌은 오류가 아니라 질문이다.

    merge — 최종 상태끼리 한 번에 대조한다

    merge는 세 지점만 본다. 두 브랜치의 끝 커밋 두 개와, 둘이 갈라진 공통 조상. 이 3자 대조(3-way merge)로 "조상 이후 양쪽에서 각각 뭐가 변했나"를 계산해 한 번에 합친다. feature에 커밋이 3개든 30개든 상관없다 — 중간 과정은 안 보고 최종 상태만 보기 때문에, 충돌 해결 세션도 최대 한 번이다.

    diagram

    다이어그램 설명. "공통 조상 커밋"을 기준점으로 "main의 끝 커밋"과 "feature의 끝 커밋"이 각각 어떻게 달라졌는지만 대조한다. feature의 중간 커밋들이 서로 지지고 볶은 과정 — 예컨대 둘째 커밋이 첫째 커밋의 코드를 다시 고쳤더라도 — 은 계산에 등장하지 않는다. 그래서 "충돌 해결 1회"로 끝난다. 이 방식의 함정은 반대쪽에 있다 — 3개월 묵은 브랜치를 한 번에 merge하면 그 1회의 충돌 덩어리가 수백 줄짜리 괴물이 될 수 있다. 횟수는 적지만 한 방이 클 수 있는 구조다.

    rebase — 커밋을 한 개씩 다시 상영한다

    rebase는 전혀 다르게 움직인다. feature의 커밋들을 하나씩 들어서 main 끝에 순서대로 재적용(replay)한다. 커밋이 3개면 적용도 3번 — 그리고 매 적용이 독립적인 충돌 기회다.

    diagram

    다이어그램 설명. "F1 재적용"부터 "F3 재적용"까지 관문이 커밋 수만큼 이어진다. 지인이 충돌을 세 번 푼 이유가 이 구조다. 특히 악명 높은 패턴이 있다 — F1이 고친 줄을 main도 고쳐서 충돌이 났다고 하자. F1에서 그 줄을 해결해도, F2가 같은 줄을 또 고치는 커밋이면 F2 재적용에서 사실상 같은 충돌을 다시 만난다. "아까 해결했잖아!"라는 절규가 나오는 지점인데, git 입장에서는 각 재적용이 별개의 사건이라 어제의 해결을 기억할 이유가 없다. 대신 장점도 정확히 여기서 나온다 — 각 충돌이 커밋 한 개 분량이라 맥락이 작고 명확하다. merge의 "수백 줄 한 방"과 rebase의 "작은 질문 여러 번"은 같은 총량을 나누는 방식의 차이다.

    실전 처치 1 — 세 개의 탈출구를 먼저 외운다

    # 충돌 파일을 고친 뒤: 해결 완료를 알리고 다음 커밋 재적용으로 진행
    git add <해결한 파일>
    git rebase --continue
    
    # 이 커밋은 재적용할 필요가 없어졌을 때 (main에 이미 같은 수정이 있는 등): 건너뛰기
    git rebase --skip
    
    # 뭔가 꼬였다, 전부 물리고 싶다: rebase 시작 전 상태로 완전 복귀
    git rebase --abort
    

    코드 설명. rebase 충돌이 무섭지 않은 이유는 세 번째 명령 때문이다. --abort는 rebase를 시작하기 전 상태로 완전히 되돌린다 — 중간까지 해결한 게 아깝긴 해도, 망칠 수 있는 것이 없다. 처음 rebase를 배울 때는 "언제든 --abort로 나올 수 있다"는 사실 하나가 심리적 안전판이 된다. --skip은 재적용하려는 커밋의 변경이 main에 이미 반영돼 있어 적용할 게 없을 때(git이 "이 커밋은 비게 된다"고 알려 준다) 쓰는 건너뛰기다.

    실전 처치 2 — 같은 충돌의 반복은 rerere로 자동화한다

    # 한 번 켜 두면: 내가 푼 충돌의 "문제-답" 쌍을 git이 기록했다가
    # 같은 충돌을 다시 만나면 답을 자동으로 재적용한다
    git config --global rerere.enabled true
    

    코드 설명. rerere는 "reuse recorded resolution"(기록된 해결책 재사용)의 약자로, 이름 그대로 충돌 해결의 캐시다. 앞서 본 "F1에서 푼 충돌을 F2에서 또 푸는" 패턴, 그리고 긴 rebase를 하다가 --abort 후 다시 시도할 때 같은 충돌을 처음부터 다시 푸는 낭비 — 둘 다 rerere가 기록해 둔 답으로 자동 처리된다. 설정 한 줄이라 켜지 않을 이유가 거의 없는데, 존재 자체가 덜 알려진 기능이다. 단 자동 적용된 해결도 결국 과거의 내 판단이므로, rebase 완료 후 빌드·테스트로 최종 상태를 확인하는 습관은 그대로 필요하다.

    구조를 알면 전략이 나온다

      merge rebase
    충돌 세션 최대 1회 커밋 수만큼 가능
    충돌 1회의 크기 클 수 있음 (전체 차이 한 방) 작음 (커밋 한 개 분량)
    같은 줄 반복 충돌 없음 가능 (rerere로 완화)
    중도 포기 git merge --abort git rebase --abort

    이 표에서 실전 전략이 하나 나온다. 오래 사는 브랜치일수록 자주, 조금씩 동기화하라. 충돌의 총량은 "양쪽이 같은 줄을 얼마나 고쳤나"로 정해지는 것이라 merge냐 rebase냐로 줄어들지 않는다. 줄일 수 있는 것은 한 번에 마주하는 크기다 — 매일 main을 가져오면(merge든 rebase든) 충돌이 그날 치 분량으로 잘게 쪼개져, "3개월 치 충돌 한 방"이라는 최악을 피할 수 있다.

    정리 — 충돌 횟수의 차이는 버그가 아니라 설계다

    merge는 최종 상태끼리 한 번 대조하고, rebase는 커밋을 하나씩 다시 상영한다. 그래서 merge는 "크게 한 번", rebase는 "작게 여러 번" 충돌을 만난다 — 어느 쪽도 고장이 아니고, 같은 작업량을 나누는 두 가지 방식일 뿐이다. 도구로는 --abort라는 탈출구와 rerere라는 캐시를 챙기고, 전략으로는 동기화 주기를 짧게 가져가면, 충돌은 공포의 대상에서 "git이 던지는 작은 질문들"로 내려온다.


    참고한 공개 자료:

    • Pro Git Book — Basic Merge Conflicts: https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
    • Pro Git Book — Rerere: https://git-scm.com/book/en/v2/Git-Tools-Rerere
    • git-rebase 공식 문서 (--continue / --skip / --abort): https://git-scm.com/docs/git-rebase
    • git-merge 공식 문서 (3-way merge, ORIG_HEAD): https://git-scm.com/docs/git-merge

    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.