Refactoring
문제
리팩토링 중에 관심사가 다른 변경이 한 커밋에 섞였습니다. 아직 푸시는 안 했는데, 이대로 두면 리뷰도 되돌리기도 어려워집니다.
- 미푸시 확인
- reset --mixed로 되돌리기
- 파일 단위로 재스테이징
- 한 파일에 섞였으면 hunk 단위로 분리
- 그룹별 커밋
- diff 공집합으로 검증
추천
미푸시 커밋을 git reset --mixed로 되돌린 뒤 관심사별로 다시 쌓습니다. 파일 단위로 안
갈리면 hunk 단위로 쪼갭니다. 대화형 git add -p는 에이전트 환경에서 쓸 수 없습니다.
이유
되돌리기 전에 미푸시인지부터 확인합니다. git branch -r --contains <해시>가 비어 있어야
안전합니다. 이미 원격 브랜치에 올라간 커밋을 reset --mixed로 되돌리면 히스토리가 갈립니다.
확인이 끝나면 git reset --mixed HEAD~1로 커밋을 풀고, 파일 단위로 갈리면 그룹별로
git add -- <파일들>만 하면 됩니다. 문제는 한 파일 안에 관심사가 섞였을 때입니다. 대화형
git add -p로 hunk를 골라내는 방법이 표준이지만, 에이전트 세션에는 그 상호작용이 없습니다.
대신 git diff를 패치 파일로 뜨고, awk로 hunk 헤더(^@@) 번호를 세어 원하는 hunk만
골라 git apply --cached로 스테이징합니다.
줄 번호를 다시 계산할 필요는 없습니다. git apply는 컨텍스트로 위치를 찾고 오프셋을
허용합니다. 분리가 제대로 됐는지는 git diff <원래 커밋> HEAD가 공집합인 것 하나로
검증됩니다. 두 커밋으로 나눈 변경의 합이 원래 커밋과 정확히 같아야 합니다.
애초에 부분 스테이징 상태(같은 파일이 staged + unstaged)에서 나누려 하면 안 됩니다.
git reset 후 재스테이징하는 과정에서 이미 골라둔 hunk 선택이 사라집니다. hunk를 고르는
작업은 한 번에 끝내야 합니다.
커밋 관련 자동화는 “메시지만 만들기”와 “커밋 실행”을 분리된 모드로 둡니다. “메시지만 뽑아줘”라고 했는데 커밋까지 실행되면 되돌리는 비용이 발생합니다. 커밋을 여러 개로 쪼개는 작업에서는 그룹을 확정하기 전에 실행되기 쉬우므로 이 분리가 더 중요합니다.
예시
미푸시 확인부터 시작합니다.
git log -1 --format=%H # 나눌 커밋의 해시git branch -r --contains <해시> # 비어 있어야 안전git reset --mixed HEAD~1파일 단위로 갈리면:
git add -- src/feature-a.ts src/feature-a.test.tsgit commit -m "feature-a 관련 변경"git add -- src/feature-b.tsgit commit -m "feature-b 관련 변경"한 파일에 관심사가 섞였으면 hunk 단위로 쪼갭니다.
git diff -- src/mixed.ts > mixed.patchawk '/^@@/{h++} h==0 || h==2' mixed.patch > group1.patchgit apply --cached group1.patch마지막에 반드시 검증합니다.
git diff <원래커밋> HEAD # 출력이 없어야 한다하지 말 것
이미 푸시된 커밋을 reset --mixed로 되돌리기. git branch -r --contains를 건너뛰면
히스토리가 갈린다는 것을 나중에야 알게 됩니다.
부분 스테이징 상태에서 나누려 하기. git reset이 끼어드는 순간 이미 골라둔 hunk 선택이
날아갑니다.
“메시지만 뽑아줘”에 커밋까지 실행하기. 메시지 생성과 커밋 실행은 별개 요청입니다. 특히 커밋을 쪼개는 작업 중에는 실행이 앞서면 되돌리는 비용이 또 듭니다.