#git HEAD, index, working directory 이해하기 - A Tale of Three Trees 발표자료를 보고

2 minute read

nil

커밋(commit)이 바로 안 되네. index라는 게 있네. HEAD는 또 뭐람? 이게 git 첫인상이었다. 쉽게 정리한 ’A Tale of Three Trees’ 발표자료 덕에 헷갈렸던 개념을 정리할 수 있었다.

index

index는 다음 커밋 재료를 저장하는 공간이다. dircache, cache, staging area라고 부르기도 한다.

git은 wd(working directory)와 index를 나눈다. 딱 선을 그어 확실히 분리한 건 처음 봤다. svn, perforce, alienbrain을 써봤는데, 모두 index를 감춘다. 감춘다고 모두 감추는 건 아니다. 수정은 감추지만, 버전 컨트롤을 할 것인가? 안 할 것인가? 이건 명령어로 수행한다. svn add, svn rm과 같은 명령어다.

이렇게 분리해서 얻는 이익은 뭔가? 조금 불편해도 명확하긴 하다. add, rm 만 명시적으로 하는 게 찝찝하잖아. 당연히 내용 변경도 이렇게 명령을 통해서 커밋 재료를 만들어야지. 이런 몸은 불편하지만, 정신이 위로받을 수 있는 단순함 때문에 추가한 건 아니겠지? 아니지. 일부분만 커밋할 때, 충돌(conflict)을 해결할 때, 커밋을 다시 할 때, index를 유용하게 사용할 수 있다.

HEAD

HEAD는 마지막 커밋을 가리킨다. index 후 커밋하면 부모가 될 녀석이다.

이것도 좀 의외였다. 커밋을 하면 어디에 추가를 하지? 현재 branch 최근 커밋으로 추가하는 게 당연하다고 생각하고 있었다. 그런데, 이것도 노출했구나.

nil

$ git reset --soft HEAD~2
$ git commit

저 산이 아니었나벼~ HEAD를 조작할 수 있어서 저런 게 가능하다. “아니 저런 게 얼마나 위험한지 알아요? 그러니깐 제가 감춥니다.” 보다는 “난 널 믿어. X돼도 니 사정이지 뭐. 하지만 넌 유능하니깐 잘하리라 믿어.” 라고 말하는 것 같다.

wd는 sandbox. 정리는 생략. reset, checkout은 HEAD, index, wd를 변경한다. 이 관점에서 reset과 checkout을 정리해보자.

reset

nil

reset은 HEAD가 가리키는 branch도 같이 변경한다. checkout과 다른 점.

soft, mixed, hard 옵션이 있다. 구분이 어려웠는데, 이 슬라이드를 보니 쉽게 이해가 된다. 이 옵션을 각각 1 step, 2 step, 3 step으로 이해하면 된다.

checkout

nil

reset과 다르게 HEAD만 이동한다.

nil

checkout은 reset –hard와 달리 wd가 안전하다.

$ git checkout HEAD~
error: Your local changes to the following files would be overwritten by checkout:
hello.txt
Please, commit your changes or stash them before you can switch branches.
Aborting

hello.txt를 변경하고 git checkout을 수행한 결과. wd와 merge하는데, 충돌하면 명령을 취소한다. 위는 wd에서 변경한 hello.txt와 충돌했기 때문. hello.txt만 HEAD~에서 변경하고 현재 working directory에서 hello2.txt를 변경했다면 checkout이 성공한다. 이렇게 충돌 나면 취소해서 wd를 보호한다.

반면 reset은 충돌이고 뭐고 없음. merge 시도를 안 하니깐. 그냥 overwrite. 그래서 wd가 안전하지 않다.

여기까지 보면 reset hard는 무서운 놈. checkout은 그래도 좀 덜 무서운 놈이다. 그런데 file은 전혀 반대다. 옵션을 보면 이유를 알 수 있는데, path를 인자로 넘길 때는 soft, hard가 불가능하다. mixed만 가능(reset 디폴트 옵션)하다.

파일 레벨에선 checkout이 더 터프하다. 왜냐면 reset은 hard 같은 옵션을 사용할 수 없기 때문. index만 변경한다. 그래서 git add path 반대 명령어는 git reset path이다.

checkout은 wd가 안전하다고 생각했다. 하지만 파일 레벨로 명령을 수행할 땐, 또 그게 아니다. 그래서 좀 헷갈려.

git status

nil

이제 git status로 나온 명령어가 다르게 보인다. 어떤 걸 diff한 결과인지.

결론

nil

HEAD, Index, Working Directory 역할을 잘 모르겠다. 헷갈린다. 그렇다면 이 발표를 추천한다. 이 아저씨 발표자료도 잘 만든다.

git은 섹시하다. 노출을 많이 해서.

참고