Git 내부로의 짧은 여정

8143 단어 git
이 기사에서는 실제 예제를 통해 Git 내부에 대해 알아보겠습니다. 아직 터미널을 열지 않았다면 그렇게 하고 안전벨트를 매고 가자! 💨

Git 저장소 초기화


git init 를 사용하여 빈 Git 프로젝트를 이미 초기화했을 것입니다. 하지만 이 명령이 무엇을 하는지 궁금하신가요?

빈 폴더를 만들고 빈 Git 프로젝트를 초기화해 봅시다. 공식 Git documentation, git init에서 :

This command creates an empty Git repository — basically a .git directory with subdirectories for objects, refs/heads, refs/tags, and template files. An initial HEAD file that references the HEAD of the master branch is also created.



폴더의 내용을 검사하면 다음 구조를 볼 수 있습니다.

$ tree -L 1 .git/
.git/
├── HEAD
├── config
├── description
├── hooks
├── info
├── objects
└── refs

Git은 키-값 데이터 저장소입니다.



핵심적으로 Git은 콘텐츠 주소 지정이 가능한 파일 시스템입니다. 뭐? 🤔 좋아요, Git은 단순히 키-값 데이터베이스입니다. 모든 종류의 콘텐츠를 Git 리포지토리에 삽입하면 Git에서 해당 콘텐츠를 다시 검색하는 데 사용할 수 있는 고유 식별자(키)를 다시 제공합니다.

Git은 hash-object 명령을 사용하여 값을 데이터베이스에 저장합니다.

Computes the object ID value for an object with specified type with the contents of the named file (which can be outside of the work tree), and optionally writes the resulting object into the object database. Reports its object ID to its standard output. When is not specified, it defaults to “blob”.



"blob"은 바이트 시퀀스에 불과합니다. Git blob은 정확한 데이터를 파일로 포함하지만 Git 키-값 데이터 저장소에 저장되는 반면 "실제"파일은 파일 시스템에 저장됩니다.

블롭을 생성해 보겠습니다.

$ echo hello | git hash-object --stdin -w
ce013625030ba8dba906f756967f9e9ca394464a
-w 플래그를 사용하여 실제로 개체를 개체 데이터베이스에 기록하고 개체를 표시할 뿐만 아니라(--stdin 플래그로 달성).

"hello"값은 Git 데이터 저장소의 "값"이고 hash-object 함수에서 반환된 해시가 이 경우 키입니다. 이제 git-cat-file 명령을 사용하여 키로 값을 읽는 반대 작업을 수행할 수 있습니다.

$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello
-t 플래그를 사용하여 유형을 확인할 수 있습니다.

$ git cat-file -t ce013625030ba8dba906f756967f9e9ca394464a
blob

githash-object.git/objects/ 폴더(일명 개체 데이터베이스)에 데이터를 저장합니다. 확인해보자:

$ tree .git/objects/
.git/objects/
├── ce
│   └── 013625030ba8dba906f756967f9e9ca394464a
├── info
└── pack

해시 접미사("ce"디렉토리 아래)는 hash-object 함수에서 얻은 것과 동일하지만 접두사가 다릅니다. 왜요? 상위 폴더 이름에 키의 처음 두 문자가 포함되어 있기 때문입니다. 왜요? 일부 파일 시스템에는 하위 디렉토리 수에 제한이 있기 때문입니다. 따라서 이 계층을 도입하면 해당 문제가 완화됩니다.

다른 개체를 저장해 보겠습니다.

$ echo world | git hash-object --stdin -w
cc628ccd10742baea8241c5924df992b5c019f71

예상대로 이제 .git/objects/ 아래에 두 개의 디렉토리가 있습니다.

$ tree .git/objects/
.git/objects/
├── cc
│   └── 628ccd10742baea8241c5924df992b5c019f71
├── ce
│   └── 013625030ba8dba906f756967f9e9ca394464a
├── info
└── pack

그리고 다시 키의 접두사가 있는 cc 폴더에는 포함된 파일 이름에 나머지 키가 있습니다.

나무 개체 🌲



다음으로 조사할 Git 개체는 트리입니다. 이 유형은 파일 이름을 저장하는 문제를 해결하고 파일 그룹을 함께 저장할 수 있습니다.
트리 개체는 항목을 포함합니다. 각 항목은 관련 모드, 유형 및 파일 이름이 있는 BLOB 또는 하위 트리의 SHA-1입니다. git-mktree 문서를 확인해보자:

Reads standard input in non-recursive ls-tree output format, and creates a tree object. The order of the tree entries is normalized by mktree so pre-sorting the input is not required. The object name of the tree object built is written to the standard output.



ls-tree 출력 형식이 궁금하다면 다음과 같습니다.

<mode> SP <type> SP <object> TAB <file>

이제 위의 두 Blob을 연결해 보겠습니다.

$ printf '%s %s %s\t%s\n' \
    100644 blob ce013625030ba8dba906f756967f9e9ca394464a hello.txt \
    100644 blob cc628ccd10742baea8241c5924df992b5c019f71 world.txt |
  git mktree
88e38705fdbd3608cddbe904b67c731f3234c45b
mktree는 새로 생성된 트리 개체에 대한 키를 반환합니다.

이 시점에서 다음과 같이 트리를 시각화할 수 있습니다.

             88e38705fdbd3608cddbe904b67c731f3234c45b  
                                |                   
                  +-------------|------------+             
                  |                          |        
                  |                          |        
                  |                          |          
                  |                          |       
                  |                          |
                hello                       world        
            ce013625030b                 cc628ccd1074

트리의 내용을 살펴보겠습니다.

$ git cat-file -p 88e38705fdbd3608cddbe904b67c731f3234c45b
100644 blob ce013625030ba8dba906f756967f9e9ca394464a hello.txt
100644 blob cc628ccd10742baea8241c5924df992b5c019f71 world.txt

물론 .git/objects도 그에 따라 업데이트되었습니다.

$ tree .git/objects/
.git/objects/
├── 88
│   └── e38705fdbd3608cddbe904b67c731f3234c45b
├── cc
│   └── 628ccd10742baea8241c5924df992b5c019f71
├── ce
│   └── 013625030ba8dba906f756967f9e9ca394464a
├── info
└── pack

지금까지 인덱스를 업데이트하지 않았습니다. 이렇게 하려면 git-read-tree 명령을 사용합니다.

Reads the tree information given by into the index, but does not actually update any of the files it “caches”. (see: git-checkout-index[1])



$ git read-tree 88e38705fdbd3608cddbe904b67c731f3234c45b
$ git ls-files -s
100644 ce013625030ba8dba906f756967f9e9ca394464a 0 hello.txt
100644 cc628ccd10742baea8241c5924df992b5c019f71 0 world.txt

그러나 Git 데이터 저장소에 직접 값을 쓰고 있기 때문에 파일 시스템에 파일이 아직 없다는 점에 유의하세요. 파일을 "체크아웃"하기 위해 인덱스에서 작업 트리로 파일을 복사하는 git-checkout-index 명령을 사용합니다.

git checkout-index 0 -a
-a는 "모두"를 의미합니다. 이제 파일을 볼 수 있어야 합니다.

$ ls
hello.txt world.txt
$ cat hello.txt
hello
$ cat world.txt
world

요약 📝



이 기사에서는 두 개의 파일을 Git 데이터 저장소에 직접 저장했습니다. 파일이 아직 로컬 파일 시스템에 표시되지 않았습니다. 우리는 트리를 만들고 두 개의 "blobs"를 연결한 다음 git-checkout-index 명령을 사용하여 파일을 작업 디렉토리로 가져왔습니다.

좋은 웹페이지 즐겨찾기