取り消した機能を入れ直そうとしたら、合わせるものがないと言われた
한국어 원문으로 표시합니다.
목표
병합 커밋을 되돌리고 되살리고, 릴리스 브랜치의 수정을 출처를 남기며 가져옵니다. 그리고 무엇이 이미 들어갔는지 기계가 어떻게 판정하는지까지 확인합니다.
왜 중요한가
reset 은 커밋을 지우고 revert 는 뒤집는 커밋을 더합니다. 이미 남에게 간 이력에는
revert 밖에 쓸 수 없는데, 병합 커밋에서는 그 뒤집기가 간단하지 않습니다. 부모가
둘이라 어느 쪽 상태로 돌아갈지를 사람이 말해 주어야 합니다. 그리고 되돌린 다음이
더 중요합니다 — merge 는 이력의 도달 가능성으로 판단하므로, 되돌린 기능을 다시 merge
해도 "합칠 것이 없다" 고 답합니다. 이 두 가지를 모르면 장애 대응 중에 같은 자리에서
30분을 잃습니다. 마지막 두 단계는 백포트 운영의 기본기입니다. 같은 변경이 이미
들어갔는지를 해시가 아니라 patch-id 로 판정한다는 것, 그리고 충돌을 해결해 가져온
커밋은 그 판정에서 빠진다는 것을 직접 만들어 봅니다.
단계
/root/gitx7/repo에 병합 커밋과 릴리스 브랜치가 있는 이력을 만듭니다.- 병합 커밋을
-m없이 되돌려 보고, 거절 메시지를notes/revert-m.txt에 남긴 뒤-m 1로 되돌립니다. git merge feature가 무엇이라고 답하는지notes/reland.txt에 적고, 되돌림을 되돌려 기능을 되살립니다.- 릴리스의 핫픽스 커밋을
-x로main에 가져옵니다. - 릴리스의 설정 변경 커밋을 가져오다 충돌하면
--abort로 물러섰다가, 다시 해서--continue로 마칩니다. 과정을notes/conflict.txt에 남깁니다. git cherry -v main release결과를notes/cherry.txt에 남깁니다.- 원본과 가져온 커밋의 patch-id 를
notes/patchid.txt에 나란히 적습니다. notes/report.md에 언제 무엇을 쓰는지 정리합니다.
참고
- 저장소마다
git config user.email과user.name을 지정해야 커밋이 됩니다. 커밋 시각은GIT_AUTHOR_DATE와GIT_COMMITTER_DATE로 고정하세요. git revert --no-edit와GIT_EDITOR=true를 쓰면 편집기가 열리지 않습니다.- 흔한 실수: 3단계에서
merge가 "Already up to date" 를 내는 것을 실패로 보고--force류를 찾는 것입니다. 정확한 답이고, 해법은 되돌림을 되돌리는 쪽입니다. - 흔한 실수: 5단계에서 충돌 표시(
<<<<<<<)를 파일에 남긴 채git add하는 것입니다. 그 표시까지 커밋됩니다.
병합 커밋과 릴리스 브랜치가 있는 이력
/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 하는 것입니다.
출처를 남기며 가져오기
릴리스의 핫픽스 커밋을 -x 로 main 에 가져옵니다.
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 --short 로 UU 를 보고 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 판정의 한계까지 다섯 덩어리로 쓰세요.