본문 바로가기

Git

Git 내부 동작 분석

Github에서 레포지토리를 새로 만들면 다음과 같은 가이드가 나온다.

 

지금부터 init부터 branch까지 명령어에 따라 내부적으로 어떤 방식으로 작업이 이루어지는지 살펴보도록 한다.

 

1. git init

Local에 레포지토리를 연결 할 폴더를 하나 만들고 터미널을 통해 git init 명령어를 실행하면 .git 폴더가 생성된다.

.git Folder

 

.git 폴더 내의 폴더 및 파일들은 Git 작업을 위한 각자의 역할들을 수행한다.


2. git add

git init을 수행한 폴더에 test/test.txt 파일을 만든 후 git add를 수행하면 두 가지의 작업이 실행된다.

 

1) Blob 파일 생성

objects 폴더 내에 Blob 파일이 생성되는데, add 명령어로 추가한 파일 내용으로 Hash 알고리즘을 돌려 나온 Hash Code로 이루어진 폴더와 Blob 파일을 생성한다.

HashCode의 앞 2자리 값을 폴더 이름으로 생성하며, 앞 2자리를 뺀 나머지 HashCode를 파일명으로 생성한다.

test.txt의 HashCode: 91ed12bbf3c1c0dc555a2...

 

 

Blob 파일에는 add한 파일의 내용이 암호화되어 저장된다.

  • Blob 객체 생성
    • Hash Code로 이루어진 폴더와 파일이 생성된다.
      • 폴더 - Hash Code의 앞에서 2개
      • 파일 명 - 폴더에서 뺀 2개를 제외한 나머지
    • 파일 내용은 add한 파일의 내용
    • 파일 내용을 Hash로 변환하기 때문에 파일 내용이 같은 두 개의 파일의 경우 동일한 blob 파일을 갖는다.
      (1개의 blob 파일을 2개의 파일이 가리킴)

 

2) index 파일 생성

Blob 파일과 함께 index 파일이 .git 폴더 내에 생성된다. - .git/index

이 index 파일에는 blob 파일의 HashCode와 파일 명이 저장되어 있다.

//index
//[HashCode] [FileName]
91ed12bb...  test.txt
  • 파일 내용에 대한 Hash Code파일 이름이 생성된다.
    • 폴더의 경우 파일 이름이 dir/filename 의 형식으로 저장된다.
      [HashCode] [Dir/FileName]
  • Commit 이후 수정 된 파일을 다시 add 하는 경우
    • 변경 된 파일의 경우 새로 추가되는 것이 아닌 HashCode 값만 바뀐다.
    • 새로 추가된 파일의 경우, 새로운 파일에 대한 HashCode와 파일 명이 새로 추가
  • 파일 명이 달라도 파일 내용이 같다면 같은 Hash Code를 가리킨다.
    • Git은 파일 내용을 해시 알고리즘(SHA-1)을 통해 Hash 값을 도출하기 때문에 파일 이름이 달라도 파일 내용이 같으면 같은 Hash Code를 가리키게 된다.
    • 파일 명이 다르기 때문에 동일한 Hash Code와 다른 파일 명으로 새로 추가된다.
//index (test.txt와 test3.txt의 내용이 같음)
91ed12bb...  test.txt
67ec12ksn... test2.txt
91ed12bb...  test3.txt

 


3. git commit

git add 한 파일들을 commit 명령어로 commit을 했을 때 다음과 같은 작업들이 이루어진다.

 

1) Commit 파일 

objects 폴더 내에 commit 파일이 생성된다.

폴더와 파일 명은 똑같이 Hash 코드로 이루어져 있고, commit 파일에는 tree 파일의 hash 코드 값이 저장된다.

// commit
tree [HashCode]

 

만인 이전 commit 이력이 존재하는 경우 이전 commit tree의 정보가 parent의 이름으로 추가 저장된다.

// commit
tree [HashCode]
parent [HashCode]

 

2) Tree 파일

tree 파일 또한 마찬가지로 Hash 코드로 폴더와 파일 명이 생성되고, commit 된 blob 파일들의 정보가 저장된다.

// tree
//blob [Blob HashCode] [fileName]
blob  91ed12bbf3c1c0dc555a2... test.txt

 

  • git add로 생성 된 blob 파일의 HashCode가 123abc 인 경우
  • HashCode가 456def 인 tree 파일에 blob 123abc가 저장 및 생성되고
  • tree 456def 가 저장 된 commit 파일이 HashCode로 이루어진 경로에 생성된다. 

tree 파일의 경우 파일 경로마다 생성된다. 예를 들어 파일이 다음과 같이 존재하는 경우

  • root/test.txt
  • root/test/test2.txt
// commit
tree [root tree HashCode]
// root tree
tree [test folder의 tree HashCode] test
blob [test.txt의 HashCode] test.txt
// test folder tree
blob [test2.txt의 HashCode] test2.txt

위와 같이 1개의 commit 파일과 2개의 tree 파일이 생성된다.

 

Commit까지 중간 정리

commit까지의 정보를 요약하자면

 

objects의 폴더에는 add와 commit 명령어를 통해 3가지의 파일이 저장된다.

  • git add
    • blob : 파일 정보
  • git commit
    • tree : blob 또는 폴더에 대한 정보
    • commit : tree 정보

commit에 있는 tree의 HashCode를 통해 tree 내의 blob 파일의 HashCode를 얻을 수 있고, blob 파일을 통해 파일 내용을 알 수 있는데, 이게 가능한 이유는 HashCode로 폴더와 파일명을 생성하기 때문이다.

 

index 파일의 경우 add를 통해 생성 된 blob 파일들의 HashCode와 파일 명이 저장된다.


4. git status

git status 명령어는 현재 파일 목록 중 add 된 파일과 add 되지 않은 파일을 알려준다.

위와 같이 두 개의 text 파일을 생성한 뒤 add-text 파일만 add 하고 status를 실행하면 아래와 같은 결과를 얻을 수 있다.

 

status 명령어로 확인 할 수 있는 이유는 commit 명령어까지의 과정을 이해했다면 다음과 같이 쉽게 유추할 수 있다.

  • 수정되지 않은 파일 (add가 필요 없는 파일, status 목록에 안뜸)
    • index 파일에 저장 된 폴더와 파일 경로가 같고, HashCode 또한 같은 경우
    • 최근 Commit한 파일의 HashCode와 같은 경우 (commit 파일에서 tree를 통해 확인 가능)
  • add 한 파일
    • index 파일에 저장 된 폴더와 파일의 경로 및 HashCode가 같은 경우
    • 최근 Commit한 파일의 HashCode와 다르거나 없는 경우
  • add 가능한 파일
    • index 파일에 저장 된 파일 경로는 같지만 HashCode가 다르거나 없는 경우
    • index 파일에 저장 된 파일 경로가 없는 경우

5. git branch

지금까지 index와 objects 폴더를 살펴봤다면 branch는 HEAD 파일과 refs/heads 폴더를 살펴볼 것이다.

1) refs/heads

refs/heads를 가면 브랜치들의 정보를 확인할 수 있다.

 

현재는 master 브랜치 하나 밖에 없기 때문에 master 파일만 존재하지만 새로운 브랜치를 생성한다면 해당 브랜치에 대한 파일이 생길 것이다.

 

refs/heads에 있는 브랜치 파일에는 어떤 정보가 담겨있을까? 바로 해당 브랜치의 최근 commit HashCode가 들어있다.

 

objects 경로에서 확인해보면 해당 commit 파일을 확인할 수 있다.

 

1) HEAD 파일

HEAD 파일은 현재 사용 중인 Branch를 나타내며, 아래와 같이 현재 사용 중인 branch의 경로를 갖고 있다.