git history 명령
9 hours ago
4
- Git 2.54와 2.55에 걸쳐 도입된 실험적 git history 명령은 기존 Git 작업 흐름을 유지하면서 과거 커밋 수정과 파생 브랜치 재구성을 자동화함
- fixup 은 스테이징한 변경을 과거 커밋에 합친 뒤, 해당 커밋에서 파생된 모든 로컬 브랜치를 새로운 커밋 해시에 맞춰 자동 리베이스함
- reword 는 과거 커밋 메시지를 바꾸고, split 은 커밋의 변경 내역을 헝크 단위로 나눠 두 커밋으로 분리한 뒤 후속 커밋과 브랜치를 다시 구성함
- 세 하위 명령은 충돌 가능성이 있는 작업을 거부하는 원자적 처리로 작업 트리가 중간에 깨지는 상황을 막지만, 병합 커밋이 있는 이력에서는 동작하지 않음
- jj의 1급 충돌 처리, 작업 로그 기반 실행 취소, 작업 복사본의 커밋 모델링까지 제공하지는 않지만, 별도 설치 없이 Git 코어 배포판에서 여러 jj식 이력 편집 기능을 사용할 수 있음
기존 Git 이력 편집이 불편한 이유
- 여러 변경을 병렬로 다루면 브랜치와 커밋을 계속 오가야 하며, rebase -i 도중 작업 트리가 불완전한 상태에 빠질 수 있음
- Git 대안인 jj는 이런 문제의 해결책으로 자주 거론되지만, 1년 반 동안 3개월마다 며칠씩 시도해도 결국 기존 Git 작업 흐름으로 돌아오게 됨
- git history는 Git 코어 배포판에 포함된 실험적 명령이어서 별도 도구를 설치하지 않고 시험할 수 있음
- 하위 명령은 fixup, reword, split 세 가지로 구성됨
fixup: 과거 커밋과 파생 브랜치 동시 수정
- git history fixup은 과거 커밋의 잘못된 부분을 수정하고, 그 커밋에서 파생된 브랜치를 자동으로 리베이스함
- 일반적인 수정 절차처럼 git add로 변경을 스테이징한 뒤 git history fixup <commit> 을 실행하면 스테이징된 변경이 대상 커밋에 합쳐짐
- git commit --fixup과 autosquash 리베이스를 합친 것과 비슷하지만, 대상 커밋을 포함하는 다른 브랜치까지 갱신한다는 차이가 있음
- git rebase --update-refs가 현재 리베이스 범위 안의 참조만 이동하는 데 비해, git history는 대상 커밋에서 파생된 모든 로컬 브랜치를 찾아 다시 작성함
- 필요하면 갱신 범위를 현재 브랜치로만 제한할 수 있음
- 병합 커밋이 있는 이력에서는 동작하지 않아 일부 Git 사용 방식에는 적용하기 어려움
- B에 수정 사항을 합치면 새로운 해시를 가진 B*가 생성되고, 그 위의 C와 D도 각각 C*, D*로 다시 만들어짐
- feat-1과 feat-2의 브랜치 끝도 새 커밋을 따라 이동함
원자적 처리와 충돌 제한
- 세 하위 명령은 모두 원자적으로 처리돼 작업 트리를 반쯤 깨진 상태로 남기지 않음
- 충돌을 일으킬 수 있는 작업 자체를 거부하는 방식으로 원자성을 보장함
- 이는 충돌을 1급 객체로 처리해 리베이스 도중 충돌 상태를 유지하고 나중에 해결할 수 있는 jj보다 기능적으로 제한적임
- git history 제한 사항은 이력 재작성이 상태 보존 작업으로 바뀌지 않도록 의도적으로 적용된 것임
- Git이 향후 1급 충돌을 지원하면 이 제한을 해제할 수 있음
reword: 작업 트리 없이 커밋 메시지 변경
- git history reword는 과거 커밋 메시지를 바꾸고, 그 위의 커밋과 브랜치를 자동으로 다시 구성함
- git history reword <commit> 을 실행하면 편집기에 기존 메시지가 열리며, 수정 후 저장하면 후속 커밋 스택이 새 해시에 맞춰 재구축됨
- 반복 개발 중 설계가 바뀌었을 때 이전 커밋 메시지를 현재 구조에 맞게 고치는 데 유용함
- 트리 내용 대신 커밋 메시지만 바꾼다는 점을 제외하면 fixup과 같은 방식으로 동작함
- reword는 인덱스나 작업 트리를 건드리지 않고 커밋 그래프만 변경함
- 체크아웃하지 않은 브랜치의 커밋도 현재 작업을 방해하지 않고 수정할 수 있음
- B의 메시지를 바꾸면 해시가 달라지므로 후속 C는 C*로 다시 만들어지고 feat-1도 새 커밋을 따라감
split: 하나의 커밋을 둘로 분리
- git history split은 한 커밋의 변경을 대화식으로 선택해 두 커밋으로 나눔
- git history split <commit> 을 실행하면 대상 커밋의 변경 내역을 헝크 단위로 선택하는 프롬프트가 열림
- 선택해 유지한 헝크는 첫 번째 커밋을 구성함
- 나머지 헝크는 두 번째 커밋에 들어감
- git add -p와 비슷하지만 git rebase를 조합하는 복잡한 절차가 필요 없음
- 서로 관련 없는 두 변경이 들어 있던 B를 분할하면 B1과 B2가 생성되고, 후속 C는 두 커밋 위에 C*로 재구축됨
- 세 명령 중 사용 범위가 가장 특화돼 있지만, 커밋을 실제로 분리해야 할 때 유용함
jj와의 기능 차이
- git history는 jj가 제공하는 전체 작업 모델을 대체하지 않음
- 반면 git history는 기존 Git 안에서 과거 커밋 수정, 메시지 변경, 커밋 분할과 파생 브랜치 갱신을 지원해 jj의 일부 장점을 현재 작업 흐름에 도입할 수 있음
- 향후 제한을 완화할 가능성이 열려 있어 이후 Git 릴리스에서 추가로 개선될 여지가 있음
-
Homepage
-
Tech blog
- git history 명령