LabHub
배우기 러닝패스 코스

Git in Practice

Solving the Same Conflict a Third Time Means Something Is Missing

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

rerere 는 충돌을 어떻게 풀었는지 기록해 두었다가 같은 충돌이 다시 나오면 그대로 적용합니다. merge.conflictStyle=zdiff3 는 충돌 표시에 공통 조상을 함께 보여 줘서 "누가 무엇을 바꿨는지" 를 추측하지 않게 합니다. -X ours-s ours 는 이름만 비슷하고 결과가 전혀 다릅니다.

Concept map: 원래 무엇이었나 · 충돌 전 모습(preimage) · 해결한 결과(postimage) · 적용만 하고 스테이징하지는 않습니다

왜 이게 필요했나

오래 사는 기능 브랜치를 main 위로 계속 리베이스하면, 같은 자리에서 같은 충돌이 매번 납니다. 열 개 커밋을 리베이스하면 그 충돌을 열 번 풉니다. 실수로 --abort 하고 다시 하면 또 열 번입니다. 지치면 손이 미끄러지고, 미끄러진 해결은 조용히 커밋됩니다.

그리고 충돌 표시 자체가 정보가 부족합니다. 기본 표시는 이렇게 나옵니다.

<<<<<<< HEAD
b by main
=======
b by topic
>>>>>>> topic

여기서 알 수 없는 것이 하나 있습니다 — 원래 무엇이었나. 한쪽이 지운 것인지, 양쪽이 서로 다르게 고친 것인지, 한쪽은 그대로 두고 다른 쪽만 고친 것인지가 구별되지 않습니다. 그래서 "안전해 보이는 쪽" 을 고르게 되고, 그 판단이 틀리면 남의 수정이 사라집니다.

어떻게 동작하나

zdiff3 — 공통 조상을 함께 보여 준다

git config merge.conflictStyle zdiff3

그러면 충돌 표시에 가운데 칸이 하나 더 생깁니다.

<<<<<<< HEAD
b by main
||||||| 75364cd
b
=======
b by topic
>>>>>>> topic

||||||| 아래가 공통 조상의 내용입니다. 이제 "원래 b 였는데 양쪽이 서로 다르게 고쳤다" 가 한눈에 보입니다. diff3 이라는 옛 설정값도 같은 일을 하는데, zdiff3 (git 2.35 이상)는 양쪽에 공통으로 남은 줄을 충돌 바깥으로 빼 줘서 표시가 짧습니다.

rerere — 해결을 기억한다

git config rerere.enabled true

켜 두면 충돌이 났을 때 git 이 충돌 전 모습(preimage).git/rr-cache 에 기록하고, 커밋할 때 해결한 결과(postimage) 를 같은 자리에 붙여 둡니다. 다음에 똑같은 preimage 가 나오면 이렇게 말합니다.

Resolved 'handler.txt' using previous resolution.

주의할 것이 셋 있습니다. 첫째, rerere 는 해결을 적용만 하고 스테이징하지는 않습니다. 결과를 보고 git add 하는 것은 사람의 몫입니다(rerere.autoUpdate 를 켜면 자동으로 스테이징되지만, 그러면 확인 없이 지나가게 되므로 권하지 않습니다). 둘째, 기록은 .git 안에 있어서 내 기계에만 남습니다. 셋째, 잘못 푼 해결도 똑같이 기억합니다 — 그때는 git rerere forget <경로> 로 그 기록을 지워야 합니다.

-X ours-s ours 는 전혀 다르다

이름이 비슷해서 자주 헷갈립니다.

손잡이 무엇인가 결과
-X ours 기본 병합 전략에 주는 옵션 충돌한 자리만 우리 것으로 고르고, 충돌하지 않은 상대 변경은 그대로 들어온다
-s ours 전략 자체 상대 트리를 통째로 버린다. 결과 트리는 병합 전 우리 것과 한 글자도 다르지 않다

-s ours 는 "이 브랜치는 합치지 않기로 했다" 는 사실을 이력에 남기는 용도입니다. 상대 브랜치가 조상으로 붙으므로 다음부터 그 브랜치는 병합 대상에서 빠집니다. 내용을 가져오려는 의도로 이것을 쓰면, 이력에는 합쳐졌다고 적혀 있는데 코드에는 아무것도 들어오지 않은 상태가 됩니다 — 그리고 나중에 누구도 그것을 의심하지 않습니다.

현장에서 만나는 모습

다음 실습에서 할 것

같은 자리를 서로 다르게 고친 두 브랜치를 만들어, 기본 표시와 zdiff3 표시를 나란히 봅니다. rerere 를 켜고 한 번 해결한 뒤, 병합을 되돌리고 다시 병합해 git 이 스스로 같은 해결을 적용하는 것을 확인합니다. 마지막으로 -X ours-s ours 를 각각 한 번씩 써서, 결과 파일에 무엇이 남고 무엇이 사라지는지를 내용으로 확인합니다.

공식 문서는 git-rerere, git-merge, git-config 입니다.