Git의 기본 저장 단위 Commit
Commit은 Git의 기본 저장 단위이다. 우리는 Commit을 파일들에 대한 스냅샷이라고도 부르며, Commit은 Commit을 찍은 시간의 파일들의 상태에 대해 저장한다. Commit은은 tree, parent, author, commiter,message 5가지 구성요소로 이루어져 있다.
- tree : tree와 blob를 포인팅하는 구성요소이다.
- parent : 해당 커밋 직전에 어떤 커밋이 있었는지 포인팅한다.
- author : 작성자.
- commiter : 커밋을 만든 사람.
- message : 커밋을 설명하는 메세지.
예를 들어 commit이 두 개 찍힌 다음과 같은 로그를 가진 Git 폴더가 있다고 해보자
$ git log --oneline
6e3a608 (HEAD -> master) test2
b2f3c96 test
이 중 두번째 커밋인 6e3a608에 대한 압축을 풀어보면 다음과 같은 결과가 나온다. 위에서 부터 순서대로 tree, parent, author, comitter, message 가 나오는 것을 확인할 수 있다.
$ git cat-file -p 6e3a608
tree 849ed50babda69c16811c9cfcf2f9d373114ec2a
parent b2f3c967b8ad45a2ddfe615695075699d280c05b
author Seyoung Cho <simplistudiodev@gmail.com> 1642000362 +0900
committer Seyoung Cho <simplistudiodev@gmail.com> 1642000362 +0900
test2
우리는 이들을 순서대로 알아보고자 한다.
Commit과 Tree
프로그래밍에서 다량의 데이터를 저장하기 위해서는 시간 복잡도를 낮추기 위해 Tree 형태의 구조를 사용한다. Git또한 마찬가지로 Commit은 커밋을 찍는 순간 Tree라 부르는 변경 사항을 가리키는 포인터를 저장한다. 이 Tree는 다른 Tree와 Blob를 포인팅하는 포인터들로 이루어진다. Blob는 개별 파일들의 스냅샷으로 Commit의 Tree가 포함하는 모든 Blob 값들이 Commit의 스냅샷이 된다.
예를 들어 [그림1]과 같은 상황에서는 Commit은 90ab123.. 해시를 가진 Tree을 포인팅 하는데, 이 Tree는 내부에 Tree와 Blob 파일을 포함한다. 이 중 Blob 파일은 개별 파일에 대한 스냅샷이며, Tree는 또 다른 Blob들을 포함하는 구조체이다. Git은 이 Tree들에서 포인팅하는 모든 변경사항에 대한 스냅샷을 확인 한 후 해당 커밋의 변경 사항을 확인한다. [그림1]에서는 5가지 Blob 파일이 스냅샷이 된다. Blob 파일들은 내용이 각각 압축되어 있으며 Git의 압축 해제를 통해 내부 내용을 볼 수 있다. 이에 대해서는 궁금하면 아래 글을 참조하도록 하자.
*commit, tree, author 파일들은 모두 .git의 objects 폴더에 포함된다.
Commit의 Parent
Commit의 Parent는 해당 커밋의 parent commit에 대한 해시값으로 첫 커밋을 제외한 모든 커밋은 parent commit을 가지고 있다. 우리가 이전 커밋을 확인할 수 있는 이유는 이러한 parent에 대한 참조를 반복하기 때문이며, git 의 diff를 확인할 때 parent commit의 tree의 스냅샷과 현재 commit의 tree의 스냅샷을 확인한다.
Commit의 메타데이터 : author, commiter, message
Commit은 author, comitter, message 세개의 메타데이터를 가진다. author과 commiter은 거의 일치하지만 이따끔씩 다를 수도 있다. 하지만, 왠만해서는 둘은 같다고 보면 된다 코드를 쓴 사람(author)가 커밋(commiter)도 하기 때문이다. 메세지는 커밋에 대한 로그를 남기기 위해 쓰며, message를 잘 작성하는 것은 이후 코드를 작성하는 사람이 맥락(Context) 파악을 하기 위해 매우 중요하기 때문에 잘 작성해야 한다.