git 2.54~2.55에 실험적으로 추가된 'git history' 명령, jj 없이도 커밋 재작성을 안전하게
- git history는 git 2.54(4월, reword·split)와 2.55(6월, fixup)에 걸쳐 추가된 실험적 명령으로 fixup, reword, split 세 서브커맨드로 구성됨
- git history fixup 은 스테이징한 수정을 과거 커밋에 접어넣고 그 커밋을 포함하는 모든 로컬 브랜치를 자동으로 rebase해서 업데이트함
- 기존 git rebase --update-refs는 현재 rebase 범위 안의 ref만 옮기지만, git history fixup은 대상 커밋에서 파생된 모든 로컬 브랜치를 찾아 재작성함(현재 브랜치로만 제한하는 옵션도 있음)
- 세 명령 모두 원자적(atomic)으로 동작해 충돌이 발생할 수 있는 작업은 거부하며, 이는 git이 아직 1급 conflict 상태를 지원하지 않기 때문이고 문서에는 향후 git이 이를 지원하면 이 제약이 풀릴 수 있다고 명시됨
- git history는 병합 커밋이 있으면 동작하지 않는 한계가 있고, HN 댓글에서는 유용성 논쟁과 함께 rebase --update-refs와의 동작 차이에 대한 구체적 질문이 이어짐
Hacker News opinions
이거 그냥 rebase -i 자주 하는 사람 입장에서는 별로 필요성 못 느낌. 커밋을 직접 눈으로 보면서 옮기는 게 더 편하지, git history를 로컬에 없는 orphan 커밋에 잘못 겨냥할까봐 오히려 불안함
conflict 무서워하는 사람들 얘기 나오는데, 그건 git 인터페이스 문제가 아니라 코드베이스를 제대로 이해 못해서 그런 거 아님? A랑 B가 충돌한다는 건 의도가 다르다는 신호니까 그 의도를 파악하고 합치는 게 본질이지
git이 코드를 그냥 텍스트 스트림으로 다루니까 저런 문제 생기는 거지, 코드를 구조화된 의미로 다뤘으면 애초에 conflict 개념 자체가 달랐을 듯
conflict를 완전히 이해해도 git이 그걸 다루는 방식 자체가 짜증나서 무서운 거임. 이해력 문제가 아니라 git 워크플로우 문제라니까
rebase -i 무섭다는 거 이해 안 됨. git rebase --abort 있고, rebase 전에 태그나 브랜치 하나 찍어두면 언제든 git reset --hard로 되돌릴 수 있는데 뭐가 무섭다는 건지
나는 rebase 전에 항상 before-rebase 이런 이름으로 브랜치 하나 만들어둠. reflog 뒤지는 것보다 훨씬 편하고, rebase 끝나고 git log -p로 diff 비교해서 의도치 않은 conflict resolution 있었는지 확인함
git history split은 주니어들 큰 PR 쪼개게 도와줄 때 진짜 유용할 듯. 브랜치 자체를 통째로 두 개로 쪼개는 기능까지 있으면 더 좋겠음
나는 회계사처럼 히스토리 절대 안 건드리고, 고칠 일 있으면 새 커밋(저널 엔트리)으로 남김
깨진 걸 애초에 커밋하면 안 되는 거 아님?
커밋 그래프는 그냥 데이터 구조일 뿐이야. 프로젝트의 진짜 history를 남기고 싶은지, 개발자가 로컬에서 한 삽질까지 다 남기고 싶은지는 각자 취향 문제지
게임 개발자 입장에서 보면 이런 식으로 과거 커밋 뜯어고치는 거 자체가 소름 돋음. 공통 조상 찾아서 고치는 대신 그냥 원하는 변경을 위에서 만들어서 merge하는 게 맞다고 봄
git rebase --update-refs 쓸 때랑 git history fixup 쓸 때 결과가 다른 것 같은데, 체크아웃한 브랜치 밖에 있는 다른 브랜치(E)까지 rebase 되는지 정확히 궁금함
커밋 해시는 부모 해시를 포함하니까 애초에 E가 안 바뀌는 건 불가능함. 질문자가 생각한 세 번째 그래프가 맞는 결과고, 이미 그렇게 동작하는 거임
git 배워서 코딩뿐 아니라 웹사이트, 전자공학, 음악 작업, 개인 지식 관리까지 다 git으로 관리함. 완벽하진 않아도 주변 사람들한테 다 배우라고 권함
git history reword는 옛 커밋의 오타 고칠 때 유용할 듯, 기존에도 비슷한 방법 있었겠지만 이게 더 이해하기 쉬움
개별 커밋 히스토리 그렇게 열심히 다듬을 필요 있나 싶음. 아무도 나중에 커밋 하나하나 다시 안 읽는데, 그냥 merge 전에 squash 한 번 해버리면 끝 아님?
아니 그 반대임. 코드 보다가 왜 이렇게 짜여있나 싶을 때 커밋 히스토리 보면 맥락 파악에 엄청 도움됨. 큰 덩어리로 뭉쳐놓으면 그 맥락 다 사라짐
테스트랑 그 테스트를 통과시키는 fix를 별도 커밋으로 나눠두면, 테스트가 먼저 fail하는 걸 확인할 수 있어서 false negative 방지에 좋음
커밋 하나에 논리적 변경 하나씩 잘 정리해두면 bisect로 회귀 버그 찾을 때 진짜 큰 도움이 됨
나는 커밋 히스토리 자주 들여다봄. 버그나 회귀 추적할 때, 그리고 작성자 의도 이해할 때 잘 정리된 히스토리가 진짜 값어치가 있음