1. git internals
Juan de Bravo
@juandebravo
git internals DevCon I 2012/11/27
2. Git. Definition Page 2
free and open source
distributed version control
system designed to handle
everything from small to very
large projects with speed and
efficiency
git internals DevCon I 2012/11/27
12. 1.1 git objects. format and filename Page 12
git object format
- object type: blob|tree|commit|tag
- content size
- null byte
- content
git object filename
SHA1 of the previous format applied to the object
git internals DevCon I 2012/11/27
14. 1.1.1 git objects. blobs Page 14
Git stores every single file content using a blob
object with the git format (object type, etc)
<Blob SHA1>
git internals DevCon I 2012/11/27
21. 1.1.1 git objects. blobs. no file info Page 21
The following two commands are similar
$ # porcelain
$ echo 'Hello, world!' > foo
$ git add foo
$ # plumbing
$ echo 'Hello, world!' | git hash-object -w --stdin
In both cases, a blob object is created in .git/objects
.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
git internals DevCon I 2012/11/27
23. 1 git internals
1.1 git objects
1.1.2 git trees
git internals DevCon I 2012/11/27
24. 1.1.2 git objects. trees Page 24
Trees are used to:
- store the filename of a specific file
- store a group of files together
<Tree SHA1>
git internals DevCon I 2012/11/27
25. 1.1.2 git objects. trees 2 Page 25
# Add a file content to git
$ echo 'Hello, world!' > foo
$ git add foo
$ find .git/objects
.git/objects
.git/objects/af
.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
.git/objects/info
.git/objects/pack
git internals DevCon I 2012/11/27
26. 1.1.2 git objects. create a tree Page 26
# Add a file content to git
$ mkdir bar
$ echo 'Hello, world!' > bar/foo
$ git add bar/foo
$ find .git/objects
.git/objects
.git/objects/af
.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
.git/objects/info
.git/objects/pack
git internals DevCon I 2012/11/27
28. 1.1.2 git objects. create a tree 3 Page 28
$ find .git/objects
.git/objects
.git/objects/83
.git/objects/83/862bbb8472f0b802be96b5e59993ca044f3c31
.git/objects/a8
.git/objects/a8/54cc8b798fb00ad0c3a7a63508b8cffe2e979b
.git/objects/af
.git/objects/af/5626b4a114abcb82d63db7c8082c3c4756e51b
.git/objects/f2
.git/objects/f2/df5266567842bbb8a06acca56bcabf813cd73f
.git/objects/info
.git/objects/pack
git internals DevCon I 2012/11/27
29. 1.1.2 git objects. create a tree 4 Page 29
$ git cat-file -t 83862bbb8472f0b802be96b5e59993ca044f3c31
commit
$ git cat-file -t a854cc8b798fb00ad0c3a7a63508b8cffe2e979b
tree
$ git cat-file -t af5626b4a114abcb82d63db7c8082c3c4756e51b
blob
$ git cat-file -t f2df5266567842bbb8a06acca56bcabf813cd73f
tree
git internals DevCon I 2012/11/27
30. 1.1.2 git objects. create a tree 5 Page 30
git ls-tree
git internals DevCon I 2012/11/27
31. 1.1.2 git objects. inspect a tree Page 31
$ git ls-tree a854cc8b798fb00ad0c3a7a63508b8cffe2e979b
040000 tree f2df5266567842bbb8a06acca56bcabf813cd73f bar
100644 blob af5626b4a114abcb82d63db7c8082c3c4756e51b foo
$ git ls-tree f2df5266567842bbb8a06acca56bcabf813cd73f
100644 blob af5626b4a114abcb82d63db7c8082c3c4756e51b foo
a854cc
af5626
f2df52
af5626
git internals DevCon I 2012/11/27
32. 1.1.2 git objects. inspect a tree 2 Page 32
- Blobs does not store any file specific info
- File specific info is stored in trees
- Same operations, run in different computers,
will create the same blobs/trees.
git internals DevCon I 2012/11/27
34. 1.1.2 git objects. tree. plumbing 3 Page 34
A commit is the easiest way to create a tree, but
it can be created manually (plumbing)
$ git update-index --add --cacheinfo 100644
af5626b4a114abcb82d63db7c8082c3c4756e51b
bazz
$ git update-index --add --cacheinfo 100644
af5626b4a114abcb82d63db7c8082c3c4756e51b
bazz2
$ git write-tree
0a5de923df76ac94a71800e28a4e449171073e3e
git internals DevCon I 2012/11/27
41. 1 git internals
1.1 git objects
1.1.4 git tag
git internals DevCon I 2012/11/27
42. 1.1.4 git objects. tags. lightweight tag Page 42
lightweight tag
Similar to a commit, but points to a
commit rather than to a tree
Like a branch reference, but it never
moves
git internals DevCon I 2012/11/27
43. 1.1.4 git objects. tags. lightweight tag 1 Page 43
λ git tag v1.0
λ git cat-file -p v1.0
tree dba14fbffe61ae959c139d847fcf7709ac7f03d5
parent 83862bbb8472f0b802be96b5e59993ca044f3c31
author juandebravo <juandebravo@gmail.com> 1353954525 +0100
committer juandebravo <juandebravo@gmail.com> 1353954525 +0100
git internals DevCon I 2012/11/27
44. 1.1.4 git objects. tags. annotated tag Page 44
annotated tag
Stored as full objects:
- checksum
- tagger name, email, date
- comment
- can be signed and verified
git internals DevCon I 2012/11/27
45. 1.1.4 git objects. tags. anotated tag Page 45
λ git tag -a v1.1 -m "version 1.1"
λ git cat-file -p v1.1
object c2120756cce9f359373d2fd42f8eac5cd5f9cbe9
type commit
tag v1.1
tagger juandebravo <juandebravo@gmail.com> Tue Nov 22 17:42:02
2012 +0100
version 1.1
git internals DevCon I 2012/11/27
46. 1.1.4 git objects. tags. anotated tag 2 Page 46
λ cd CONNECT/tid-commons
λ ls -l
total 32
-rw-r--r-- 1 jdbd staff 1594 27 Nov 07:47 LICENSE.txt
-rw-r--r-- 1 jdbd staff 1909 27 Nov 07:47 README.md
drwxr-xr-x 2 jdbd staff 68 22 Aug 13:21 dist
-rw-r--r-- 1 jdbd staff 114 30 Oct 23:53 setup.cfg
-rw-r--r-- 1 jdbd staff 312 27 Nov 07:47 setup.py
drwxr-xr-x 18 jdbd staff 612 27 Nov 07:47 tests
drwxr-xr-x 24 jdbd staff 816 27 Nov 07:47 tid_commons
git internals DevCon I 2012/11/27
47. 1.1.4 git objects. tags. anotated tag 3 Page 47
λ git ls-tree HEAD
100644 blob 0d20b6487c61e7d1bde93acf4a14b7a89083a16d .gitignore
100644 blob a27144556d3b857a6fb609f39be204996e1f7792 LICENSE.txt
100644 blob 15446c94618f3863584814d669048dc3def789cf README.md
100644 blob b6c8d6c27ce614109dcb07b2e655ce13727675fa setup.cfg
100644 blob 6ee4913e18e4a6a2320ac1e540a585f12bc110b2 setup.py
040000 tree a7c28bc15f440bcf3783915f24ff3336b81dd01f tests
040000 tree 35ea155eb6899a337b1b0ed5307d0882a0b7858e tid_commons
git internals DevCon I 2012/11/27
48. 1.1.4 git objects. tags. anotated tag 4 Page 48
λ git tag -a LICENSE a2714455 -m "License file"
λ git cat-file -p LICENSE
object a27144556d3b857a6fb609f39be204996e1f7792
type blob
tag LICENSE
tagger juandebravo <juandebravo@gmail.com> Tue Nov 27 07:48:36 2012 +0100
License file
git internals DevCon I 2012/11/27
54. 1.2.1 git internal structure. HEAD 4 Page 54
# Check where HEAD is pointing to
$ git symbolic-ref HEAD
refs/heads/feature/memoize/client
# Modify HEAD
$ git symbolic-ref HEAD refs/head/master
$ cat .git/HEAD
refs/heads/master
git internals DevCon I 2012/11/27
55. 1.2.1 git internal structure. HEAD 5 Page 55
# Example. zsh
# get the name of the branch we are on
function git_prompt_info() {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return
echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$
(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_SUFFIX"
}
juandebravo [~/projects/git_internals/repo] (master) ✓
git internals DevCon I 2012/11/27
56. 1.2.2 git internal structure. config Page 56
CONFIG
repository specific configuration
git internals DevCon I 2012/11/27
72. 2.1 git bisect Page 72
The bisect command does a binary
search through your commit history
to help you identify as quickly as
possible which commit introduced an
issue.
git internals DevCon I 2012/11/27
74. 2.1 git bisect 2 Page 74
λ tree
.
!"" main
# !"" __init__.py
# $"" foo.py
$"" tests
$"" foo_tests.py
git internals DevCon I 2012/11/27
75. 2.1 git bisect 3 Page 75
import re
reg_expr = re.compile('^d{,10}$')
class Foo(object):
@staticmethod
def is_valid(value):
_value = reg_expr.match(str(value))
return True if _value else False
git internals DevCon I 2012/11/27
76. 2.1 git bisect 4 Page 76
import unittest
from pyshould import should
from main.foo import Foo
class TestFoo(unittest.TestCase):
def setUp(self):
self.foo = Foo
def test_is_valid_string(self):
self.foo.is_valid('1234') | should.be_true
def test_is_valid_number(self):
self.foo.is_valid(1234) | should.be_true
def test_is_valid_one_digit(self):
self.foo.is_valid(1) | should.be_true
git internals DevCon I 2012/11/27
77. 2.1 git bisect 5 Page 77
λ nosetests -sv
test_is_valid_number (foo_tests.TestFoo) ... ok
test_is_valid_one_digit (foo_tests.TestFoo) ... ok
test_is_valid_string (foo_tests.TestFoo) ... ok
---------------------------------------------------------
Ran 3 tests in 0.013s
OK
git internals DevCon I 2012/11/27
79. 2.1 git bisect 7 Page 79
λ nosetests -sv
test_is_valid_number (foo_tests.TestFoo) ... FAIL
test_is_valid_one_digit (foo_tests.TestFoo) ... ok
test_is_valid_string (foo_tests.TestFoo) ... FAIL
-------------------------------------------------------
Ran 3 tests in 0.013s
FAILED (failures=2)
git internals DevCon I 2012/11/27
80. 2.1 git bisect 8 Page 80
git bisect is your friend
1) Figure out a commit that was right: good commit
2) Figure out a commit that is wrong: the current
one, bad commit
3) run git bisect command
git internals DevCon I 2012/11/27
83. 2.1 git bisect 10 Page 83
λ git bisect start HEAD 9a8bdf8
Bisecting: 5 revisions left to test after this
(roughly 3 steps)
[ec56109cc441293571a0773c83006afe483ff0e6] change regepx
git internals DevCon I 2012/11/27
85. 2.1 git bisect 12 Page 85
$ git bisect run nosetests -sv
Ran 3 tests in 0.014s
OK
Bisecting: 2 revisions left to test after this (roughly 2
steps)
[898489c1e7b77989717a84f08f49f43cf215c120] change regepx
git internals DevCon I 2012/11/27
87. 2.1 git bisect 13 Page 87
----------------------------------------------------------
Ran 3 tests in 0.014s
FAILED (failures=2)
Bisecting: 0 revisions left to test after this (roughly 1
step)
[f6838032010b18a7e3998f4a2fdcde65124424a2] change regepx
git internals DevCon I 2012/11/27
89. 2.1 git bisect 14 Page 89
----------------------------------------------------------
Ran 3 tests in 0.013s
OK
898489c1e7b77989717a84f08f49f43cf215c120 is the first bad
commit
commit 898489c1e7b77989717a84f08f49f43cf215c120
Author: juandebravo <juandebravo@gmail.com>
Date: Mon Nov 26 21:48:50 2012 +0100
change regepx
:040000 040000 70ccfdcf5d796cbd581a840c1c92ebe47b40345e
3912c8faed49a91e6fe3f68e7370a86c120c2844 M
main
bisect run success
git internals DevCon I 2012/11/27
91. 2.1 git bisect 16 Page 91
Reset: remove bisect information from history
λ git bisect reset
Previous HEAD position was f683803... change regepx
Switched to branch 'master'
git internals DevCon I 2012/11/27
93. 2.2 git reflog Page 93
A log of where your HEAD and
branch references have been
for the last few months.
git internals DevCon I 2012/11/27
94. 2.2 git reflog 4 Page 94
It persists independently of other changes
in your repository.
I could unlink any commit from my
repository (using reset), yet it would
still be referenced by the reflog for
another 30 days!
git internals DevCon I 2012/11/27
95. 2.2 git reflog 2 Page 95
$ git reflog
dc46efc HEAD@{0}: checkout: moving from 2ca0083fc6ba6bdfbf3000122eba51359309ae7f to master
2ca0083 HEAD@{1}: checkout: moving from master to HEAD@{22}
dc46efc HEAD@{2}: checkout: moving from 1824e4fdcf1fc963554b2ae671ede799a692838a to master
1824e4f HEAD@{3}: checkout: moving from ec56109cc441293571a0773c83006afe483ff0e6 to
HEAD@{36}
ec56109 HEAD@{4}: checkout: moving from master to HEAD@{70}
dc46efc HEAD@{5}: checkout: moving from f6838032010b18a7e3998f4a2fdcde65124424a2 to master
f683803 HEAD@{6}: checkout: moving from 898489c1e7b77989717a84f08f49f43cf215c120 to
f6838032010b18a7e3998f4a2fdcde651
898489c HEAD@{7}: checkout: moving from ec56109cc441293571a0773c83006afe483ff0e6 to
898489c1e7b77989717a84f08f49f43cf
ec56109 HEAD@{8}: checkout: moving from master to ec56109cc441293571a0773c83006afe483ff0e6
dc46efc HEAD@{9}: checkout: moving from master to master
dc46efc HEAD@{10}: checkout: moving from a8aa38f28e9bc76bdc73603b73f1a31a674b28dd to master
git internals DevCon I 2012/11/27
96. 2.2 git reflog 3 Page 96
$ git show HEAD@{5}
$ git show master@{2.months.ago}
git internals DevCon I 2012/11/27
97. 2 git advanced topics
2.1 git rebase
2.2 git bisect
2.3 git stash
git internals DevCon I 2012/11/27
98. 2.3 git stash 9 Page 98
Imagine this scenario...
git internals DevCon I 2012/11/27
99. 2.3 git stash Page 99
1) you are working in a cool user story
2) a JIRA task is assigned to you
git internals DevCon I 2012/11/27
100. 2.3 git stash 11 Page 100
1) you are working in a cool user story
2) a JIRA task is assigned to you
3) JIRA is down
git internals DevCon I 2012/11/27
101. 2.3 git stash 10 Page 101
1) you are working in a cool user story
2) a JIRA task is assigned to you
3) JIRA is down
4) coffee while JIRA comes back to life
5) you figure out what you should do
6) you need to switch to another branch
7) but you don't want to commit half-work
git internals DevCon I 2012/11/27
103. 2.3 git stash 3 Page 103
λ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: main/foo.py
#
no changes added to commit (use "git add" and/or "git commit -a")
git internals DevCon I 2012/11/27
104. 2.3 git stash 4 Page 104
λ git stash
Saved working directory and index state WIP on master:
dc46efc add unittest main
HEAD is now at dc46efc add unittest main
λ git stash list
stash@{0}: WIP on master: dc46efc add unittest main
git internals DevCon I 2012/11/27