Git Refs

sith-call.dev·2025년 2월 9일
0

Git

목록 보기
3/3

References'' 또는 Refs''

A Git reference (git ref) is just a file that contains a Git commit SHA-1 hash. When referring to a Git commit, you can use the Git reference, which is an easy-to-remember name, rather than the hash. The Git reference can be rewritten to point to a new commit. A branch is just a Git reference that stores the new Git commit hash.

커밋의 SHA-1 값을 날로 사용하기보다 쉬운 이름으로 된 포인터가 있으면 그걸 사용하는 게 더 좋다. 외우기 쉬운 이름으로 된 파일에 SHA-1 값을 저장한다.

Git에서는 이런 것을 References'' 또는 Refs'' 라고 부른다.

이 SHA-1 값을 저장하는 파일은 .git/refs 디렉토리에 있다.

Refs가 있으면 커밋을 찾기 쉬워진다.

.git/refs의 디렉토리 구조

$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags

refs의 내부

$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master

refs를 이용한 git log 명령

$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

git update-ref 명령

Refs 파일을 직접 고치는 것이 좀 못마땅하다. Git에는 좀 더 안전하게 바꿀 수 있는 git update-ref 명령이 있다.

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
**git update-ref** [-m <reason>] [--no-deref] (-d <ref> [<oldvalue>] | [--create-reflog] **<ref> <newvalue>** [<oldvalue>] | --stdin [-z])

Git Branch의 의미

브랜치는 어떤 작업 중 마지막 작업을 가리키는 포인터 또는 Refs이다.

브랜치는 직접 가리키는 커밋과 그 커밋으로 따라갈 수 있는 모든 커밋을 포함한다.

Git Branch 만들어보기

$ git update-ref refs/heads/test cac0ca

위의 코드는 test 브랜치를 만든 것이다.

$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

해당 브랜치의 로그를 찍어본다.

git log 명령

Shows the commit logs.

git log [<options>] [<revision range>] [[--] <path>]

git branch <branch> 명령

git branch [--color[=<when>] | --no-color] [--show-current]
	[-v [--abbrev=<n> | --no-abbrev]]
	[--column[=<options>] | --no-column] [--sort=<key>]
	[--merged [<commit>]] [--no-merged [<commit>]]
	[--contains [<commit>]] [--no-contains [<commit>]]
	[--points-at <object>] [--format=<format>]
	[(-r | --remotes) | (-a | --all)]
	[--list] [<pattern>]
git branch [--track | --no-track] [-f] <branchname> [<start-point>]
git branch (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
git branch --unset-upstream [<branchname>]
git branch (-m | -M) [<oldbranch>] <newbranch>
git branch (-c | -C) [<oldbranch>] <newbranch>
git branch (-d | -D) [-r] <branchname>git branch --edit-description [<branchname>]

git branch <branch> 명령을 실행하면 Git은 내부적으로 update-ref 명령을 실행한다. 입력받은 브랜치 이름과 현 브랜치의 마지막 커밋의 SHA-1 값을 가져다 update-ref 명령을 실행한다.

HEAD

HEAD 파일은 현 브랜치를 가리키는 간접(symbolic) Refs다.

이 Refs는 다른 Refs를 가리키는 것이라서 SHA-1 값이 없다.

HEAD 파일의 내용

$ cat .git/HEAD
ref: refs/heads/master

git checkout 명령

Git은 HEAD 파일을 git checkout 명령어를 통해서 HEAD 파일의 내용을 바꾼다.

아래와 같이 기존의 브랜치에서 test 브랜치로 바꾸는 예시이다.

$ git checkout test
$ cat .git/HEAD
ref: refs/heads/test

git symbolic-ref 명령

git-symbolic-ref - Read, modify and delete symbolic refs

git symbolic-ref [-m <reason>] <name> <ref>
git symbolic-ref [-q] [--short] <name>
git symbolic-ref --delete [-q] <name>

이 명령으로 HEAD의 값을 읽을 수 있다.

$ git symbolic-ref HEAD
refs/heads/master

HEAD의 값도 변경할 수도 있다.

$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test

git commit 명령

git-commit - Record changes to the repository

git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
	   [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
	   [--date=<date>] [--cleanup=<mode>] [--[no-]status]
	   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
	   [(--trailer <token>[(=|:)<value>])] [-S[<keyid>]]
	   [--] [<pathspec>]

이 명령을 실행하면 커밋 개체가 만들어지는데, 지금 HEAD가 가리키고 있던 커밋의 SHA-1 값이 그 커밋 개체의 부모로 사용된다.

태그

태그 개체는 커밋 개체랑 매우 비슷하다. 커밋 개체처럼 누가, 언제 태그를 달았는지 태그 메시지는 무엇이고 어떤 커밋을 가리키는지에 대한 정보가 포함된다.

태그 개체도 .git/objects 파일에 저장된다.

그러나 이 개체를 가리키는 태그(”태그 개체”가 아님, “태그”임)는 .git/refs/tags 폴더에 파일로서 저장되어 있다. 그 파일의 이름이 태그의 이름이며, 파일 내용은 그 태그가 가리키는 태그 개체의 해시값이다. 어찌보면 브랜치와 비슷한 것이다.

Lightweight 태그

Lightwieght 태그는 만들기 쉽다. 브랜치랑 비슷하지만 브랜치처럼 옮길 수는 없다.

그냥 refs/tags 폴더에 태그 이름을 이름으로 갖는 파일을 만든 뒤에 그 태그가 가리키는 커밋의 해시값을 저장하면 된다.

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

Annotated 태그

Annotated 태그는 태그 개체를 가리킨다.

Annotated 태그를 만들면 Git은 태그 개체를 만들고 거기에 커밋을 가리키는 Refs를 저장한다.

-a 옵션을 주고 Annotated 태그를 만들어 확인해보자.

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
$ 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 개체에 태그를 달 수 있다.

커밋 개체에 태그를 다는 것이 아니라 Git 개체에 태그를 다는 것이다.cd

git tag 명령

Add a tag reference in refs/tags/, unless d/-l/-v is given to delete, list or verify tags.

  • -a
  • -annotate

Make an unsigned, annotated tag object

git tag [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] [-e]
	<tagname> [<commit> | <object>]
git tag -d <tagname>git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
	[--points-at <object>] [--column[=<options>] | --no-column]
	[--create-reflog] [--sort=<key>] [--format=<format>]
	[--merged <commit>] [--no-merged <commit>] [<pattern>]
git tag -v [--format=<format>] <tagname>

Lightweight 태그와 Annotated 태그의 차이점

Lightweight 태그는 태그에 이름만 붙일 수 있다.

그러나 Annotated 태그는 태그에 이름과 커밋과 같은 기타 정보들을 붙일 수 있다.

이때 커밋과의 차이점은 커밋은 트리 개체를 중심으로 스냅샷에 메타 정보를 부여하기 위한 개체라면, 태그는 커밋을 포함한 모든 개체에 메타 정보를 부여하기 위한 것이다. 따라서 커밋은 변화를 기록하는 단위라면 태그는 단지 어떤 하나의 지표가 될 뿐이다.

리모트 Refs

리모트를 추가하고 Push 하면 Git은 각 브랜치마다 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 브랜치에서 서버와 마지막으로 교환한 커밋이 어떤 것인지 refs/remotes/origin/master 파일에서 확인할 수 있다.

$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949

refs/heads 에 있는 Refs인 브랜치와 달리 리모트 Refs는 Checkout 할 수 없고 읽기 용도로만 쓸 수 있는 브랜치인 것이다. 이 리모트 Refs는 서버의 브랜치가 가리키는 커밋이 무엇인지 적어둔 일종의 북마크이다.

profile
lim (time → ∞) Life(time) = LOVE

0개의 댓글

관련 채용 정보