
어떠한 1a4103~~ 라는 커밋이 있을 때 이전의 히스토리를 보려면 git log 1a4103라고 실행을 하면 히스토리를 볼 수 있음
하지만 여전히 1a4103이라는 SHA-1 값을 기억해야 한다는 단점이 있음
그래서 이 SHA-1 값을 바로 사용하기보다는 이름으로 된 포인터가 있으면 그것을 사용하는 것이 더 좋은 선택일 수 있음
외우기 쉬운 이름으로 된 파일에 SHA-1 값을 저장하는 것
Git에서는 이런 것을 "References" 또는 "Refs"라고 부름
이 SHA-1 값을 저장하는 파일은 .git/refs 디렉토리에 존재
처음 초기화한 상태에서는 아직 디렉토리 안에 파일은 없고 디렉토리만 몇 개 있음
$ find .git/refs // .git/refs에 존재하는 것들
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f // .git/refs에 존재하는 파일들 (존재 X)
Refs가 있으면 커밋을 찾기 쉬워짐
사실 내부는 아래처럼 단순
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
위처럼 커밋의 SHA-1값을 “master”라는 이름의 파일에 하나 하나 쌓아가는 것
이제 SHA-1값 대신 Refs를 사용할 수 있음
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
이렇게 직접 Refs 파일을 고치는 것 보다 Git에서 제공하는 git update-ref 명령이 있음
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
Refs의 역할을 하는 것이 바로 Git에서의 브랜치
브랜치는 어떤 작업 중 마지막 작업을 가리키는 포인터 또는 Refs
$ git update-ref refs/heads/test cac0ca
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
위는 두 번째 커밋으로 만든 새로운 브랜치
위까지의 결과를 그림으로 확인하면 아래와 같음

git branch <branch> 명령을 실행하면 Git은 내부적으로 update-ref 명령을 실행
입력받은 브랜치 이름과 현 브랜치의 마지막 커밋의 SHA-1 값을 가져다 update-ref 명령을 실행
HEAD 파일은 현 브랜치를 가리키는 간접(symbolic) Refs
이 Refs는 다른 Refs를 가리키는 것이라서 SHA-1 값이 없음
$ cat .git/HEAD
ref: refs/heads/master
git checkout test 를 실행하면 Git은 HEAD 파일을 아래와 같이 바꿈
$ cat .git/HEAD
ref: refs/heads/test
git commit 을 실행하면 커밋 개체가 만들어지는데, 지금 HEAD가 가리키고 있던 커밋의 SHA-1 값이 그 커밋 개체의 부모로 사용
이 파일도 손으로 직접 편집할 수 있지만 git symbolic-ref 라는 명령어가 있어서 좀 더 안전하게 사용 가능
아래와 같이 현재 HEAD의 값을 읽을 수 있음
$ git symbolic-ref HEAD
refs/heads/master
HEAD의 값을 변경할 수도 있음
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
Refs의 형식에 맞지 않으면 아래와 같은 오류가 발생
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
Blob, Tree, Commit 개체 외에 태그 개체가 존재
커밋 개체처럼 누가, 언제 태그를 달았는지 태그 메시지는 무엇이고 어떤 커밋을 가리키는지에 대한 정보가 포함
태그 개체는 Tree 개체가 아닌 커밋 개체를 가리킴
브랜치처럼 커밋 개체를 가리키지만 옮길 수는 없음
태그 개체는 늘 그 이름이 뜻하는 커밋만 가리키는 것
태그는 Annotated 태그와 Lightweight 태그 두 종류로 나뉨
Annotated 태그는 GPG 서명과 함께 태그를 만들 때 주로 사용
주석이 달린 태그로, 메시지, 태그를 만든 사람, 날짜 등의 정보를 포함할 수 있음
안정성과 신뢰성을 높일 수 있으며 릴리즈와 같은 중요한 지점에 사용
Lightweight 태그는 단순한 포인터와 같은 역할
메타데이터와 추가 정보 없이 특정 커밋을 가리키는 가벼운 태그
주로 일시적이거나 간단한 태그를 만들 때 사용
일단 아래와 같이 Lightweight 태그를 만들 수 있음
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Annotated 태그는 만들어질 때 Git은 태그 개체를 만들고 거기에 커밋을 가리키는 Refs를 저장
Annotated 태그는 커밋을 직접 가리키지 않고 태그 개체를 가리킴
아래와 같이 -a 옵션을 주고 Annotated 태그를 만들 수 있음
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
git cat-file -p 명령으로 해당 SHA-1 값의 내용을 조회
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
test tag
object 부분에 있는 SHA-1 값이 실제로 태그가 가리키는 커밋
커밋 개체뿐만 아니라 모든 Git 개체에 태그를 달 수 있음
리모트를 추가하고 Push 하면 각 브랜치마다 Push 한 마지막 컴시이 무엇인지 refs/remotes 디렉토리에 저장
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
위와 같이 origin이라는 리모트를 추가하고 master 브랜치를 Push하면 origin의 master 브랜치에서 서버와 마지막으로 교환한 커밋이 어떤 것인지 refs/remotes/origin/master 파일에서 확인할 수 있음
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
refs/heads에 있는 Refs인 브랜치와 달리 리모트 Refs는 Checkout 할 수 없고 읽기 용도로만 쓸 수 있는 브랜치
이 리모트 Refs는 서버의 브랜치가 가리키는 커밋이 무엇인지 적어둔 일종의 북마크
좋은 내용 잘 봤습니다!