빌드노트
git commit --only에 파일을 줬더니 stage 뒤의 수정까지 들어갔다
stage 뒤 다시 수정한 파일을 --only 경로로 커밋하면 현재 작업 파일 내용이 저장된다. 경로 없는 커밋과 새 독립 저장소에서 비교해, 대상 파일의 인덱스 갱신과 다른 파일의 staged 변경 보존을 확인한다.
git add한 파일을 다시 수정한 뒤 git commit --only ... -- note.txt를 실행하면, add 당시에는 없던 수정까지 커밋에 들어갈 수 있다. 경로를 지정한 `--only`는 그 파일의 현재 작업 트리 내용을 가져온다. 인덱스에 준비해 둔 내용에서 파일명만 골라 커밋하는 옵션으로 생각하면 결과가 어긋난다. 파일 경로와 -a 같은 자동 스테이징 옵션이 없는 일반 커밋은 인덱스의 내용을 기록한다. Git commit 공식 문서 (새 탭에서 열림)
여기서는 이미 추적 중인 텍스트 파일에 새 일반 커밋을 만드는 경우를 비교한다. 마지막 커밋의 메시지를 바꾸는 amend는 다루지 않는다. 인덱스는 git add로 준비한 파일 내용이고, 작업 트리는 편집기로 수정하고 저장한 현재 파일이다. 둘은 같은 파일명 아래 서로 다른 버전을 가질 수 있다.
커밋 전에 두 diff에서 서로 다른 수정을 읽는다
저장소 루트에서 대상 파일의 staged 변경과 그 뒤의 수정을 각각 확인한다. 아래 note.txt는 확인할 추적 파일의 경로로 바꾼다. 첫 명령이 의도한 저장소를 가리키는지 보고, 어느 명령이든 오류가 나면 다음 단계로 넘어가지 않는다.
git rev-parse --show-toplevel
git diff --cached -- note.txt
git diff -- note.txt
--cached가 붙은 diff는 기본적으로 현재 커밋인 HEAD와 인덱스를 비교한다. 마지막 diff는 인덱스와 작업 파일을 비교한다. 따라서 첫 diff만 읽고 --only로 커밋하면, 두 번째 diff에 있던 수정도 함께 가져올 수 있다. Git diff의 비교 대상 (새 탭에서 열림)
이를 확인하려고 새 독립 저장소마다 note.txt와 other.txt를 준비했다. 두 파일의 최초 커밋 내용은 모두 version=base 한 줄이었다. note.txt를 version=staged로 바꾸고, other.txt를 version=other-staged로 바꾼 뒤 두 파일을 add했다. 그다음 note.txt만 version=working으로 다시 수정하고 add하지 않았다.
이 상태에서 위의 cached diff에 나온 핵심 변경 두 줄은 다음과 같다. diff의 파일명과 위치를 나타내는 헤더는 생략했다.
-version=base
+version=staged
그다음 일반 diff에는 add 이후의 변경이 나왔다.
-version=staged
+version=working
두 출력이 모두 있다는 것은 note.txt가 staged 상태이면서 추가 수정도 있다는 뜻이다. 지금 선택해야 할 것은 파일명 하나만이 아니다. version=staged를 커밋할지, version=working까지 커밋할지를 먼저 정해야 한다.
같은 상태에서 커밋 명령만 바꿨다
직접 실행한 환경은 Windows 11, Git 2.45.1.windows.1, PowerShell 7.6.6이다. 아래 두 명령은 같은 저장소에서 이어 실행하지 않았다. 각각 별도 저장소를 위와 같은 상태로 만든 뒤 한 번씩 실행했다.
먼저 경로를 붙이지 않고 준비한 인덱스를 커밋했다.
git commit -m 'Record staged changes'
새 커밋에는 note.txt의 version=staged와 other.txt의 version=other-staged가 들어갔다. 커밋 뒤 git diff --cached는 비었고, git diff에는 note.txt의 staged에서 working으로 바뀌는 수정이 남았다. 두 파일을 add했으므로 둘 다 커밋됐고, add 이후의 수정은 남은 결과다.
다른 저장소에서는 현재 note.txt만 커밋하도록 경로를 지정했다.
git commit --only -m 'Record note' -- note.txt
이번 새 커밋의 note.txt는 version=working이었다. other.txt는 이전 커밋의 version=base 그대로였다. 즉, 지정한 파일은 add 이후의 수정까지 들어갔고, 지정하지 않은 파일의 staged 변경은 이번 커밋에서 빠졌다.
이 결과는 --only를 빼는 것으로 바뀌지 않는다. 세 번째 새 저장소에서 git commit -m 'Record note' -- note.txt도 실행했고, 커밋의 파일 스냅샷인 tree와 남은 두 diff가 --only를 쓴 경우와 같았다. 경로를 주면 이 방식이 기본이라는 설명은 Git 2.45.0의 --only 문서 (새 탭에서 열림)에도 있다. 중간의 --는 이후 인자를 옵션으로 해석하지 않게 하는 구분자다.
다른 파일은 남지만 대상 파일의 예전 staged 내용은 바뀐다
--only 커밋 뒤에는 무엇이 저장됐고 무엇이 남았는지 나눠서 확인한다. 다음 명령은 바로 앞 --only 예제의 결과를 읽는다.
git show HEAD:note.txt
git show HEAD:other.txt
git diff --cached
git diff
git show :note.txt
첫 두 명령은 커밋에 저장된 파일 내용을 읽는다. 실험에서는 차례로 version=working, version=base가 출력됐다. cached diff에는 other.txt의 다음 변경만 남았다. 역시 헤더를 뺀 변경 줄이다.
-version=base
+version=other-staged
따라서 other.txt의 변경은 사라지지 않았다. 다음 커밋을 위해 계속 staged 상태로 남았다. 반면 일반 diff는 아무것도 출력하지 않았다. note.txt의 최신 수정이 이미 커밋에 들어갔고, other.txt는 인덱스와 작업 파일이 같았기 때문이다. 일반 diff가 비었다는 사실만으로 staged 변경까지 없다고 판단하면 안 된다.
마지막 git show :note.txt는 인덱스에 든 내용을 읽으며, 여기서도 version=working이 출력됐다. HEAD:경로와 :경로의 의미는 Git revision 표기 문서 (새 탭에서 열림)에 설명돼 있다. `--only`가 모든 인덱스를 그대로 보존하는 것은 아니다. 이 실험에서 대상 파일의 인덱스는 커밋한 최신 내용으로 갱신됐고, 다른 파일의 staged 내용이 보존됐다. 이전의 version=staged가 대상 파일의 인덱스에 계속 남을 것이라고 기대해서는 안 된다.
자신의 결과가 다르다면 빈 출력만 보고 끝내지 말고, 먼저 명령의 오류 여부와 실제 HEAD:경로 내용을 확인한다. 커밋 전 두 버전이 정말 달랐는지, 다른 옵션을 함께 썼는지, 훅이 내용을 바꾸었는지도 확인할 대상이다.
add 당시의 note.txt만 담으려면 인덱스를 먼저 정리한다
목적이 “최신 작업 파일”이 아니라 “이미 add한 note.txt만”인 경우에는 경로를 붙인 커밋을 선택하지 않는다. 처음 상태로 준비한 네 번째 저장소에서는 other.txt를 staged 목록에서 뺀 뒤, 남은 인덱스 전체를 읽고 경로 없는 커밋을 했다. 다음 절차는 아직 커밋하기 전인 그 상태에서 실행하는 대안이다.
git restore --staged -- other.txt
git diff --cached
git commit -m 'Record staged note'
restore --staged는 작업 파일을 유지하면서 인덱스를 기본값인 HEAD 내용으로 되돌린다. 실행 전 other.txt를 이번 커밋에서 뺄 대상인지 확인한다. 이어 나오는 cached diff 전체에 note.txt의 base에서 staged로 바뀌는 수정만 있는지 읽고 커밋한다. 다른 변경도 보이면 먼저 커밋 범위를 다시 정리한다. Git restore의 복원 대상과 기본 입력 (새 탭에서 열림)
이 대안의 새 커밋에는 note.txt의 version=staged만 반영됐다. git diff --cached는 비었고, 일반 diff에는 note.txt의 추가 수정과 other.txt의 수정이 모두 남았다. 두 작업 파일의 내용은 유지됐지만, other.txt의 staged 상태는 해제됐다. 다른 파일의 스테이징을 그대로 남겨 두는 --only와는 이 점도 다르다.
선택 기준은 커밋에 넣을 버전이다. 인덱스에 준비한 내용을 기록하려면 경로 없는 일반 커밋 전에 인덱스 전체를 확인한다. 지정 파일의 현재 내용을 기록하면서 다른 파일의 staged 변경을 남길 목적이면 --only -- 경로를 쓴다. 파일명만 보고 고르지 말고, 처음 확인한 두 diff 중 어느 변경까지 이번 커밋에 들어가야 하는지를 기준으로 고른다.
직접 비교한 범위는 기존 커밋이 있는 저장소의 충돌 없는 추적 텍스트 파일 두 개다. 훅·커밋 서명·줄바꿈 자동 변환을 끈 환경에서 실행했다. 새 미추적 파일, 삭제·이름 변경, 충돌 또는 병합 진행 중인 상태, sparse checkout과 다른 운영체제는 시험하지 않았다. 부분 스테이징을 복원하는 절차도 검증하지 않았다.