Git presentation, internals, advanced use and workflow examples.
Presentation by Tommaso Visconti http://www.tommyblue.it for DrWolf srl http://www.drwolf.it
5. Git uses snapshots
•
A version is a tree (like a FS) using hashes as nodes
•
Every version is a snapshot of the full repository, with all files
•
A file is identified by a SHA-1 hash, depending on the file content
•
If the content doesn’t change, the hash is the same
7. The .git folder
Everything is in the .git folder (delete it to delete repo)
.git/
hooks/
info/
objects/
=>
refs/
=>
config
description
index
=>
HEAD
=>
repo content
commit objects’ pointers
stage infos
checkouted branch
8. Git objects
Git works like a key-value datastore
When you save an object in Git, it returns its hash
All the object are identified by an hash
Objects
!
Blob
Tree
Commit
TAG
9. Blob objects - 1
Essentially the committed file with its content
# Save a simple text file (without -w it calculates the hash)
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4
# The created object (notice the folder structure)
$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
# Extract the content using the hash as reference
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
10. Blob objects - 2
# New version of the file
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30
# Now there are two objects
$ find .git/objects -type f
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
# Restore the old version
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 >
test.txt
11. Tree objects
Contains references to its children (trees or blobs), like a UNIX folder
Every commit (snapshot) has a different tree
# Adds a file to the index (staging area)
$ git update-index --add --cacheinfo 100644
a906cb2a4a904a152e80877d4088654daad0c859 README
# Write the tree object (containing indexed/staged files)
$ git write-tree
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
tree
# Show the tree object content
$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
100644 blob a906cb2a4a904a152e80877d4088654daad0c859
README
100644 blob 8f94139338f9404f26296befa88755fc2598c289
Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
lib
12. Commit objects - 1
Commit message, other informations (GPG) and reference to a
tree object (through its hash)
# First commit object given a tree object (1f7a7a)
$ echo 'first commit' | git commit-tree 1f7a7a
fdf4fc3344e67ab068f836878b6c4951e3b15f3d
# Let’s check the commit content
$ git cat-file -p fdf4fc3
tree 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
author Tommaso Visconti <tommaso.visconti@drwolf.it> 1243040974 -0700
committer Tommaso Visconti <tommaso.visconti@drwolf.it> 1243040974 -0700
!
first commit
13. TAG objects
Lightweight tag
Like a commit with reference to a commit object (not a tree)
Annotated tag
Git creates a tag object and the ref tag pointing to its hash
$ 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 Tommaso Visconti <tommaso.visconti@drwolf.it> Mon Nov 25 15:56:23 2013
!
test tag
14. References - 1
Useful to avoid using and remembering hashes
Stored in .git/refs/
Text files just containing the commit hash
15. References - 2
Branches are references stored in .git/refs/heads
# Update master ref to the last commit
$ git update-ref refs/heads/master 1a410e
Lightweight tags are refs placed in .git/refs/tags
Remotes are refs stored in
.git/refs/remotes/<REMOTE>/<BRANCH>
!
The commit hash of a remote is the commit of that branch
the last time the remote was synchronized (fetch/push)
17. HEAD - 1
How GIT knows which branch or commit is checkouted?
# HEAD is a symbolic reference
$ cat .git/HEAD
ref: refs/heads/master
# Get HEAD value using the proper tool
$ git symbolic-ref HEAD
refs/heads/master
# Set HEAD
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
18. HEAD - 2
HEAD generally points to the checked out branch
Committing in this situation means set a new hash to the
current branch and, as a consequence, HEAD points to it
HEAD can be moved with git reset
If HEAD points to a commit and not a branch, it’s the so
called Detached HEAD
Committing in this situation means advance HEAD to the
new commit hash, without modifying any branch
20. Detached HEAD - 2
$ cat .git/HEAD
ref: refs/heads/master
$ git checkout 30657817081f6f0808bf37da470973ad12cb7593
Note: checking out '30657817081f6f0808bf37da470973ad12cb7593'.
!
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
!
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
!
git checkout -b new_branch_name
!
HEAD is now at 3065781... message1
$ cat .git/HEAD
30657817081f6f0808bf37da470973ad12cb7593
22. Detached HEAD - 4
$ git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
!
!
b843940 det commit
If you want to keep them by creating a new branch, this may be a good time
to do so with:
!
!
git branch new_branch_name b843940
Switched to branch 'master'
$ git log
commit 33676f027d9c36c66f2a2d5d74ee1cbf3e1ff56b
Author: Tommaso Visconti <tommaso.visconti@gmail.com>
Date:
Mon Nov 25 16:40:31 2013 +0100
!
!
test2
commit 30657817081f6f0808bf37da470973ad12cb7593
Author: Tommaso Visconti <tommaso.visconti@gmail.com>
Date:
Mon Nov 25 16:39:53 2013 +0100
!
message1
The b843940 commit
is gone.. :-(
24. Background: refspec
A refspec is a mapping between remote and local branch
An example is the fetch entry in a remote config:
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/*:refs/remotes/origin/*
Format: +<src>:<dst>
<src>: where those references will be written locally
<dst>: pattern for references on the remote side
+: (optional) update the reference even if it isn’t a fast-forward
25. Background: ancestry references
Given a ref (eg. HEAD):
•
•
•
•
HEAD^ is the first parent of HEAD
HEAD^2 is the second parent (and so on..)
HEAD~ is identical to HEAD^1
HEAD~2 is is the parent of the parent of HEAD
^ is useful for merging, where a commit has two or more parents
26. Background: ranges
git log <refA>..<refB>
All commits reachable by refB that aren’t reachable by refA
Commits in refB not merged in refA
Synonyms:
git log ^refA refB
git log refB --not refA
git log refA refB ^refC
!
The last is useful when using more refs
27. Background: ranges
git log <refA>…<refB>
All commits either reachable by refB and refA
but not both of them
Commits to be merged between the two refs
30. Basic commands - 2
git commit and commit message
Commit description (visible with —oneline) max 50 chars
!
Commit full message. Breakline at 72nd char
Buzzword buzzword buzzword buzzword buzzword buzzword buzzword
buzzword buzzword buzzword buzzword buzzword buzzword buzzword
!
Commit footer
Commands, eg:
fixes #<BUG>
ecc.
git commit --amend
31. Basic commands - 3
git log
# Short diff
git log --oneline
!
# Line diff between files
git log -p
# Diff stats without lines
git log --stat
!
# Pretty diff with tree
git log --pretty=format:'%h %s' --graph
!
# Word diff
git log -p —word-diff
git diff
# Diff with remote
git diff HEAD..origin/master
.gitignore
# Exact match (absolute path)
/public/README
!
# All matches
public/README
READ*
32. Useful tools
git blame
git bisect
Show the author of each line
Find the problematic commit
git alias
git filter-branch
Create command aliases
Hard change of history
to delete committed passwords
git format-patch
git request-pull
Create a patch file ready to be
sent to somebody
Implement pull-request workflow
33. Git stash
Save unstaged changes for future reuse
Create a branch from stash:
git stash branch <BRANCH>
git unstash doesn’t exist but:
git stash show -p stash@{0} | git apply -R
Create an alias to do it:
git config --global alias.stash-unapply '!git stash show -p | git apply -R'
34. Git reset
Move HEAD to specific state (e.g. commit)
--soft
Move only HEAD
--mixed Move HEAD and reset the staging
area to it (default)
--hard
Move HEAD and reset staging area
and working tree
git reset [option] <PATH>
Don’t move HEAD, but reset the PATH (staging area and working tree,
depending from option)
36. Fetch
Sync remotes status: git fetch <remote>
Uses .git/config to know what to update
[remote "origin"]
url = git@github.com:schacon/simplegit-progit.git
fetch = +refs/heads/master:refs/remotes/origin/master
fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*
After checking a remote status we can:
•
•
•
merge
rebase
cherry-pick
37. Pull
git pull origin master
=
git fetch origin
git merge origin/master
In both cases the master branch must be checkouted
38. Fast-forward merge
When a branch has commits which are direct predecessor
of the branch where we’re merging, this is a so called
fast-forward merge
To merge iss53 to master,
git just advances master
pointer to C3 without
creating a commit
object. This is a fastforward merge
Use merge --no-ff to force creation of a commit object
39. 3-way merge
When the commit to be merged isn’t a direct predecessor
of the commit to merge into
C5 is a new commit object, including merge informations
41. Rebase
The experiment’s
commits (C3) become
a single commit (as a
patch) C3’ which is
applied to master
It’s a rebase on experiment, then a FF merge on master
git
git
git
git
checkout experiment
rebase master # C3’ is created
checkout master
merge experiment # FF merge
44. Advanced rebase
git rebase --onto master server client
“Check out the client branch, figure out the patches from the common ancestor
of the client and server branches, and then replay them onto master”
45. Advanced rebase
Now perform a simple fast-forward merge on
master to advance it to C9’
C8’+C9’, originally made on C3, on C6 can break code!
46. Advanced rebase
With rebase the rebased commits become only one,
the commit history is lost
With interactive rebase is possible to edit history,
changing commit messages, squashing, splitting,
deleting and reordering commits
48. Submodules
Use other repositories in your own
e.g. an external lib in ./lib/<libname>
git submodule add [-b <BRANCH>] <REPO> <PATH>
Submodules track a commit or a branch (from 1.8.2)
Submodules informations are stored in .gitmodules
and .git/modules.
.gitmodules must be committed at the beginning and after a
submodule update
49. Subtree merging
Can be used in place of submodules
Is a way to track a branch in an another branch folder
RepositoryFolder/
|_lib/
|_libA/
RepositoryFolder is on
master branch and libA/ is
the lib_a branch
51. Git flow
master contains production code
and is tagged with release
development contains dev code
create a new feature from
development
the feature merges on
development
development becomes a release
a release merges on master
an hotfix is a branch from master
and merges on master and
development
If you write code on master or development, you’re wrong!