git internals
TRANSCRIPT
git internals
dbyrne23andMe
agenda
1.data ... in two commits
a. blobs
b. trees
c. commits
2.algorithms ... in six commitsa. commit
b. branch
c. merge
d. reset
e. rebase
objects
commits
trees
blobs
objects, blobs
$ git init objects_example
$ cd objects_example
$ echo "puts 'hello world'" > foo.rb
$ git add foo.rb
$ strings .git/index | grep hello
$ strings .git/index | grep foo.rb
foo.rb
objects, blobs$ find .git/objects -type file
.git/objects/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
$ git cat-file -t aaaa # what type of object is this?
blob
$ git cat-file -p aaaa # print the object
puts 'hello world'
objects, blobs$ echo "puts 'hello world'" > bar.rb
$ git add bar.rb
$ strings .git/index | grep bar.rb
bar.rb
$ find .git/objects -type file # no new blob
.git/objects/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
objects
$ git commit -m 'commit msg #1'
$ find .git/objects -type file
.git/objects/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
.git/objects/bb/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
.git/objects/cc/cccccccccccccccccccccccccccccccccccccc
objects, trees$ git cat-file -t bbbb
tree
$ git cat-file -p bbbb
100644 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bar.rb
100644 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa foo.rb
objects, commits$ git cat-file -t cccc
commit
$ git cat-file -p cccc
tree bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
author dbyrne <[email protected]> 1474171822 -0700
committer dbyrne <[email protected]> 1474171822 -0700
commit msg #1
c
a
b
foo.rb bar.rb
objects
$ mkdir dir
$ echo "puts 'hello world'" > dir/baz.rb
$ git add dir/baz.rb
$ git commit -m 'commit msg #2'
objects$ find .git/objects -type file
.git/objects/aa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
.git/objects/bb/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
.git/objects/cc/cccccccccccccccccccccccccccccccccccccc
.git/objects/dd/dddddddddddddddddddddddddddddddddddddd <- new
.git/objects/ee/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee <- new
.git/objects/ff/ffffffffffffffffffffffffffffffffffffff <- new
objects$ git cat-file -p HEAD^{commit} # same as ffff
tree eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
parent cccccccccccccccccccccccccccccccccccccccc
author dbyrne <[email protected]> 1474172113 -0700
committer dbyrne <[email protected]> 1474172113 -0700
commit msg #2
objects
$ git cat-file -p HEAD^{tree} # same as eeee
100644 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bar.rb
040000 tree dddddddddddddddddddddddddddddddddddddddd dir
100644 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa foo.rb
objects$ git cat-file -t dddd
tree
$ git cat-file -p dddd
100644 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa baz.rb
c
a
b /
f
e /
d /dir
foo.rb
bar.rb
baz.rb
foo.rb bar.rb
objectsthere are three types of objects: blobs, trees & commits
blobs represent files
blobs are created with the add, not the commit command
blobs are snapshots, not deltas or patches
the add command records snapshots every time
a file can be both “staged” and “modified”
trees represent directories
trees point to blobs and/or trees
commits point to trees and most likely each other
a SHA can be abbreviated with a minimum of four chars
refs$ ls .git/HEAD
.git/HEAD <- important
$ tree .git/refs/
├── heads <- important
│ └── master
├── remotes
├── stash
└── tags
git commit$ git init refs_example
$ cd refs_example
$ echo "print 'commit #1'" > spam.py
$ git add spam.py
$ git commit -m 'commit msg #1'
[master (root-commit) 1111111] commit msg #1
git commit$ ls .git/objects/11
11111111111111111111111111111111111111
$ cat .git/refs/heads/master
1111111111111111111111111111111111111111
$ cat .git/HEAD
ref: refs/heads/master
git commit
1111
master
HEAD
top to bottom
5HEAD
branch
commit
tree
blob
git commit$ echo "print 'commit #2'" >> spam.py
$ git commit -am 'commit msg #2'
[master 2222222] commit msg #2
$ cat .git/HEAD
ref: refs/heads/master
git commit
1111
master
HEAD2222
git commit$ git show-ref master --abbrev
2222222 refs/heads/master
$ git cat-file -p 2222 | grep parent
parent 1111111111111111111111111111111111111111
git branch$ git branch feature_branch
$ ls .git/refs/heads/
feature_branch
master
$ git show-ref --abbrev
2222222 refs/heads/feature_branch
2222222 refs/heads/master
git branch
1111
master
HEAD2222
feature_branch
git checkout$ cat .git/HEAD
ref: refs/heads/master <- before
$ git checkout feature_branch
$ cat .git/HEAD
ref: refs/heads/feature_branch <- after
git checkout
1111
master
HEAD2222
feature_branch
working on a branch$ echo "print 'commit #3'" > eggs.py
$ git add eggs.py
$ git commit -m 'commit msg #3'
[feature_branch 3333333] commit msg #3
$ git show-ref --abbrev
3333333 refs/heads/feature_branch
2222222 refs/heads/master
working on a branch
1111
master
HEAD2222
feature_branch
3333
divergence$ git checkout master
$ echo "print 'commit #4'" > spam.py
$ git commit -am 'commit msg #4'
[master 4444444] commit msg #4
divergence
1111
master
HEAD2222
feature_branch
3333
4444
git merge$ git merge --no-edit feature_branch
Merge made by the 'recursive' strategy. <- important
eggs.py | 1 +
1 file changed, 1 insertion($)
create mode 100644 eggs.py
git merge
1111
master
HEAD2222
feature_branch
3333
4444
5555
git lol$ git log --graph --oneline --decorate
* 5555555 (HEAD -> master) Merge branch 'feature_branch'
|\
| * 3333333 (feature_branch) commit msg #3
* | 4444444 commit msg #4
|/
* 2222222 commit msg #2
* 1111111 commit msg #1
git merge$ git show-ref master --abbrev
5555555 refs/heads/master
$ git cat-file -p 5555 | grep parent
parent 4444444444444444444444444444444444444444 <- master
parent 3333333333333333333333333333333333333333 <- fe. br.
merge vs. rebase
record of what
actually happened
vs. story of how your
project was made
git reset (to a commit)
change index? change working dir? working dir safe?
git reset --soft SHA Yes No
git reset --mixed SHA No Yes
git reset --hard SHA Yes Yes
git reset$ git show-ref --abbrev
3333333 refs/heads/feature_branch
5555555 refs/heads/master
$ git reset --hard HEAD^
HEAD is now at 4444444 commit msg #4
$ git show-ref --abbrev
3333333 refs/heads/feature_branch
4444444 refs/heads/master
git reset
1111
master
HEAD2222
3333
4444
5555
feature_branch
feature_branch
git reset, simplified
1111
master
HEAD2222
3333
4444
git rebase$ git show-ref feature_branch --abbrev
3333333 refs/heads/feature_branch
$ git checkout feature_branch
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: commit msg #3
$ git show-ref feature_branch --abbrev
6666666 refs/heads/feature_branch
git rebase
1111
master
HEAD2222
feature_branch
3333
4444
6666
git rebase, simplified
1111
master
HEAD2222
feature_branch
4444 6666
git merge - fast forward$ git checkout master
$ git merge feature_branch
Updating 4444444..6666666
Fast-forward <- important
eggs.py | 1 $
1 file changed, 1 insertion($)
create mode 100644 eggs.py
git merge - fast forward
1111
master
HEAD2222
feature_branch
4444 6666
git merge - fast forward$ git show-ref --abbrev
6666666 refs/heads/feature_branch
6666666 refs/heads/master
$ ls
eggs.py
spam.py
git reflog$ git reflog
6666666 HEAD@{0}: merge feature_branch: Fast-forward
...6666666 HEAD@{3}: rebase: commit msg #3...4444444 HEAD@{6}: reset: moving to HEAD^
5555555 HEAD@{7}: merge feature_branch: Merge made by the 'recursive' strategy....
git fsck$ echo "lost?" >> spam.py && git add spam.py
$ echo "no" >> spam.py && git add spam.py
$ git fsck --unreachable
unreachable blob 7777777777777777777777777777777777777777
$ git cat-file -p 7777
print 'commit #4'
lost?
git gc$ git fsck --unreachable
unreachable blob 7777777777777777777777777777777777777777
$ git gc --prune=all
$ git fsck --unreachable
$ git cat-file -p 7777
fatal: Not a valid object name 7777
detached head state$ git checkout 5555555
<(HEAD detached at 5555555)> $ cat .git/HEAD
5555555555555555555555555555555555555555
<(HEAD detached at 5555555)> $ # look around, even do work
$ git checkout -b nostalgia
$ git branch
feature_branch master* nostalgia
trends