저장소마다 인덱스는 하나야
다들 아는데 아무도 적용 안 하는 사실이 이거야. 스테이징 영역은 세션 상태가 아니라 저장소 상태야. 세션 셋이 체크아웃 하나에서 일하면 그걸 공유해. 그리고 커밋을 자기 경로로 좁히는 예의 바른 수는 보이는 것만큼 안 지켜줘. 어느 쪽 절반이 작동하는지를 정확히 알아야 해. 거꾸로 아는 경우가 흔하거든. 경로를 받은 커밋은 다른 스테이징된 걸 무시해. 그 절반은 문서에 있고 믿을 만해. 못 하는 건 네가 지명한 파일 안쪽을 지키는 거야. 거기선 작업 트리를 커밋하니까 이웃의 반쯤 된 편집까지 같이 들어가. 그리고 평범한 방식으로 커밋을 빚으면 git add 가 공유 인덱스에 돌아서, 네 스테이징이 이웃 걸 덮어써.
측정된 판. 어떤 세션이 커밋을 자기 경로로 좁혔는데 이웃이 파일 아흔둘을 스테이징해둔 상태였어. 이웃의 집합은 문서 그대로 커밋 밖에 남았어. 그런데도 그 세션은 그걸 무시할 수 없었어. 자기가 한 add 하나하나가 그 이웃이 일하고 있는 인덱스에 쓰였으니까.
배관에 손을 뻗는 이유 둘
처방은 공유 인덱스를 아예 안 건드리고 커밋을 빚는 거야. 임시 인덱스 파일을 가리킬 수 있게 해주는 저수준 명령을 써서.
격리. 고른 베이스 트리에서 시작해서, 정확히 네 경로만 추가하고, 트리를 쓰고, 커밋 객체를 만들어. 공유 인덱스는 읽히지도 쓰이지도 않으니까, 이웃의 스테이징된 작업이 너랑 같이 갈 수 없고 네 커밋이 그들 걸 흔들 수도 없어.
훅 없음. 배관은 사전 커밋 훅을 안 태워. 그 훅이 자산 재생성이나 외부 서비스 동기화 같은, 진짜지만 비싼 일을 할 땐 커밋 하나가 다들 필요로 하는 잠금 파일을 쥔 채로 몇 분짜리 작업이 돼. 자동 착지를 거기서 우회시키니까 착지가 몇 분에서 몇 초가 됐고, 사람이 치는 보통 커밋은 훅이랑 훅이 하던 일을 그대로 유지했어.
브랜치를 안전하게 옮기기
커밋 객체를 만든다고 뭐가 움직이는 건 아냐. 브랜치 참조를 여전히 갱신해야 해. 그건 비교 후 교체로 해. 시작할 때 가리키던 자리를 여전히 가리키고 있을 때만 참조를 갱신하는 거야. 그 사이에 누가 옮겼으면 갱신이 깨끗하게 실패하고, 맞는 대응은 강제가 아니라 새 끝 위에 다시 빚는 거야.
참조를 옮기기 전에 검사 하나가 더 속해. 커밋의 파일 목록이 이 작업이 건드려도 되는 경로의 부분집합인지 확인해. 싸고, 경로 패턴이 의도보다 많이 잡힌 경우를 잡고, 상관없는 파일을 조용히 쓸어담은 착지랑 거부한 착지를 가르는 차이야.