#git index를 좀 더 자세히 - ‘Why Should I Care about the Index?’를 보고
A Tale of Three Trees는 index를 비롯해 HEAD, wd(working directory)를 쉽게 설명한다. 여기서 index에 대한 이해가 부족했는데, index를 더 자세히 설명한 자료가 있어서 정리.
기본적인 세 가지 속성
- binary file
- maps paths to blob ids
- cached lstat information
index는 이런 세 가지 속성을 가진다.
$ cat .git/index
....... binary. 알아볼 수가 없다 .....
index는 .git/index에 저장한다.
$ git ls-files --stage --abbrev
100644 175d9db 0 hello.txt
100644 13c909c 0 hello2.txt
git ls-files로 index 내용을 볼 수 있다. blob id와 path 매핑 정보를 가지고 있다. 100644는 실행할 수 없는 일반 파일 모드. 0은 slot 번호이다. 이건 뒤에서 다시 설명.
$ git ls-files --debug
hello.txt
ctime: 1385003406:0
mtime: 1385004359:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 35 flags: 0
hello2.txt
ctime: 1385003688:0
mtime: 1385007769:0
dev: 0 ino: 0
uid: 0 gid: 0
size: 13 flags: 0
debug 옵션을 사용하면 더 많은 정보를 볼 수 있다. git add로 index를 안 해도 정보가 나온다. diff, status와 같은 tree 명령을 빠르게 하려고 정보를 캐시 하는데도 사용하기 때문.
index 파일 삭제 및 재생성
$ rm .git/index
index를 지우면 어떻게 될까?
$ git status
# HEAD detached at cf2ea2a
# Changes to be committed:
# (use "git reset HEAD ..." to unstage)
#
# deleted: hello.txt
# deleted: hello2.txt
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# hello.txt
# hello2.txt
위는 index와 HEAD를 비교한 결과고 아래는 index와 wd를 비교한 결과다. index가 없어서 위와 같은 결과가 나온다. HEAD와 빈 index를 비교하니 모두 삭제됐다고 나온다. 마찬가지로 wd와 빈 index를 비교하니 파일 두 개 다 버전 컨트롤이 안 된다고 나온다.
$ git reset --mixed HEAD
mixed 옵션으로 wd는 놔두고 index까지만 HEAD로 reset한다. 즉, HEAD로부터 index를 다시 만든다. 혹은 read-tree 명령으로 tree object를 직접 읽어서 index를 생성할 수도 있다.
slot 번호는 어디에 사용하나?
$ git merge dev
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
충돌(conflict)났다. 그럼 이 정보는 어디에 저장할까?
$ git ls-files -s --abbrev
100644 3b18e51 1 hello.txt
100644 33d2bc8 2 hello.txt
100644 516583e 3 hello.txt
바로 index. 충돌 났을 때는 slot 1, 2, 3을 사용한다. 평온한 상태면 slot 0을 사용한다.
$ git show 3b18e51
hello world
$ git show 33d2bc8
hello [master] world
$ git show 516583e
hello [dev] world
slot 1에 공통 조상(common ancestor), 2에 ours(target), 3에 theirs(source)를 저장한다.
$ cat hello.txt
<<<<<<< HEAD hello [master] world ======= hello [dev] world >>>>>>> dev
$ vim hello.txt
$ cat hello.txt
hello [master, dev] world
$ git add hello.txt
resolve하고 index 업데이트.
$ git ls-files -s --abbrev
100644 9706440 0 hello.txt
slot 0으로 바뀌었다. 이제 commit을 할 수 있다. git은 slot 번호를 보고 충돌 여부를 판단한다.
$ git checkout -m hello.txt
$ git ls-files -s --abbrev
100644 3b18e51 1 hello.txt
100644 33d2bc8 2 hello.txt
100644 516583e 3 hello.txt
$ cat hello.txt
<<<<<<< ours hello [master] world ======= hello [dev] world >>>>>>> theirs
이 산이 아닌가벼. resolve를 잘못했다면 git checkout -m으로 돌릴 수 있다.