1. 해커스 가이드 투 깃
동일한 제목의 article 요약 by jd.K
http://goo.gl/5xS8Dg
2. Introduction
add, commit, push, pull 까지는 쉬운데,
branch, merge, rebase, multiple remote, remote tracking branch, detached
HEAD state 얘기가 나오면 정신없음...
no-fast-forward merge 라고 말하는 사람이 두려워 지고, 잘하는 사람들도
rebase 를 꺼려한다.
이유는 Subversion 같이 개념적으로 단순한 VCS 를 사용해 왔고 같은 개념으로
Git 을 대하기 때문.
3. Introduction
Subversion 은 단순하다. 그냥 파일하고 디렉토리.
commit 은 순차적으로 번호 매기는 것, branch, tag 는 그냥 백업 폴더 만들기.
Subversion 은 파일과 폴더의 개념과 revision 10 은 9 다음이다 라는 것과 같은
컴퓨터를 다루던 패러다임을 사용. 이걸 Git 에 같다 데면 망한다.
왜? Git 은 완전히 다르니까. 추가 삭제하고 commit 하고 diff 뜨고 다 되는데 뭐
가 달라?
Git 같이 복잡한 얘들은 한번 제대로 이해하면 완전 쉽다.
가이드의 목적은 어떻게 돌아가는지 알려 주는 것.
4. Introduction
뭘 다루나?
● 핵심 개념, basic object storage 같은 것.
● commit 이 동작하는 방식
● branch, tag 의 동작 방식
● rebase 와 같은 다른 종류의 merge
5. Repositories
Git 저장소는 단지, 단순한, key-value data store.
아래 같은 형태로 저장함.
● Blobs, Git 의 기본 데이터 타입. 기본적으로 하나의 blob 는 바이트들의 덩
어리. (보통 하나의 파일에 대한 binary 표현)
● Tree objects, 디렉토리와 유사하다고 보면됨. blob 들이나 다른 tree
objects 에 대한 포인터를 포함할 수 있음.
● Commit objects, 하나의 tree object 를 가르킴, 메타 데이터 포함 (누가
commit 했는지, 부모 commit 등)
● Tag objects, 하나의 commit object 를 가르킴킴, 메타 데이터 포함.
● References, 하나의 object 에 대한 포인터들 (보통 commit or tag object)
6. Repositories
Git 저장소에 대해 기억해야 할 중요한 것 => 프로젝트 루트에 있는 .git 디렉토리
하나에 모두 저장된다는 거.. Subversion, CVS 처럼 중앙 저장소는 없오.
그래서 분산 VCS 라고 하는 거고, 모두 자기 저장소를 들고 있는 거임.
7. Repositories
git init 으로 저장소를 만들고, .git 을 보면, 중요한 디렉토리..
.git/objects 모든 objects 를 저장하는 곳
.git/refs 모든 references 를 저장하는 곳
앞으로 배워가면서 이것들이 어떻게 물려있는지 볼꺼 고,
지금은 tree objects 가 뭔지 더 보자.
8. Tree Objects
a tree object = a directory
blobs (files) 를 포함하고, 다른 tree objects (sub directories) 를 포함.
간단한 저장소가 하나 있다고 치자..
요 저장소는 두 개의 tree object 로 표현될 것이다.
(하나는 루트 디렉토리를 위한 것, 또 하나는 src 디렉토리를
위한 것)
9. Tree Objects
blob 을 초록으로 그리고,
tree object 를 파랑으로 그리면..
root tree object 부터 모든 tree
object 를 따라가면서,
전체 working tree 상태를 알 수
있다.
‘root tree object’ 가 특정 순간에
저장소의 snapshot 이라고 볼 수
있음.
10. Commits
하나의 commit object 는 몇 가지 중요한 metadata 를 갖고 있는 하나의 포인터.
commit 는 하나의 hash 를 갖는데, 갖고 있는 metadata 의 조합으로 만들어 짐.
● tree 에 대한 hash (root tree object), commit 할 당시. tree object 에서 배운
것 처럼, 하나의 commit 으로 Git 은 tree 를 돌면서 전체 working tree 를 만
들 수 있음.
● 부모 commit 들에 대한 hash, 저장소가 history 를 제공할 때 주는 것. 모든
commit 는 부모가 있고, 최초의 commit 으로 통함.
● author 의 이름과 메일주소, 변경 시간
● commit 한 사람의 이름과 메일주소, commit 한 시간
● commit message
11. Commits
commit 을 하면, Git 은 commit 에 대한 hash 를 준다.
git show 명령어에 --format=raw flag 를 주면,
새로 생성된 commit 의 metadata 를 볼 수 있다.
13. References
앞에서 봤 듯이 object 를 hash 로 구분하며, Git 에서 object 를 많이 다루려면
hash 를 알고 있어야 한다.
Git 명령어를 쓰면서 object 를 hash 로 직접 가르킬 수 도 있을 꺼다.
git show d409ca7 처럼, d409ca7 hash 를 갖는 object 를 보여 달라…
그럼 hash 를 다 기억해야 하나?
못할 껄 아니까, Git 은 references (‘refs’) 를 갖고 있다.
하나의 reference 는 .git/refs 여기 어딘가에 저장되어 있는 하나의 파일이다.
(commit object 에 대한 hash 저장)
14. References
git status 를 쳐보면, 어떤 branch 에 있는지 보인다. 나중에 보겠지만 branch 들
은 그냥 reference 들 이다.
.git/refs/heads 를 보면 알 수 있다.
그럼 master 는 뭘 가르킬까?
cat 해보면 안다.
그렇다, master 는 첫번째 commit object 의
hash 를 갖고 있다.
15. References
이렇게 보는걸 단순하게 할 수도 있다.
show, rev-parse 명령을 사용하면, reference 가 어떤 commit 을 가르키는지 볼
수 있다.
Git 은 HEAD 라는 특별한 reference 도 갖고 있다.
요건 ‘Symbolic’ reference 로써,
actual commit 보다 현재 branch 의 tip 을 가르킨다.
HEAD 를 검사해보면, refs/head/master 를 가르키고
있는걸 알 수 있다.
16. References
HEAD 가 commit object 를 가르키게 할 수도 있는데,
요런 일이 생기면, Git 은 말한다.. “detached HEAD state” 라고.
뒤에 더 얘기 하겠지만, 이건 니가 지금 branch 위에 있지 않다는 의미 이다.
17. Branches
Git 의 branch 는 큰 장점 중 하나라고 얘기 되기도 하는데, 가볍기 때문.
다른 VCS 는 branch 가 저장소를 몽땅 복사하는 것이다.
왜 가볍나? Git 에서 branch 는 그냥 reference 니까.
전에 본 것 처럼, master branch 는 .git/refs/heads 에 있는 하나의 파일이다.
그럼 하나 더 만들고 뭔 일이 있는지 보자.
간단한데, .git/refs/heads 아래 entry 하나를 만들고,
현재 commit 을 가르키도록 했다.
18. Branches
HEAD 는 현재 branch 를 가르키는 reference 인데, branch 를 바꿔보자.
새로운 commit 을 만들면, Git 은 현재 branch 가 새로운
commit object 를 가르키도록 변경한다.
나중에, local branch 와
remote tracking branch 의 차이점을
볼 것 이다.
19. Tags
lightweight tags, annotated tags - 두 종류
보기엔 비슷해 보임, 둘다 .git/refs/tags 에 저장되는 reference 임.
근데 여기까지만 비슷한 거임. lightweight tag 가 어떻게 돌아가나 보자.
Git 이 현재 commit 을 가르키는 tag reference 를
만들었다.
default 로 git tag 하면 lightweight tag 가 만들어지는데, 중요한건 이게 tag object
는 아니라는 거.. git cat-file 로 tag 를 검사해 보면 알 수 있음.
20. Tags
Git 이 보기엔 1.0-lightweight 나 d409ca7 commit 이나 동일하다.
왜냐하면, lightweight tag 는 그냥 commit object 를 가르키는 reference 이기 때
문.
21. Tags
그럼, annotated tag 랑 비교해보자.
git tag 에 -a (--annotate) flag 주면 됨.
lightweight tag 처럼 tag 를 위한 reference 를 만들지만, 같은 object 를 가르키진
않는다.
요게! tag object 다.
요놈이 가르키는 commit 과는
다른 object 임.
22. Tags
commit 에 대한 pointer, tag message, tagger 에 대한 정보도 포함.
commit, email spoofing 를 막기 위해 GPG key 로 sign 될 수 있음.
GPG-signable 말고도, annotated tag 를 선호하는 몇 가지 이유가 있음.
● 아마 가장 중요한건 tag author 정보를 포함할 수 있다는 거.
● timestamped 되기 때문에, 언제 commit 했는지가 아니라 언제 release 했는
지 알 수 있음.
23. Merging
Git 에서의 merging 은 두 개의 history (보통 branch)를 하나로 합치는 것.
예)
1) master 에서 feature branch 를 따서
작업을 좀 했음.
2) 근데 hotfix 할게 생겼음. 다시 master 에서
hotfix branch 를 만들어서 작업함.
25. Merging
이제 버그 고친 걸 master 에 가져와서 tag 하고 release 할 것이다.
merge 할 때, Git 이 ‘fast-forward’ 라고
말하는 걸 보자.
뭔 뜻이냐면,
hotfix 에 있는 모든 commit 들이 master 로
부터 바로 upstream 된다는 것.
Git 은 master 가 가르키던 pointer 가 hotfix 로 이동하도록 한다.
27. Merging
이제 feature-branch 를 master 로 merge 해보자.
이때, Git 은 fast-forward 를 수행하지 않는다.
왜냐하면 feature-branch 는 master 에서 바로 upstream 이 될 수 없기 때문이다.
이전 그래프를 보면 명확한데,
commit D 가 있는 master 는 commit C 가 있는 feature-branch 와 다른 history
이다.
그럼 Git 은 이걸 어떻게 처리할까?
28. Merging
로그를 보면, Git 이 실제로 새로운 merge commit 을 만든다.
물론 feature-branch 에서 comit 도 가져온다.
좀더 살펴보면, 특별한 종류의 commit object 라는 걸
알 수 있다.
두 개의 parents 를
갖는다.
이걸 merge commit
이라고 한다.
30. Merging
어떤 사람들은 이런 history graph 를 원하지 않을 것이다.
master 로 merge 하기 전에 feature branch 를 rebase 해서,
non-fast-forward merge 를 피하는 방법을 살펴 볼 것이다.
31. Rebasing
Rebasing 는 Git 에서 가장 오해 받는 기능 중 하나.
대분의 사람들에게 git rebase 는 어떤 수를 쓰더라도 피해야 하는 명령어.
인터넷에 rebase 에 대해 무지하게 유언비어를 퍼트리는.. rebase 를 비방하는
글들이 많다.
rebase 가 뭘 하는지 알게 되면, 무섭거나 위험하지 않다.
rebasing 에 대해 얘기하지 전에, 먼저 약간 옆길로 셀 텐데,
cherry-picking 을 설명하면서 rebasing 을 얘기 하면 훨씬 쉽기 때문이다.
32. Cherry-Picking
git cherry-pick 은 하나 혹은 몇 개의 commit 을 가져와서, 현재 commit 에다 대
고 replay 한다.
commit D 에 있다고 할 때,
git cherry-pick F 을 돌리면,
Git 은 commit F 에서 변경된 것들을 가져와서, commit D 에다 대고 변경된 걸 적
용하는 새로운 commit F’ 를 만든다.
33. Cherry-Picking
commit F 를 사용하는게 아니라 복사본을 사용하는 이유는 commit 이 생성되는
방식 때문.
parent commit 은 commit hash 의 일부로 사용되는데,
변경된 내용이 동일하더라도, 다른 parent 를 갖기 때문에 복사본을 사용한다.
일반적인 workflow 는 작은 몇개의 branch 에서 feature 를 개발하고,
master branch 에 merge 하는 것 이다.
이 시나리오를 다시 살펴보면,
34. Cherry-Picking
foo 가 만들어진 후, master 가 업데이트 됐다.
foo 를 master 와 merge 할 때 충돌을 피하기 위해, master 의 변경내용을 foo 로
가져오려고 한다.
master 가 base branch 이기 때문에, master 위에 foo 의 commit 들을 올리려고
한다.
근본적으로 commit C의 부모인 B 부터 F 까지 변경한다.
어려워 보이지만, git cherry-pick 으로 할 수 있다.
우선 commit F 에 임시 branch 를 만든다.
36. Cherry-Picking
이제 남은 일은 foo 가 commit D’ 를 가르키도록 하고, foo-tmp branch 를 삭제하
는 것.
reset 명령어로 할 수 있다, HEAD 를 특정 commit 을 가르키도록 함(현재
branch)
--hard flag 는 working tree 역시 업데이트 하도록 함.
37. Cherry-Picking
foo 의 commit 들이 master 의 upstream 이 되는, 원하는 결과를 얻게됨.
original C, D commit 은 가르키는 branch 가 없기 때문에 접근할 수 없다.
38. Rebasing (Continued)
Cherry-Picking 의 예제가 돌아가긴 하는데, 실용적이진 않음.
rebase 가 장황한 cherry-pick workflow 를 대체해 줌.
git rebase <base> <target>
target 에서 모든 commit 을 가져와 하나씩 base 에 적용함.
base 를 고치지 않고 수행하며, base 가 target 에 fast-forward 할 수 있는 linear
history 를 생성함.
39. Rebasing (Continued)
다른 말로 Git 에게 이렇게 얘기하는 것..
“<target> 이 실제로 <base> 에서 braching 한 것 처럼 됐음 좋겠다. 모든
<target> commit 들이 <base> 다음에 수행된 것처럼 보이게 하고 싶다.”
rebase 가 어떻게 non-fast-forward merge 를 피할 수 있게 하는지,
Merging 에 있던 예제를
다시 보자.
40. Rebasing (Continued)
fast-forward merge 를 하기 위해,
먼저 git rebase master fature-branch
명령을 수행한다.
이 명령은 feature-branch 를 master 의 upstream 으로
가져온다.
Git 은 이제 fast-forward merge 를 수행할 수 있다.
41. Remotes
여러 Git 프로젝트로 작업 하려면, 최소한 한 개의 원격 저장소를 활용해야 함.
중앙 집중식 VCS 가 전용 서버 데몬이 필요한 반면, Git remote 는 단순히 다른
Git 저장소임.
이걸 입증하기 위해, 먼저 bare 저장소라는 개념을 이해해야 함.
Git 이 모든 저장소를 .git 에 저장한다는 것을 상기하자.
이 디렉토리 안에는 전체 프로젝트의 스냅샷을 만들 수 있는 blobs, tree objects
가 있다.
이 말은 실제 working tree 가 필요하지 않다는 것. (단지 마지막 commit 에서 변
경을 확인 하기 위해서만 필요)
이건 간단하게 확인 할 수 있는데, 파일을 하나 지우고 git checkout <file> 하면
다시 생성된다. 이전에 저장소에 저장해 놨기 때문이다.
Git 은 다른 파일들도 동일하게 tree object 들을 순회하면서 복구 할 수 있다.
42. Remotes
working tree 없이 프로젝트 history 를 저장하는 저장소를 만들 수 있음,
이게 bare 저장소 (bare repository)
bare 저장소는 협업자들이 변경을 공유하기 위한 중앙 저장소로 사용된다.
이런 메커니즘은 Pushing, Pulling 섹션에서 자세히 설명한다.
우선 bare 저장소나 만들어 보자.
저장소로 .git 디렉토리를 만들지 않고,
현재 디렉토리를 .git 디렉토리로
간주한다.
43. Remotes
이 저장소에 뭔가 많지 않지만, 몇 가지는 흥미있는게 있다.
● master branch 를 가르키는 HEAD reference
(아직 존재하지 않음)
● bare flag 가 true 로 되어있는 config 파일일
다른 파일은 별로 신경쓸게 없다.
그럼, 이 저장소로 뭘 할 수 있나? 당장은 없다.
working tree 가 없어서 수정할게 없기 때문에..
(엄격하게 보면 사실은 아님, git low-level 명령어로
object 를 만들어서 저장할 수도 있음. 관심 있으면,
Git Internals – Git Objects 참고)
44. Remotes
이 저장소의 목적은 다른 협업자들이 clone 하고, 변경을 pull 하거나, push 하기
위함이다.
45. Remotes - Cloning
bare 저장소를 만들었다. 저장소 cloning 에 대한 개념을 알아보자.
git clone 은 몇 가지 일들을 대신 해주는 단축키 같은 것이다. default 설정이라면
아래 일들을 할꺼다.
1. 원격에 있는 각 branch 를 위해, remote-tracking branch 들을 생성.
2. 원격에 현재 active (HEAD) 인 branch 를 check out.
3. remote-tracking branch 들을 업데이트 하기 위해 git fetch 수행.
4. 현재 branch 와 working tree 를 최신으로 맞추기 위해 git pull 수행.
clone 명령은 URL 을 받고 HTTP, SSH 혹은 Git 자체 프로토콜과 같은 여러 전송
프로토콜을 지원함. 파일 경로도 받는다.
47. Remotes - Cloning
말 그대로 bare-repo 의 clone 이다. 유일하게 다른건 .git/config 에 몇 줄이 더 있
다는거.
remote listing for “origin”
- origin 은 main remote 에게 주어지는 default name.
- 저장소의 URL
- git fetch 할 때 어떤 reference 들을 가져와야 하는지.
branch
- remote-tracking branch 에 대한 설정
48. Remotes - Pushing
빈 저장소를 clone 했는데, 작업을 좀 하자.
기술적으로 .git/refs/heads 에는 없었지만,
이 commit 는 master branch 에서 만들어졌다.
이 저장소의 HEAD 는 master 를 가르키고 있기
때문에, Git 은 master 를 만들었다.
작업한걸 다른 사람과 공유해야 하는데,
Git 은 이걸 정말 쉽게 한다.
49. Remotes - Pushing
Git 이 push 할 remote(origin) 과 branch(master)를 어떻게 기술했는지 보자.
git push 라고만 해도 되지만, 일반적으로 위험하고 신중하지 않다.
git push 는 설정에 근거해서 모든 remote-tracking branch 로 push 할 수 있다.
보통 괜찮지만, 다른 사람이 pull 하지 말아야 할 변경까지 push 할 수 있다.
최악의 경우 --force flag 를 같이 쓰면, 다른 사람의 변경까지 망칠 수 있다.
50. Remotes - Pushing
원격 저장소에 뭔 일이 났는지 보자.
예상 했듯이, 원격 저장소는 방금 만든
commit 을 가리키는 master branch 를
갖고있다.
git push 하면, Git 은 원격 references 를
업데이트 하고, references 를 build 하는데
필요한 object 들을 보낸다.
51. Remotes - Pushing
이 경우, git push 는 원격 master 가 5d591d5 를 가르키도록 하고,
5d591d5 commit object 와 commit 과 관련된 tree, blob objects 도 보낸다.
52. Remotes - Remote-Tracking Branches
Cloning 에서 본것 처럼, remote-tracking branch 는 .git/config 에서 몇 줄 안된
다.
다시보자.
[branch "master"] 는 다음 설정이 로컬 master branch 에 적용된다는 걸 의미한
다.
나머지는, 이 remote-tracking branch 가 fetch 되면, Git 은 origin remote 에서
master branch 를 fetch 하도록 한다.
이 설정 뿐만 아니라, Git 은 remote branch 에 대한 local copy 도 저장한다.
.git/refs/remotes/<remote>/<branch> 와 같이 reference 로 저장된다.
Fetching 에서 더 자세히 보자.
53. Remotes - Fetching
git fetch 는 완전 단순.
remote 이름을 주면(--all 을 주지 않는 다면, 모든 remote fetch), 모든 새로운
references 와 이를 빌드 하기 위한 모든 objects 를 가져온다.
remote 설정이 어땠나 보자.
fetch 는 <remote-refs>:<local-refs> 형태로 기술했다.
origin 의 refs/heads/* 에 있는 references 를 로컬의 refs/remotes/origin/* 에 저장
되도록 한다.
좀 전에 clone 한 저장소에서 볼 수 있다.
54. Remotes - Fetching
뭔일이 일어나는지 fetch 를 좀더 자세히 보자. 우선 원격 저장소에 branch 를 하
나 만든다.
clone 으로 가서 git fetch 를 실행한다.
몇 가지 일을 수행한다.
1) remote branch 에 대한 reference
를 .git/refs/remotes/origin 아래 생성한다.
2) 특별한 파일 .git/FETCH_HEAD 에 중요한
정보를 업데이트 한다. (자세한건 나중에..)
55. Remotes - Fetching
local branch 는 아직 만들지 않았다!
Git 은 원격에 feature-branch 가 있어도, 로컬 저장소엔 필요치 않을 것으로 처리
함.
근데 원격 feature-branch 를 추적하는 local branch 가 필요하다면?
git checkout feature-branch 라고 하면, branch 가 없다고 짜증내지 않고,
remote branch 가 있는지 보고, local branch 를 만들어 준다.
56. Remotes - Fetching
Git 은 여기서 몇 가지 더 해준다.
1) local reference 인 feature-branch 를 만든다.
어디에? .git/refs/heads 에..
.git/refs/remotes 아래 있는 얘들은 remote
reference 들.
이 놈은 remote reference 와 동일한
commit 을 가르킨다.
2) .git/config 에는 remote-tracking branch
entry 를 추가해준다.
57. Remotes - Pulling
git pull 은 git clone 처럼 여러 저수준 명령어들을 묶어서 돌려주는 좋은 단축키.
예를 들어, git pull <remote> <branch> 치면,
1. git fetch <remote> 수행
2. .git/FETCH_HEAD 를 읽어서, <branch> 가 merge 할 remote-tracking
branch 가 있는지 체크.
3. 필요하면 git merge 하고, 아니면 적당한 메세지 뱉고 종료.
요기서, FETCH_HEAD 가 먼지 알면 좋다.
매번 git fetch 를 때릴 때 마다, .git/FETCH_HEAD 에 가져온 branch 정보를 저장
한다.
이걸 short-lived reference 라고 한다. 왜나면 git fetch 칠 때마다 FETCH_HEAD
내용을 엎어치기 때문에..
59. Remotes - Pulling
계속 해서, 다른 clone 에서 변경을 가져오기 위해, 수동으로 git pull 을 해보자.
remote branch 에 대한 local copy 업데이트 했고, FETCH_HEAD 도 업뎃 했다.
60. Remotes - Pulling
FETCH_HEAD 내용을 알다시피,
fetch 에서 feature-branch 에 변경이 있다는걸
알게됐다. “pull” 이 끝나려면 merge 만 남았다.
방금 git pull 하면 수행되는 것들을 수동으로 해봤다.
Git 이 알아서 하게 하는데 훨씬 쉽다.
결과는 동일하다. git pull 도 해보자.
61. Toolkit : git-reflog
branch 에 영향을 주는 변경이 생기면 Git 은 변경에 대한 정보를 기록하며, 이걸
reflog 라고 한다.
보통은 필요 없지만, 가끔 아주 유용하다.
저장소에 commit 이 몇 개 있다.
왠일인지 master branch 에 대고 삽질을 한다.
이래서 몇 개 commit 이 날라갔고, hash 는 알리가
없다.
더군다나 push 한적도 없고, 그냥 로컬 저장소.
git log 도 소용없다. 왜냐면 날라간 얘들은 HEAD 가 가르킬 수 없어서..
62. Toolkit : git-reflog
git reflog 를 써먹을 때다.
reflog 는 HEAD 에 있었던 변경목록을
발생한 순서의 역으로 보여준다.
첫 번째 컬럼의 hash 는 오른쪽 action 이 수행됐을 때 HEAD 의 값이다.
그러니까, 삽질 하기 전에 d6f2a84 commit 이었다는 걸 알 수 있다.
복구하는 방법은 상황에 따라 다른데,
git reset --hard d6f2a84 요렇게 하면, HEAD 를 원래 위치로 복구 할 수 있다.
근데, 삽질 + commit 까지 새로 했다면, 날라간 commit 들을 cherry-pick 할 수도
있을 것이다.
63. Toolkit : git-reflog
유의할 점은 reflog 는 로컬 저장소에서의 변경에 대한 기록이다. (원격아님)
로컬 저장소가 깨지거나 삭제됐으면 reflog 도 소용없다. (저장소가 삭제되면 같
이 삭제됨)
상황에 따라 잃어 버린 commit 을 복구하는데 git fsck 가 더 적절할 수 도 있다.
64. Toolkit : git-fsck
어떤 면에서는 Git 의 object storage 는 원시 파일시스템 처럼 동작한다.
(object = 파일, object hash = 디스크의 물리주소)
Git index 는 파일시스템의 인덱스와 완전 같다. index 는 object 의 물리적인 위
치를 가르키는 reference 를 갖고 있다.
이렇게 봤을 때, git fsck 는 fsck(file system check) 에서 이름을 땄다고 할 수 있
다.
이 툴은 Git 의 database 를 검사하고, 포함된 object 의 validity, reachability 를
검증한다.
branch 와 같은 reference 가 Git 의 index 에서 삭제될 때, 참조하는 object 는 보
통 삭제되지 않는다. 어떤 reference 에서도 참조할 수 없더라도 마찬가지 이다.
65. Toolkit : git-fsck
간단한 예를 들면, feature-branch 가 있고 f71bb43 을 가르키고 있을 때, feture-branch
를 삭제하면, 해당 commit 은 더 이상 접근할 수 없다.
f71bb43 commit 이 아직 저장소에 있긴 하다.
요걸 가르키는 reference 가 없을 뿐 이다.
git fsck 로 database 를 뒤지는 과정에서, 이걸
찾을 수 있당.
66. Toolkit : git-fsck
뭐 간단한 경우면, git reflog 가 좋다.
git fsck 가 더 효과를 발휘하는 경우는, 로컬 저장소에서 한번도 참조된 적이 없
는 object 라서 reflog 조차 없을 때 이다.
예를 들면, GitHub 같은 인터페이스로 remote branch 를 삭제한다. object 들이
아직
garbage-collected 되지 않았다면, 원격 저장소를 clone 한 다음 삭제된 branch
를 git fsck 로 복구 할 수 있다.
67. Toolkit : git-stash
git stash 는 working tree 와 index 의 모든 변경을 긁어와서 구석에 숨겨 놓는다.
working tree 는 깨끗해져~
언제든지 숨겨둔 변경들을 stash 에서 가져와서 현재 working tree 에 적용할 수
있다.
git stash apply 치면됨.
보통은 작업한 걸 잠시 저장하고 다른 branch 로 checkout 할 때 쓴다.
별거 아닌 것 같은데,
내부적으로 돌아가는 건 왕
복잡하다. 실습 하면서 보자.
68. Toolkit : git-stash
변경을 좀 하고, stash
해보자.
Git 에서 stash 들은 stack 에 들어간다.
git stash list 로 리스트를 볼 수 있다.
지금은 하나의 stash 만 있다. stash@{0}
요건 실제로는 reference 이며, 검사해볼 수
있다. (오른 쪽 그림)
69. Toolkit : git-stash
보면, stash 는 commit object 를 가르키고 있다.
흥미로운건 stash commit 이 merge commit 이라는 것이다.
조금 만 더 살펴 볼텐데, 먼저 이 commit 은 어디있는 건가?
현재 branch 는 없고, 다른 branch 는 있을리
없다. git fsck 도 못찾았고, 어디선가 참조하고
있을 텐데, 어딘지?
답은 간단. Git 은 git branch 나 git tag 로 안보이는, stash 를 위한 특별한
reference 를 만든다. 요건 .git/refs/stash 에 있다. git show-ref 로 확인 할 수 있
다.
70. Toolkit : git-stash
근데 왜 stash 를 위해 merge commit 을 만들었을까?
git stash 는 working tree 의 상태를 기록하면서, index 의 상태도 기록한다.
(index 는 흔히 말하는 “staging area”)
index 나 working tree 는 같은 파일에 대한 변경이 있을 수 있어서, 상태를 별도
로 저장할 필요가 있다. 우측과 같은 history 로 볼 수 있다.
commit C 는 working tree 변경 저장,
commit A 는 stash 만들 때, 이전 HEAD
가 가르키던 얘,
commit B 는 index 변경 저장.
B, C 두 개의 commit 으로 stashed
changes 를 재적용 할 수 있다.