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

Mais conteúdo relacionado

Destaque

[아주대] 오픈 소스와 글로벌 경쟁력
[아주대] 오픈 소스와 글로벌 경쟁력[아주대] 오픈 소스와 글로벌 경쟁력
[아주대] 오픈 소스와 글로벌 경쟁력Daniel Juyung Seo
 
개발자와 영어 Why and how
개발자와 영어 Why and how개발자와 영어 Why and how
개발자와 영어 Why and howMinwoo Park
 
Opensource realm soscon
Opensource realm sosconOpensource realm soscon
Opensource realm sosconMinwoo Park
 
[스마트스터디] 재택근무 잘 하고 있어요
[스마트스터디] 재택근무 잘 하고 있어요[스마트스터디] 재택근무 잘 하고 있어요
[스마트스터디] 재택근무 잘 하고 있어요Hyekyoung Yun
 
모바일광고플랫폼
모바일광고플랫폼모바일광고플랫폼
모바일광고플랫폼Lee Ji Eun
 
OAuth2 - API 인증을 위한 만능도구상자
OAuth2 - API 인증을 위한 만능도구상자OAuth2 - API 인증을 위한 만능도구상자
OAuth2 - API 인증을 위한 만능도구상자Minwoo Park
 
2017디지털마케팅트렌드분석조사결과
2017디지털마케팅트렌드분석조사결과2017디지털마케팅트렌드분석조사결과
2017디지털마케팅트렌드분석조사결과Digital Initiative Group
 

Destaque (9)

[아주대] 오픈 소스와 글로벌 경쟁력
[아주대] 오픈 소스와 글로벌 경쟁력[아주대] 오픈 소스와 글로벌 경쟁력
[아주대] 오픈 소스와 글로벌 경쟁력
 
개발자와 영어 Why and how
개발자와 영어 Why and how개발자와 영어 Why and how
개발자와 영어 Why and how
 
Opensource realm soscon
Opensource realm sosconOpensource realm soscon
Opensource realm soscon
 
[스마트스터디] 재택근무 잘 하고 있어요
[스마트스터디] 재택근무 잘 하고 있어요[스마트스터디] 재택근무 잘 하고 있어요
[스마트스터디] 재택근무 잘 하고 있어요
 
모바일광고플랫폼
모바일광고플랫폼모바일광고플랫폼
모바일광고플랫폼
 
OAuth2 - API 인증을 위한 만능도구상자
OAuth2 - API 인증을 위한 만능도구상자OAuth2 - API 인증을 위한 만능도구상자
OAuth2 - API 인증을 위한 만능도구상자
 
learn-python
learn-pythonlearn-python
learn-python
 
2017디지털마케팅트렌드분석조사결과
2017디지털마케팅트렌드분석조사결과2017디지털마케팅트렌드분석조사결과
2017디지털마케팅트렌드분석조사결과
 
Key Digital Trends for 2017
Key Digital Trends for 2017Key Digital Trends for 2017
Key Digital Trends for 2017
 

Semelhante a 해커스 가이드 투 깃

Git from google techtalks by Randal
Git from google techtalks by RandalGit from google techtalks by Randal
Git from google techtalks by Randalyagurchoi
 
Git: A Motivating Introduction
Git: A Motivating IntroductionGit: A Motivating Introduction
Git: A Motivating IntroductionJongwook Choi
 
Git server 구축(git olite,gitweb)
Git server 구축(git olite,gitweb)Git server 구축(git olite,gitweb)
Git server 구축(git olite,gitweb)진혁 박
 
[17.02.09] Github introduction (Korean Version)
[17.02.09] Github introduction (Korean Version)[17.02.09] Github introduction (Korean Version)
[17.02.09] Github introduction (Korean Version)Ildoo Kim
 
리스펙토링 5월 세미나, git과 github
리스펙토링 5월 세미나, git과 github리스펙토링 5월 세미나, git과 github
리스펙토링 5월 세미나, git과 githubJungHoon Lee
 
svn 능력자를 위한 git 개념 가이드
svn 능력자를 위한 git 개념 가이드svn 능력자를 위한 git 개념 가이드
svn 능력자를 위한 git 개념 가이드Insub Lee
 
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습 [숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습 Soongsil University
 
Git Tutorial
Git TutorialGit Tutorial
Git TutorialMDLicht
 
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기CONNECT FOUNDATION
 
깃허브 시작하기
깃허브 시작하기깃허브 시작하기
깃허브 시작하기진태 이
 
git, 이해부터 활용까지
git, 이해부터 활용까지git, 이해부터 활용까지
git, 이해부터 활용까지jylee1229
 
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+github
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+githubGit 더하기 GitHub(Git클라이언트 활용) / Getting started with git+github
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+githubJunyoung Lee
 
리스펙토링 세미나 - Git, Github 알아보기
리스펙토링 세미나 - Git, Github 알아보기리스펙토링 세미나 - Git, Github 알아보기
리스펙토링 세미나 - Git, Github 알아보기Wooyoung Ko
 
Git branch stregagy & case study
Git branch stregagy & case studyGit branch stregagy & case study
Git branch stregagy & case studyWoo Jin Kim
 

Semelhante a 해커스 가이드 투 깃 (20)

Git from google techtalks by Randal
Git from google techtalks by RandalGit from google techtalks by Randal
Git from google techtalks by Randal
 
Git: A Motivating Introduction
Git: A Motivating IntroductionGit: A Motivating Introduction
Git: A Motivating Introduction
 
Git
Git Git
Git
 
Git server 구축(git olite,gitweb)
Git server 구축(git olite,gitweb)Git server 구축(git olite,gitweb)
Git server 구축(git olite,gitweb)
 
[17.02.09] Github introduction (Korean Version)
[17.02.09] Github introduction (Korean Version)[17.02.09] Github introduction (Korean Version)
[17.02.09] Github introduction (Korean Version)
 
리스펙토링 5월 세미나, git과 github
리스펙토링 5월 세미나, git과 github리스펙토링 5월 세미나, git과 github
리스펙토링 5월 세미나, git과 github
 
svn 능력자를 위한 git 개념 가이드
svn 능력자를 위한 git 개념 가이드svn 능력자를 위한 git 개념 가이드
svn 능력자를 위한 git 개념 가이드
 
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습 [숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습
[숭실대학교 SODA]깃(git) 명령 및 소스트리(sourceTree) 실습
 
Git Tutorial
Git TutorialGit Tutorial
Git Tutorial
 
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기
[부스트캠프 Tech Talk] 최재필_P 스테이지에서 Git으로 협업하기
 
Git 코드랩 스터디 1
Git 코드랩 스터디 1Git 코드랩 스터디 1
Git 코드랩 스터디 1
 
깃허브 시작하기
깃허브 시작하기깃허브 시작하기
깃허브 시작하기
 
git, 이해부터 활용까지
git, 이해부터 활용까지git, 이해부터 활용까지
git, 이해부터 활용까지
 
Git lecture2
Git lecture2Git lecture2
Git lecture2
 
git-workflow
git-workflowgit-workflow
git-workflow
 
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+github
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+githubGit 더하기 GitHub(Git클라이언트 활용) / Getting started with git+github
Git 더하기 GitHub(Git클라이언트 활용) / Getting started with git+github
 
Git lecture1
Git lecture1Git lecture1
Git lecture1
 
리스펙토링 세미나 - Git, Github 알아보기
리스펙토링 세미나 - Git, Github 알아보기리스펙토링 세미나 - Git, Github 알아보기
리스펙토링 세미나 - Git, Github 알아보기
 
Git branch stregagy & case study
Git branch stregagy & case studyGit branch stregagy & case study
Git branch stregagy & case study
 
Git
GitGit
Git
 

해커스 가이드 투 깃

  • 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 를 볼 수 있다.
  • 12. Commits hash 는 unique 하기 때문에, 4글자 정도면 충분하다. 4자 미만이면 오류.
  • 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 를 만들어서 작업함.
  • 24. Merging history 는 이럴 것이다.
  • 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 이라고 한다.
  • 29. Merging history graph 는 이럴 것 이다. E 는 새로운 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 를 만든다.
  • 35. Cherry-Picking 이제 commit F 를 base 로 해서, foo 의 모든 commit 을 cherry-pick 할 수 있다.
  • 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 자체 프로토콜과 같은 여러 전송 프로토콜을 지원함. 파일 경로도 받는다.
  • 46. Remotes - Cloning Git 이 어떻게 set up 했는지 보기 위해, clone 된 저장소를 살펴보자.
  • 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 내용을 엎어치기 때문에..
  • 58. Remotes - Pulling 실제로 원격에 새로운 commit 을 몇개 넣고 어떻게 되나보자.
  • 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 를 재적용 할 수 있다.