LabHub

Git 실전 · 리베이스와 충돌 · 실습

리베이스와 충돌 해결

LabHub 에서 이어서 보기

목표

리베이스가 커밋을 옮기는 것이 아니라 재작성한다는 사실을 해시로 확인하고, 충돌 해결과 중단, 대화형 리베이스의 squash/drop 까지 손으로 해 봅니다. 산출물은 /root/gitx3/ 아래에 둡니다.

왜 중요한가

커밋 객체 안에는 부모 해시가 들어 있습니다. 부모가 달라지면 커밋 해시는 반드시 달라집니다. 이 한 문장에서 나머지가 전부 따라옵니다. 남이 그 커밋 위에 작업을 쌓아 두었다면 재작성은 그 사람의 이력을 깨뜨립니다. 그래서 황금률의 정확한 형태는 "이미 푸시했으면 하지 마라"가 아니라 "다른 사람의 작업이 그 위에 쌓여 있는 커밋은 재작성하지 않는다"입니다. 충돌이 반복되는 이유도 같은 구조에서 나옵니다. 머지는 세 지점만 비교하지만 리베이스는 커밋을 하나씩 다시 적용하며 매번 삼자 병합을 하므로, 리베이스는 한 번의 병합이 아니라 N번의 병합입니다.

단계

전역 git 신원이 없습니다. 새 저장소마다 로컬 user.email / user.name 을 설정하세요.

1. /root/gitx3/repo 에 저장소를 만듭니다. main 에 커밋 3개를 쌓고 거기서 topic 브랜치를 만들어 커밋 2개를 추가한 뒤, 다시 main 으로 돌아와 커밋 1개를 더 쌓아 갈라진 상태를 만듭니다(topic 의 총 커밋은 4개 이상). 그리고 /root/gitx3/diverged.txt 에 세 줄을 적습니다: main_ahead=1, topic_ahead=2, merge_base=<두 브랜치의 공통 조상 해시>.
2. topicmain 위로 리베이스합니다. 리베이스 전에 topic 의 끝 해시를 기록해 두고, /root/gitx3/rebased.txtbefore=<리베이스 전 해시>after=<리베이스 후 해시> 두 줄을 적습니다. 두 값은 서로 달라야 하고, after 는 현재 topic 의 끝과 일치해야 하며, 리베이스가 진행 중인 상태로 남아 있으면 안 됩니다.
3. main 에서 topic빨리 감기로 병합합니다. 결과: main 의 머지 커밋 0개, main 의 총 커밋 6개 이상, maintopic같은 커밋을 가리킬 것.
4. /root/gitx3/conflict 에 새 저장소를 만듭니다. mainshared.txt 를 두고, conflict-topic 브랜치에서 그 파일을 고쳐 from-topic 이라는 문자열이 들어가게 커밋합니다. 그다음 main 에서도 같은 자리를 고쳐 from-main 이 들어가게 커밋합니다. 이제 conflict-topicmain 위로 리베이스하면 충돌이 납니다. 두 변경을 모두 남기도록 해결하세요. 완료 조건: 리베이스가 끝나 있을 것, 인덱스에 미해결 경로가 없을 것, <<<<<<< 같은 충돌 표식이 파일에 남아 있지 않을 것, shared.txtfrom-mainfrom-topic둘 다 있을 것, 작업 트리가 깨끗할 것.
5. /root/gitx3/abort 에 새 저장소를 만들고 risky 브랜치와 main 이 같은 파일을 서로 다르게 고치도록 커밋합니다. 리베이스를 시작하기 전에 risky 의 끝 해시를 /root/gitx3/abort-before.txt 에 저장합니다(해시 문자열만). 그다음 리베이스를 시작해 충돌을 만나고 중단합니다. 완료 조건: 리베이스가 진행 중이 아닐 것, risky 의 끝이 기록해 둔 해시와 정확히 같을 것, reflog 에 rebase 기록이 있을 것.
6. /root/gitx3/squash 에 새 저장소를 만들고 feature/three 브랜치에 커밋 3개를 쌓습니다(각각 s1.txt, s2.txt, s3.txt 추가). 대화형 리베이스로 3개를 1개로 합칩니다. 완료 조건: main..feature/three 커밋 수가 1개, 그 커밋 제목에 feat: combined 포함, s1.txt/s2.txt/s3.txt 셋 다 존재.
7. /root/gitx3/drop 에 새 저장소를 만들고 feature/four 브랜치에 커밋 4개를 쌓습니다: d1.txt, d2.txt, 그리고 제목이 debug: temp log 이고 debug.txt 를 추가하는 커밋, 마지막으로 d3.txt. 대화형 리베이스로 디버그 커밋만 버립니다. 완료 조건: main..feature/four3개, debug: temp log 커밋 없음, debug.txt 없음, d1/d2/d3.txt 모두 존재.
8. /root/gitx3/rebase.md 를 씁니다. 반드시 포함할 것: --force-with-lease 설명과 --force 와의 차이, 언제 리베이스하면 안 되는지(공유·푸시·다른 사람 중 한 표현 포함), 왜 해시가 바뀌는지(해시·재작성 중 한 표현 포함), 그리고 merge_commits_on_main= 줄에 /root/gitx3/repomain 머지 커밋 개수를 실제로 세어 적습니다.

참고

단계 8개

  1. 갈라진 두 브랜치 만들기
  2. topic 을 main 위로 재작성
  3. 빨리 감기로 일직선 만들기
  4. 충돌을 양쪽 보존하며 해결
  5. 리베이스 중단하고 원상 복구
  6. 커밋 3개를 1개로 합치기
  7. 커밋 하나 버리기
  8. 황금률 정리