cd $HOME/lab
rm -rf test_internal_02
git init test_internal_02
cd test_internal_02인덱스 파일
git 기본 명령의 내부 구조
- add, commit 등의 명령으로 파일이 등록되는 과정은 내부적으로 다음과 같은 고급 명령을 사용한다.
- 이 중심에는 인덱스 파일이 있다.
| 순번 | git 명령 | 내부 동작 | 설명 |
|---|---|---|---|
| 1 | git add | 블롭 객체 생성 | git hash-object 명령으로 블롭 객체 생성 |
| 2 | - | 인덱스 등록 | git update-index 명령으로 인덱스 파일에 스테이징 정보 등록 |
| 3 | git commit | 트리 객체 생성 | git write-tree 명령으로 인덱스 파일정보를 이용하여 트리 객체 생성 |
| 4 | - | 커밋 객체 생성 | git commit-tree 명령으로 커밋 객체 생성 |
| 5 | - | 브랜치 갱신 | git update-ref 명령으로 브랜치 정보 갱신 |
실습 1: 레포지토리 준비
- 레포지토리 생성
Initialized empty Git repository in ~/lab/test_internal_02/.git/
tree .git/objects.git/objects
├── info
└── pack
3 directories, 0 files
hash-object 명령
- hash-object 명령은 입력된 데이터를 이용하여 해시값을 계산하고 객체를 생성한다.
-w옵션을 주지 않으면 단순히 해시값만 계산한다.
git hash-object [옵션] 입력파일 경로hash-object 명령의 옵션
-t<유형>- 생성할 객체 유형을 지정
- 기본값: “blob”
- 가능한 값: “commit”, “tree”, “blob”, “tag”
실습 2: 파일의 블롭 객체 생성
echo "file1 line1" > file1.txtgit statusOn branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1.txt
nothing added to commit but untracked files present (use "git add" to track)
- hash-object 명령으로 file1.txt 파일에 대한 해시값을 계산
git hash-object file1.txt0b11cfca50e35a4865e8505f1a108bd23a3f9401
- -w 옵션이 없어서 실재로 블롭객체 파일을 생성하지 않음
tree .git/objects.git/objects
├── info
└── pack
3 directories, 0 files
- -w 옵션을 주면 실재로 블롭객체 파일을 생성함
git hash-object -w file1.txt0b11cfca50e35a4865e8505f1a108bd23a3f9401
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── info
└── pack
4 directories, 1 file
- cat-file 명령으로 블롭객체의 내용을 읽을 수 있음
git cat-file -p 0b11cfca50e35a4865e8505f1a108bd23a3f9401file1 line1
인덱스 파일
- 인덱스 파일은 다음과 같은 정보를 저장하고 제공하는 바이너리 파일
- 사용자가 git commit 명령으로 커밋을 만들 때,
- 이 커밋에 포함될 대상이 되는 모든 파일에 대한 메타 정보와 블롭 객체
- 즉 블롭 객체는 commit 명령 시점에 만드는 것이 아니라 add 명령 시점에 미리 만들어 놓았다가
- commit 명령을 하면 인덱스 파일의 정보를 조합하여 빠르게 생성
- 트리 객체의 정보는 포함하지 않음
- 대신 파일에 대한 메타정보에서 경로 정보 포함
- 트리 객체는 커밋 생성시 실시간으로 생성
- 메타 정보는 다음 포함
- 파일의 블롭 객체에 대한 포인터
- 해당 파일의 워크트리 파일 버전의 최신 변경 시간 등에 대한 정보
- clone, checkout, switch 명령 등으로 헤드 커밋이 바뀌면
- 헤드 커밋에 포함된 모든 대상 파일에 대한 메타 정보가 일단 인덱스 파일에 들어간다.
- 이 상태에서 add 명령을 실행하면
- 스테이지에 올라간 파일의 블롭 객체를 생성하고
- 해당 파일에 대한 메타정보를 인덱스 파일에 등록한다.
- 또한 해당 파일의 과거 버전의 정보는 삭제된다.
update-index 명령
- hash-object 명령은 객체를 만들 뿐이지 스테이지에 넣지는 않는다.
- 스테이지에 객체를 넣는 것은 update-index 명령을 사용한다.
- update-index 명령은 파일의 메타정보와 내용을 인덱스 파일에 등록한다.
- 실행시에 인덱스 파일이 없으면 새로 생성한다.
update-index 명령의 옵션
- -add <유형>
- 인덱스 파일에 파일의 블롭객체를 등록
- –cacheinfo 옵션이 없으면 블롭객체를 직접 생성함
--cacheinfo<모드> <파일의 블롭객체의 해시값> <파일 경로>- 이미 생성된 블롭객체가 존재할 경우 직접 인덱스 파일에 직접 등록
--refresh- 파일 경로 정보를 이용하여 실제 파일에 대해 stat() 시스템 콜을 호출
- 인덱스 파일의 엔트리 헤더(메타정보)가 stat() 시스템 콜 결과와 다르면 갱신
- 블롭객체는 건들지 않는다.
실습 3: 인덱스 파일 생성
- 아직 .git/index 파일이 존재하지 않음
ls -al .gittotal 24
drwxr-xr-x@ 9 joelkim staff 288 Oct 1 22:48 .
drwxr-xr-x@ 4 joelkim staff 128 Oct 1 22:48 ..
-rw-r--r--@ 1 joelkim staff 137 Oct 1 22:48 config
-rw-r--r--@ 1 joelkim staff 73 Oct 1 22:48 description
-rw-r--r--@ 1 joelkim staff 21 Oct 1 22:48 HEAD
drwxr-xr-x@ 16 joelkim staff 512 Oct 1 22:48 hooks
drwxr-xr-x@ 3 joelkim staff 96 Oct 1 22:48 info
drwxr-xr-x@ 5 joelkim staff 160 Oct 1 22:48 objects
drwxr-xr-x@ 4 joelkim staff 128 Oct 1 22:48 refs
- 아까 생성한 블롭 객체를 등록
git update-index --add --cacheinfo 100644 0b11cfca50e35a4865e8505f1a108bd23a3f9401 file1.txt- .git/index 인덱스 파일이 생성됨
ls -al .gittotal 32
drwxr-xr-x@ 10 joelkim staff 320 Oct 1 22:48 .
drwxr-xr-x@ 4 joelkim staff 128 Oct 1 22:48 ..
-rw-r--r--@ 1 joelkim staff 137 Oct 1 22:48 config
-rw-r--r--@ 1 joelkim staff 73 Oct 1 22:48 description
-rw-r--r--@ 1 joelkim staff 21 Oct 1 22:48 HEAD
drwxr-xr-x@ 16 joelkim staff 512 Oct 1 22:48 hooks
-rw-r--r--@ 1 joelkim staff 104 Oct 1 22:48 index
drwxr-xr-x@ 3 joelkim staff 96 Oct 1 22:48 info
drwxr-xr-x@ 5 joelkim staff 160 Oct 1 22:48 objects
drwxr-xr-x@ 4 joelkim staff 128 Oct 1 22:48 refs
- 인덱스 파일의 내용
hexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 01 00 00 00 00 |DIRC............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 81 a4 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 35 4c 42 43 60 45 a6 f6 87 b3 31 4e |txt.5LBC`E....1N|
00000060 84 73 b8 e3 b9 75 79 c3 |.s...uy.|
00000068
- 인덱스 항목 중 워크트리의 메타 정보에 해당하는 헤더 정보가 빠져있음. update-index –refresh 명령으로 갱신
git update-index --refreshhexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 01 68 dd 31 34 |DIRC........h.14|
00000010 0a 54 b4 f9 68 dd 31 34 0a 54 b4 f9 01 00 00 04 |.T..h.14.T......|
00000020 09 94 d2 c2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 0c 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 1e a9 4b b5 42 08 e0 43 0c f1 51 a0 |txt...K.B..C..Q.|
00000060 a9 00 54 70 3b 03 07 3d |..Tp;..=|
00000068
인덱스 파일의 구조
구조
- 인덱스 파일 헤더 (12 바이트)
- 파일에 대한 인덱스 항목들 (가변)
- 확장 영역 (가변)
- 트리 항목 (커밋이 존재하는 경우)
- 체크섬 (20 바이트)
인덱스 파일 헤더
- 총 12 바이트
- 4바이트 시그너쳐 (‘D’, ‘I’, ‘R’, ‘C’) (“dircache”를 뜻함)
- 4바이트 버전숫자 (2~4 중 하나)
- 32비트 인덱스 엔트리 갯수
헤더 예시
44 49 52 43 00 00 00 02 00 00 00 01DIRC, 버전 2, 1개 엔트리
00000000 44 49 52 43 00 00 00 02 00 00 00 01 __ __ __ __ |DIRC........ |
인덱스 항목 구성
- 항목 헤더 (파일의 생성일자, 모드, 크기 등 메타정보)
- 블롭객체 해시값 (파일의 내용)
- 플래그 + 파일 이름
- 엔트리 항목 해시값
항목 헤더 (40 바이트)
- 32 비트 ctime 초 (파일 메터메이터가 최종 변경된 시간)
- 32 비트 ctime 나노초
- 32 비트 mtime 초 (파일 본문 데이터가 최종 변경된 시간)
- 32 비트 mtime 나노초
- 32 비트 dev
- 32 비트 inode 아이디
- 32 비트 모드
- 32 비트 uid
- 32 비트 gid
- 32 비트 파일 크기
00000000 __ __ __ __ __ __ __ __ __ __ __ __ 68 b2 47 74 | h.Gt| 00000010 01 6c 0f fd 68 b2 47 74 01 6c 0f fd 01 00 00 04 |.l..h.Gt.l......| 00000020 09 65 a3 68 00 00 81 a4 00 00 01 f6 00 00 00 14 |.e.h............| 00000030 00 00 00 0c __ __ __ __ __ __ __ __ __ __ __ __ |.... |객체 해시값
- 0b11cfca50e35a4865e8505f1a108bd23a3f9401
00000030 __ __ __ __ 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_| 00000040 1a 10 8b d2 3a 3f 94 01 __ __ __ __ __ __ __ __ |....:?. |플래그(2 바이트) + 파일 이름(8 바이트 배수로 패딩)
00000040 __ __ __ __ __ __ __ __ 00 09 66 69 6c 65 31 2e |. ..file1.| 00000050 74 78 74 00 __ __ __ __ __ __ __ __ __ __ __ __ |txt. |20 바이트 체크섬
00000050 __ __ __ __ 8c 8e e0 4a cb ef 63 04 81 44 a6 22 | ...J..c..D."| 00000060 8f cd 09 a2 39 cb 45 1c |....9.E.|
ls-files 명령
- ls-files 명령은 워크트리와 스테이지, 커밋 내부의 파일 목록을 보여주는 명령
- 워크트리의 파일 목록은 실시간으로 검색하지만
- 스테이지와 커밋 파일 목록을 찾을 때 내부적으로 인덱스 파일을 사용함
ls-files 명령의 옵션
-c- 인덱스 파일의 항목 출력
- 즉, 추적 상태인 파일 목록 출력
- 아무 옵션이 없는 상태와 동일한 결과
--stage,-s- 스테이지 영역의 파일만 출력
--others,-o- 비추적 상태의 파일 목록 출력
--ignored,-i- 무시되고 있는 파일 목록 출력
- 반드시
-o옵션과 같이 사용해야 함
--debug- 메타 정보까지 출력
실습 4: ls-files 출력
- 아직 추적되지 않는 신규 파일 생성
mkdir sub
echo "file2 line1" > sub/file2.txttree ..
├── file1.txt
└── sub
└── file2.txt
2 directories, 2 files
- 추적 상태의 파일 (스테이지 + 커밋)
git ls-filesfile1.txt
- 스테이지 파일
git ls-files -s100644 0b11cfca50e35a4865e8505f1a108bd23a3f9401 0 file1.txt
- 메타 정보 포함
git ls-files --debugfile1.txt
ctime: 1759326516:173323513
mtime: 1759326516:173323513
dev: 16777220 ino: 160748226
uid: 502 gid: 20
size: 12 flags: 0
- 비추적 상태의 파일
git ls-files -osub/file2.txt
실습 5: 다른 파일을 스테이지에 추가
git hash-object -w sub/file2.txt4a8d995103b41f561e547ce3b32e1983d424da22
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── info
└── pack
5 directories, 2 files
git update-index --add --cacheinfo 100644 4a8d995103b41f561e547ce3b32e1983d424da22 sub/file2.txtgit update-index --refreshhexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 02 68 dd 31 34 |DIRC........h.14|
00000010 0a 54 b4 f9 68 dd 31 34 0a 54 b4 f9 01 00 00 04 |.T..h.14.T......|
00000020 09 94 d2 c2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 0c 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 68 dd 31 35 31 23 73 59 68 dd 31 35 |txt.h.151#sYh.15|
00000060 31 23 73 59 01 00 00 04 09 94 d3 17 00 00 81 a4 |1#sY............|
00000070 00 00 01 f6 00 00 00 14 00 00 00 0c 4a 8d 99 51 |............J..Q|
00000080 03 b4 1f 56 1e 54 7c e3 b3 2e 19 83 d4 24 da 22 |...V.T|......$."|
00000090 00 0d 73 75 62 2f 66 69 6c 65 32 2e 74 78 74 00 |..sub/file2.txt.|
000000a0 00 00 00 00 72 94 7e e7 5c e7 11 23 2a ed 37 69 |....r.~.\..#*.7i|
000000b0 37 0f c0 82 3b 47 29 5c |7...;G)\|
000000b8
git ls-files -s100644 0b11cfca50e35a4865e8505f1a108bd23a3f9401 0 file1.txt
100644 4a8d995103b41f561e547ce3b32e1983d424da22 0 sub/file2.txt
git ls-files --debugfile1.txt
ctime: 1759326516:173323513
mtime: 1759326516:173323513
dev: 16777220 ino: 160748226
uid: 502 gid: 20
size: 12 flags: 0
sub/file2.txt
ctime: 1759326517:824406873
mtime: 1759326517:824406873
dev: 16777220 ino: 160748311
uid: 502 gid: 20
size: 12 flags: 0
write-tree 명령
- write-tree 명령은 인덱스 내의 항목을 기반으로 커밋 등록에 필요한 트리 객체들을 생성하고 인덱스 파일에 추가
- 생성된 트리 객체 중 루트 트리의 해시값을 출력
실습 6: 트리 객체 생성
git write-tree4c2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
- 2개의 트리 객체가 만들어진다.
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── 4c
│ └── 2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
├── dd
│ └── 62677237dce0946aeffef97910ffc4ec32c3e7
├── info
└── pack
7 directories, 4 files
- 각 트리 객체의 내용은 다음과 같다.
git cat-file -p 4c2cf5eb3d8af11e9fe5f56cb6c853e1559d7166100644 blob 0b11cfca50e35a4865e8505f1a108bd23a3f9401 file1.txt
040000 tree dd62677237dce0946aeffef97910ffc4ec32c3e7 sub
git cat-file -p dd62677237dce0946aeffef97910ffc4ec32c3e7100644 blob 4a8d995103b41f561e547ce3b32e1983d424da22 file2.txt
- 트리 객체의 경우에는 cat-file -p 명령대신 ls-tree 명령 사용 가능
git ls-tree 4c2cf5eb3d8af11e9fe5f56cb6c853e1559d7166100644 blob 0b11cfca50e35a4865e8505f1a108bd23a3f9401 file1.txt
040000 tree dd62677237dce0946aeffef97910ffc4ec32c3e7 sub
git ls-tree dd62677237dce0946aeffef97910ffc4ec32c3e7100644 blob 4a8d995103b41f561e547ce3b32e1983d424da22 file2.txt
- write-tree 명령은 인덱스 파일에도 생성된 트리 객체의 정보를 넣는다
hexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 02 68 dd 31 34 |DIRC........h.14|
00000010 0a 54 b4 f9 68 dd 31 34 0a 54 b4 f9 01 00 00 04 |.T..h.14.T......|
00000020 09 94 d2 c2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 0c 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 68 dd 31 35 31 23 73 59 68 dd 31 35 |txt.h.151#sYh.15|
00000060 31 23 73 59 01 00 00 04 09 94 d3 17 00 00 81 a4 |1#sY............|
00000070 00 00 01 f6 00 00 00 14 00 00 00 0c 4a 8d 99 51 |............J..Q|
00000080 03 b4 1f 56 1e 54 7c e3 b3 2e 19 83 d4 24 da 22 |...V.T|......$."|
00000090 00 0d 73 75 62 2f 66 69 6c 65 32 2e 74 78 74 00 |..sub/file2.txt.|
000000a0 00 00 00 00 54 52 45 45 00 00 00 35 00 32 20 31 |....TREE...5.2 1|
000000b0 0a 4c 2c f5 eb 3d 8a f1 1e 9f e5 f5 6c b6 c8 53 |.L,..=......l..S|
000000c0 e1 55 9d 71 66 73 75 62 00 31 20 30 0a dd 62 67 |.U.qfsub.1 0..bg|
000000d0 72 37 dc e0 94 6a ef fe f9 79 10 ff c4 ec 32 c3 |r7...j...y....2.|
000000e0 e7 a8 be e7 89 92 f8 9e a3 8c 38 5e 31 01 4b 36 |..........8^1.K6|
000000f0 8d a4 65 4a d5 |..eJ.|
000000f5
status 명령
- status 명령은 실행시 인덱스 파일을 이용하여 다음과 같은 정보를 알아낸다.
- 워크트리의 파일이 추적 상태인지 아닌지 알아낸다.
- 추적 상태의 파일인 경우 변경되었는지 아닌지 알아낸다.
- 파일이 워크트리, 스테이지, 커밋 중 어느 영역에 있는지 알아낸다.
- 방법은 다음과 같다.
- 추적/비추적 여부
- 인덱스 항목에 없는 파일은 비추적 파일이다.
- 인덱스 항목에 있는 파일은 스테이지 또는 커밋 영역의 파일이다. 즉, 추적 상태의 파일이다.
- 추적 파일의 변경 여부
- 워크트리 파일의 해시값이 인덱스 항목의 블롭 객체 해시값과 같으면 변경되지 않은 파일이다.
- 워크트리 파일의 해시값이 인덱스 항목의 블롭 객체 해시값과 다르면 변경된 않은 파일이다.
- 스테이지/커밋 영역의 구별 여부
- 인덱스 항목의 해시값과 같은 해시값을 가지는 블롭 객체가 커밋에 있으면 커밋 영역의 파일이다.
- 인덱스 항목의 해시값과 같은 해시값을 가지는 블롭 객체가 커밋에 없으면 스테이지 영역의 파일이다.
- 추적/비추적 여부
실습 7: 상태 조회
git statusOn branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1.txt
new file: sub/file2.txt
commit-tree 명령
- 커밋 객체를 생성
실습 8: 커밋 객체 생성
GIT_AUTHOR_DATE="2025-01-01T12:00:00" \
GIT_COMMITTER_DATE="2025-01-01T12:00:00" \
git commit-tree -m 'first commit' 4c2cf5eb3d8af11e9fe5f56cb6c853e1559d7166e42955ccb9b2b73c7e81e251cbab0fdc84aed671
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── 4c
│ └── 2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
├── dd
│ └── 62677237dce0946aeffef97910ffc4ec32c3e7
├── e4
│ └── 2955ccb9b2b73c7e81e251cbab0fdc84aed671
├── info
└── pack
8 directories, 5 files
- 커밋 객체는 정상적으로 생성되었음
git cat-file -p e42955ccb9b2b73c7e81e251cbab0fdc84aed671tree 4c2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
author user <user@company.com> 1735700400 +0900
committer user <user@company.com> 1735700400 +0900
first commit
- 그러나 git status 명령으로는 아직 커밋된 상태가 아니라고 나옴
git statusOn branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1.txt
new file: sub/file2.txt
- 로그도 정상 출력되지 않음
git log || truefatal: your current branch 'main' does not have any commits yet
update-ref 명령
- 브랜치가 해당 커밋을 가리키지 않으면 커밋이 생성되었다고 인식하지 않음
- update-ref 명령으로 브랜치가 해당 커밋을 가리키게 만듬
실습 9: 브랜치 참조 파일 생성
- HEAD는 main 브랜치를 가리키고 있음
cat .git/HEADref: refs/heads/main
- 그러나 main 브랜치에 대한 참조 파일이 만들어지지 않았음
tree .git/refs/heads.git/refs/heads
0 directories, 0 files
- update-ref 명령으로 방금 생성한 커밋을 가리키는 main 브랜치 참조 파일 생성
git update-ref refs/heads/main e42955ccb9b2b73c7e81e251cbab0fdc84aed671- 참조 파일이 생성되었음
tree .git/refs/heads.git/refs/heads
└── main
1 directory, 1 file
- 참조 파일은 방금 생성된 커밋 객체를 가리킴
cat .git/refs/heads/maine42955ccb9b2b73c7e81e251cbab0fdc84aed671
- 이제 정상적으로 커밋되었다고 인식함
git statusOn branch main
nothing to commit, working tree clean
- 로그도 정상적으로 출력
git logcommit e42955ccb9b2b73c7e81e251cbab0fdc84aed671 (HEAD -> main)
Author: user <user@company.com>
Date: Wed Jan 1 12:00:00 2025 +0900
first commit
실습 10: add, commit 명령 사용
지금까지 한 작업을 add, commit 명령으로 해본다.
저장소 리셋
cd $HOME/lab
rm -rf test_internal_02
git init test_internal_02
cd test_internal_02Initialized empty Git repository in ~/lab/test_internal_02/.git/
echo "file1 line1" > file1.txt
mkdir sub
echo "file2 line1" > sub/file2.txt
git add .hexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 02 68 dd 31 3a |DIRC........h.1:|
00000010 24 ae 18 fd 68 dd 31 3a 24 ae 18 fd 01 00 00 04 |$...h.1:$.......|
00000020 09 94 d3 a2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 0c 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 68 dd 31 3a 2b 8e 13 1c 68 dd 31 3a |txt.h.1:+...h.1:|
00000060 2b 8e 13 1c 01 00 00 04 09 94 d3 a4 00 00 81 a4 |+...............|
00000070 00 00 01 f6 00 00 00 14 00 00 00 0c 4a 8d 99 51 |............J..Q|
00000080 03 b4 1f 56 1e 54 7c e3 b3 2e 19 83 d4 24 da 22 |...V.T|......$."|
00000090 00 0d 73 75 62 2f 66 69 6c 65 32 2e 74 78 74 00 |..sub/file2.txt.|
000000a0 00 00 00 00 61 3f 6a 01 88 c3 9b 3e c0 52 da 0e |....a?j....>.R..|
000000b0 8e b6 ac d3 cb 87 88 5d |.......]|
000000b8
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── info
└── pack
5 directories, 2 files
GIT_AUTHOR_DATE="2025-01-01T12:00:00" \
GIT_COMMITTER_DATE="2025-01-01T12:00:00" \
git commit -m 'first commit'[main (root-commit) e42955c] first commit
2 files changed, 2 insertions(+)
create mode 100644 file1.txt
create mode 100644 sub/file2.txt
hexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 02 68 dd 31 3a |DIRC........h.1:|
00000010 24 ae 18 fd 68 dd 31 3a 24 ae 18 fd 01 00 00 04 |$...h.1:$.......|
00000020 09 94 d3 a2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 0c 0b 11 cf ca 50 e3 5a 48 65 e8 50 5f |........P.ZHe.P_|
00000040 1a 10 8b d2 3a 3f 94 01 00 09 66 69 6c 65 31 2e |....:?....file1.|
00000050 74 78 74 00 68 dd 31 3a 2b 8e 13 1c 68 dd 31 3a |txt.h.1:+...h.1:|
00000060 2b 8e 13 1c 01 00 00 04 09 94 d3 a4 00 00 81 a4 |+...............|
00000070 00 00 01 f6 00 00 00 14 00 00 00 0c 4a 8d 99 51 |............J..Q|
00000080 03 b4 1f 56 1e 54 7c e3 b3 2e 19 83 d4 24 da 22 |...V.T|......$."|
00000090 00 0d 73 75 62 2f 66 69 6c 65 32 2e 74 78 74 00 |..sub/file2.txt.|
000000a0 00 00 00 00 54 52 45 45 00 00 00 35 00 32 20 31 |....TREE...5.2 1|
000000b0 0a 4c 2c f5 eb 3d 8a f1 1e 9f e5 f5 6c b6 c8 53 |.L,..=......l..S|
000000c0 e1 55 9d 71 66 73 75 62 00 31 20 30 0a dd 62 67 |.U.qfsub.1 0..bg|
000000d0 72 37 dc e0 94 6a ef fe f9 79 10 ff c4 ec 32 c3 |r7...j...y....2.|
000000e0 e7 e0 57 20 e1 7c 46 bb b0 8b 5c f2 55 63 62 9d |..W .|F...\.Ucb.|
000000f0 8b ec 0c 7f e9 |.....|
000000f5
tree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── 4c
│ └── 2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
├── dd
│ └── 62677237dce0946aeffef97910ffc4ec32c3e7
├── e4
│ └── 2955ccb9b2b73c7e81e251cbab0fdc84aed671
├── info
└── pack
8 directories, 5 files
실습 11: 인덱스 파일 항목 변경
- 변경된 파일을 add 하면 인덱스 파일 항목은 기존의 블롭 객체가 아니라 스테이징된 새 항목을 가리킨다.
- 즉, 기존의 블롭 객체는 인덱스 파일에서 제거된다.
echo "file1 line2" >> file1.txt
git add file1.txttree .git/objects.git/objects
├── 0b
│ └── 11cfca50e35a4865e8505f1a108bd23a3f9401
├── 4a
│ └── 8d995103b41f561e547ce3b32e1983d424da22
├── 4c
│ └── 2cf5eb3d8af11e9fe5f56cb6c853e1559d7166
├── d0
│ └── 37497f0226612d0c089c061a84788a3721f9e9
├── dd
│ └── 62677237dce0946aeffef97910ffc4ec32c3e7
├── e4
│ └── 2955ccb9b2b73c7e81e251cbab0fdc84aed671
├── info
└── pack
9 directories, 6 files
- 인덱스 파일 내부를 보면 항목은 여전히 2개
- file1.txt에 대한 해시값이 새로운 값으로 변경되었음
hexdump -C .git/index00000000 44 49 52 43 00 00 00 02 00 00 00 02 68 dd 31 3b |DIRC........h.1;|
00000010 2b 97 a8 2f 68 dd 31 3b 2b 97 a8 2f 01 00 00 04 |+../h.1;+../....|
00000020 09 94 d3 a2 00 00 81 a4 00 00 01 f6 00 00 00 14 |................|
00000030 00 00 00 18 d0 37 49 7f 02 26 61 2d 0c 08 9c 06 |.....7I..&a-....|
00000040 1a 84 78 8a 37 21 f9 e9 00 09 66 69 6c 65 31 2e |..x.7!....file1.|
00000050 74 78 74 00 68 dd 31 3a 2b 8e 13 1c 68 dd 31 3a |txt.h.1:+...h.1:|
00000060 2b 8e 13 1c 01 00 00 04 09 94 d3 a4 00 00 81 a4 |+...............|
00000070 00 00 01 f6 00 00 00 14 00 00 00 0c 4a 8d 99 51 |............J..Q|
00000080 03 b4 1f 56 1e 54 7c e3 b3 2e 19 83 d4 24 da 22 |...V.T|......$."|
00000090 00 0d 73 75 62 2f 66 69 6c 65 32 2e 74 78 74 00 |..sub/file2.txt.|
000000a0 00 00 00 00 54 52 45 45 00 00 00 22 00 2d 31 20 |....TREE...".-1 |
000000b0 31 0a 73 75 62 00 31 20 30 0a dd 62 67 72 37 dc |1.sub.1 0..bgr7.|
000000c0 e0 94 6a ef fe f9 79 10 ff c4 ec 32 c3 e7 25 32 |..j...y....2..%2|
000000d0 3a e6 24 a8 d2 dd 3a 75 9c c2 1f d7 55 78 bb f2 |:.$...:u....Ux..|
000000e0 69 17 |i.|
000000e2
인덱스 락 파일
- 인덱스 파일에 두 개 이상의 프로세스가 동시에 쓰기를 허용하면 누락 정보가 발생할 수 있음
- 따라서 인덱스 파일에 대한 쓰기 작업은 한 번에 하나의 프로세스만 가능
- 먼저 쓰기를 시도하는 프로세스가 인덱스 파일을 복사한
index.lock이라는 인덱스 락 파일을 생성 - 만약 인덱스 락 파일이 존재하면 다른 프로세스는 인덱스 쓰기 실패함
- 쓰기 권한을 가진 프로세스는 인덱스 파일 자체 대신 인덱스 락 파일에 쓰기 시도
- 쓰기가 완료되면
index.lock파일의 이름을index로 바꿔서 한번에 파일 교체
touch .git/index.lockgit add file1.txt || truefatal: Unable to create '/Users/joelkim/Work/personal/book_git/lab/test_internal_02/.git/index.lock': File exists.
Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.
git statusOn branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file1.txt
diff 명령
- diff 명령은 워크트리, 스테이지, 커밋간의 차이를 비교
diff 명령 사용법
| 명령 | 옵션 | 인수1 | 인수2 | 비교대상1 | 비교대상2 |
|---|---|---|---|---|---|
git diff |
- | - | - | 워크트리 | 인덱스파일 |
git diff |
--cached |
- | - | 스테이지 | 헤드커밋 |
git diff |
- | <커밋> |
- | 워크트리 | 커밋 |
git diff |
--cached |
<커밋> |
- | 스테이지 | 커밋 |
git diff |
- | <커밋1> |
<커밋2> |
커밋1 | 커밋2 |
- 인덱스 파일은 추후 다루지만
- 기본적으로는 다음 번에 commit 명령을 내릴 때 포함될 내용을 뜻한다.
- 추적중이고 아직 변경되지 않은 헤드커밋의 파일 + 추적중이고 변경되어 add 된 파일
- 따라서 추적중인 파일이 워크트리에서 변경되면 아직 add를 하지 않은 상태, 즉 스테이징을 하지 않아도 diff 명령으로 비교가 가능
실습 6: diff 명령
- 레포지토리 생성
cd $HOME/lab
rm -rf test_diff_01
git init test_diff_01
cd test_diff_01Initialized empty Git repository in ~/lab/test_diff_01/.git/
- 신규파일 생성 후
echo "file1 line1" >> file.txtgit statusOn branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
file.txt
nothing added to commit but untracked files present (use "git add" to track)
- 비추적 상태의 신규 파일은 워크트리에 있어도 스테이지와 비교하지 않는다
git diff- 아직 add 전이므로 스테이지와 커밋도 동일
git diff --cached- add 스테이징 후
git add file.txtgit statusOn branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file.txt
- add된 직후이므로 워크트리와 스테이지는 동일
git diff- 스테이지에는 신규파일이 있고 커밋에는 없으므로 –cached 옵션에는 표시됨
git diff --cacheddiff --git a/file.txt b/file.txt
new file mode 100644
index 0000000..0b11cfc
--- /dev/null
+++ b/file.txt
@@ -0,0 +1 @@
+file1 line1
- 커밋 후
git commit -m c1[main (root-commit) 44f2dfd] c1
1 file changed, 1 insertion(+)
create mode 100644 file.txt
git statusOn branch main
nothing to commit, working tree clean
- 커밋 직후에는 워크트리, 스테이지, 헤드커밋이 동일
git diffgit diff --cached- 추적 상태의 파일이 변경된 경우
echo "file1 line2" >> file.txtgit statusOn branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
- 추적 상태의 파일이 변경되면 인덱스와 달라짐
git diffdiff --git a/file.txt b/file.txt
index 0b11cfc..d037497 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
file1 line1
+file1 line2
- 이는 헤드커밋과 직접 비교한 것과 같음
git diff HEADdiff --git a/file.txt b/file.txt
index 0b11cfc..d037497 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
file1 line1
+file1 line2
- 아직 스테이지에는 변경이 반영되지 않았기 때문에 스테이지와 헤드커밋은 동일함
git diff --cached- 스테이징
git add file.txtgit statusOn branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file.txt
- 스테이징 되면 인덱스(스테이지)가 워크트리와 같아지므로 diff에 나타나지 않음
git diff- 이제는 스테이지와 헤드커밋이 달라지므로 diff –cached 명령에 나타남
git diff --cacheddiff --git a/file.txt b/file.txt
index 0b11cfc..d037497 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
file1 line1
+file1 line2
- 워크트리와 헤드커밋을 직접 비교해도 같은 결과임
git diff HEADdiff --git a/file.txt b/file.txt
index 0b11cfc..d037497 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
file1 line1
+file1 line2
- 일단 커밋하면 모든 상태가 같으므로 어떤 diff 명령도 차이를 보이지 않음
git commit -m c2[main 4bbe6cc] c2
1 file changed, 1 insertion(+)
git diffgit diff --cachedgit diff HEAD- 추적중인 파일 삭제
rm -f file.txtgit statusOn branch main
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
git diffdiff --git a/file.txt b/file.txt
deleted file mode 100644
index d037497..0000000
--- a/file.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-file1 line1
-file1 line2
git diff HEADdiff --git a/file.txt b/file.txt
deleted file mode 100644
index d037497..0000000
--- a/file.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-file1 line1
-file1 line2
git diff --cachedgit add .git diffgit diff --cacheddiff --git a/file.txt b/file.txt
deleted file mode 100644
index d037497..0000000
--- a/file.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-file1 line1
-file1 line2
git diff HEADdiff --git a/file.txt b/file.txt
deleted file mode 100644
index d037497..0000000
--- a/file.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-file1 line1
-file1 line2
git commit -m c3[main 79971a0] c3
1 file changed, 2 deletions(-)
delete mode 100644 file.txt
git diffgit diff --cachedgit diff HEAD