LabHub
学习 学习路径 课程

Git 实战

想把回退的功能放回去,Git 说没什么可合的

在 LabHub 中继续学习

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

목표

병합 커밋을 되돌리고 되살리고, 릴리스 브랜치의 수정을 출처를 남기며 가져옵니다. 그리고 무엇이 이미 들어갔는지 기계가 어떻게 판정하는지까지 확인합니다.

왜 중요한가

reset 은 커밋을 지우고 revert 는 뒤집는 커밋을 더합니다. 이미 남에게 간 이력에는 revert 밖에 쓸 수 없는데, 병합 커밋에서는 그 뒤집기가 간단하지 않습니다. 부모가 둘이라 어느 쪽 상태로 돌아갈지를 사람이 말해 주어야 합니다. 그리고 되돌린 다음이 더 중요합니다 — merge 는 이력의 도달 가능성으로 판단하므로, 되돌린 기능을 다시 merge 해도 "합칠 것이 없다" 고 답합니다. 이 두 가지를 모르면 장애 대응 중에 같은 자리에서 30분을 잃습니다. 마지막 두 단계는 백포트 운영의 기본기입니다. 같은 변경이 이미 들어갔는지를 해시가 아니라 patch-id 로 판정한다는 것, 그리고 충돌을 해결해 가져온 커밋은 그 판정에서 빠진다는 것을 직접 만들어 봅니다.

단계

  1. /root/gitx7/repo 에 병합 커밋과 릴리스 브랜치가 있는 이력을 만듭니다.
  2. 병합 커밋을 -m 없이 되돌려 보고, 거절 메시지를 notes/revert-m.txt 에 남긴 뒤 -m 1 로 되돌립니다.
  3. git merge feature 가 무엇이라고 답하는지 notes/reland.txt 에 적고, 되돌림을 되돌려 기능을 되살립니다.
  4. 릴리스의 핫픽스 커밋을 -xmain 에 가져옵니다.
  5. 릴리스의 설정 변경 커밋을 가져오다 충돌하면 --abort 로 물러섰다가, 다시 해서 --continue 로 마칩니다. 과정을 notes/conflict.txt 에 남깁니다.
  6. git cherry -v main release 결과를 notes/cherry.txt 에 남깁니다.
  7. 원본과 가져온 커밋의 patch-id 를 notes/patchid.txt 에 나란히 적습니다.
  8. notes/report.md 에 언제 무엇을 쓰는지 정리합니다.

참고

병합 커밋과 릴리스 브랜치가 있는 이력

/root/gitx7/repo 에 병합 커밋과 릴리스 브랜치가 있는 이력을 만듭니다.

main 에 기본 파일들을 커밋하고, feature 브랜치에서 feature.txt 를 더하고 app.txt 의 둘째 줄을 고친 뒤 --no-ff 로 병합합니다. 그 자리에서 release 를 따서 핫픽스·설정 변경·릴리스 메모 셋을 쌓고, main 으로 돌아와 같은 설정 값을 다르게 고칩니다. 이 마지막 하나가 5단계의 충돌을 만듭니다.

병합 커밋은 어느 쪽으로 돌아갈지 말해야 한다

병합 커밋을 -m 없이 되돌려 보고, 거절 메시지를 notes/revert-m.txt 에 남긴 뒤 -m 1 로 되돌립니다.

병합 커밋 해시는 git rev-list --merges main 으로 찾습니다. 그냥 git revert <해시> 를 하면 거절당합니다 — 그 줄을 그대로 남기세요. -m 1 이 무엇을 기준으로 삼는다는 뜻인지도 적고, --no-edit 을 붙여 편집기 없이 되돌립니다.

다시 merge 해도 합칠 것이 없다

git merge feature 가 무엇이라고 답하는지 notes/reland.txt 에 적고, 되돌림을 되돌려 기능을 되살립니다.

git merge feature 를 그냥 해 보세요. 한 줄로 답합니다. 왜 그렇게 답하는지 적으세요 — merge 는 내용이 아니라 이력의 도달 가능성으로 판단합니다. 되살리는 방법은 방금 만든 되돌림 커밋을 다시 git revert 하는 것입니다.

출처를 남기며 가져오기

릴리스의 핫픽스 커밋을 -xmain 에 가져옵니다.

hotfix.txt 를 더한 릴리스 커밋의 해시는 git rev-list release -- hotfix.txt 로 찾습니다. git cherry-pick -x <해시> 를 하면 새 커밋 메시지 끝에 한 줄이 붙습니다. git log -1 --format=%B 로 확인하세요.

충돌하면 물러섰다 다시 온다

릴리스의 설정 변경 커밋을 가져오다 충돌하면 --abort 로 물러섰다가, 다시 해서 --continue 로 마칩니다. 과정을 notes/conflict.txt 에 남깁니다.

conf.txt 를 고친 릴리스 커밋을 git cherry-pick 하면 충돌합니다. 먼저 git status --shortUU 를 보고 git cherry-pick --abort 로 깨끗이 물러서 보세요. 그다음 다시 가져와서 conf.txt 를 릴리스가 정한 값으로 손봐 git add 하고, GIT_EDITOR=true git cherry-pick --continue 로 마칩니다. 충돌 표시 줄이 파일에 남지 않았는지 꼭 확인하세요.

무엇이 이미 들어갔는지 세어 보기

git cherry -v main release 결과를 notes/cherry.txt 에 남깁니다.

git cherry -v <upstream> <head>head 의 커밋 하나하나가 upstream 에 이미 있는지를 patch-id 로 판정합니다. - 는 있다, + 는 없다입니다. 세 커밋 중 하나만 - 로 나오는데, 충돌을 해결해 가져온 것이 왜 + 인지를 반드시 적으세요. 이 도구의 한계가 거기 있습니다.

해시는 다른데 patch-id 는 같다

원본과 가져온 커밋의 patch-id 를 notes/patchid.txt 에 나란히 적습니다.

git show <커밋> | git patch-id --stable 은 두 값을 냅니다 — 앞이 patch-id, 뒤가 커밋 해시입니다. 4단계에서 -x 로 가져온 커밋은 원본과 patch-id 가 같습니다. 그 커밋은 git log --grep 'cherry picked from commit <해시>' 로 찾을 수 있습니다.

언제 무엇을 쓰는가

notes/report.md 에 언제 무엇을 쓰는지 정리합니다.

reset 과 revert 를 가르는 질문, 병합 커밋을 되돌릴 때의 -m, 되살릴 때 merge 가 아니라 revert 의 revert 를 쓰는 이유, -x 를 규칙으로 두는 이유, 그리고 patch-id 판정의 한계까지 다섯 덩어리로 쓰세요.