Your team has adopted Git, and are happily coding along. But is that all? Can you do more with it? You bet! Join the always-animated Nicola Paolucci to learn advanced techniques for grafting multiple repositories, managing project dependencies with git subtree, splitting commits, and finding the best merge strategy for your staging servers. If you've ever wondered how to collate the histories of different projects, or how to split a sub-directory into it's own project without destroying its history, this session is for you.
3. Today we’ll cover some powerful Git goodies
Interactive stagingPainless sub-projects Collating history
Interactive commits are
an amazing tool at your
disposal as you work on
complex code changes
You can use git
subtree to handle
external libraries in a
clean and efficient way
Joining together history
of your projects using
git replace is useful
when migrating to Git
4. git subtree
Extract project
Alternative to git submodule to handle
external dependencies.
Inject dependency
It allows you to inject an external
project into a sub-folder
Introduced in 1.7.11
It can be also used to extract a
sub-folder as separate project
5. Clean integration pointsStores in regular commitsNo training
When and why is git subtree a great choice
Does not require your
entire team to be
trained in the use of the
command
The command stores
the external
dependency in regular
Git commits. Squashing
the history optionally.
It makes it easy to see
when integrations
happened and makes it
easy to revert them.
6. Syntax to inject a project
Command to inject project
git subtree add
--prefix target-folder
https://bitbucket.org/team/sub.git
master --squash
Folder where to insert code
Repository URL
v1.1
7. Under the hood of git subtree
commit ab54c4e0b75c3107e3e773ab9b39268abddca002
Author: Nicola Paolucci <npaolucci@atlassian.com>
Date: Tue Sep 29 15:27:35 2015 +0200
Squashed ‘src/sub-project‘ content from commit df563ed
git-subtree-dir: src/sub-project
git-subtree-split: df563ed15fa6…6b2e95d3
9. To keep the sub-project up to date
git subtree pull
--prefix target-folder
https://bitbucket.org/team/sub.git
master --squash
Command to pull project
Folder where to insert code
Repository URL
v1.5
10. Under the hood of git subtree
commit ab54c4e0b75c3107e3e773ab9b39268abddca002
Author: Nicola Paolucci <npaolucci@atlassian.com>
Date: Tue Sep 29 15:27:35 2015 +0200
Squashed ‘src/sub-project‘ content from commit df563ed
git-subtree-dir: src/sub-project
git-subtree-split: df563ed15fa6…6b2e95d3
11. Find the symbolic ref matching a hash (sha-1)
sha-1 of last commit pulled
Git plumbing to list all remote refs
Repository URL
git ls-remote https://bitbucket.org/team/sub.git | grep df563ed
df563ed15fa685ce2508bf16b3ca7e176b2e95d3 v1.1
5eaff1232acedeca565er7e1333234dacccebfff v1.5
git ls-remote https://bitbucket.org/team/sub.git | grep <sha-1>
12. Aliases to make your life easier!
[alias]
sba = "!f() { git subtree add --prefix $2 $1 master --squash; }; f"
sbu = "!f() { git subtree pull --prefix $2 $1 master --squash; }; f"
Alias section of your .gitconfig
http://bit.do/git-aliases
13. How to use the aliases
git sba <repo URL> <destination-folder>
git sba https://bitbucket.org/team/sub.git src/sub
14. When everyone in the
team must work on
sub-projects
When you have
constant updates to
your dependencies
When you have many
dependencies
When NOT to use git subtree
17. How to extract a project
Let’s learn how to use subtree split
18. Git subtree to extract a project
Command to split out project
git subtree split
--prefix my/project/
--branch extracted
Folder prefix to extract
where we store it
19. Push to new remote
We can remove the contents of the
folder from the repo
Import extracted branch
Initialise a new repo and import the
extracted branch
Remove from old repo
After we imported the code we can
push it to a new repository
git rm -rf my/project
git init
git pull ../path/ extracted
git remote add origin …
git push origin -u master
21. Fine grained control on
your commits
Knowing this technique
frees you from worrying
about what to do first
Atomic commits make
your changes readable
Why split changes interactively?
22. We modify a single file (README) in 3 parts
# Title
Content of my article
## Subtitle second heading
Some more paragraph content
## Conclusions
23. We modify a single file in 3 different parts
[:~/p/demo] master(+3/-0) ± git diff
@@ -1,11 +1,14 @@
# Title
Content of my article
+Adding a second line to Title.
## Subtitle second heading
Some more paragraph content
+Adding another line to Subtitle 1
## Conclusions
Here are your conclusions
24. To split those changes in separate commits:
git commit --interactive
staged unstaged path
1: unchanged +3/-0 README.md
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
25. Overview of
interactive
staging
revert
The status of the files, whether they
are staged or unstaged.
update
Choose which files to add to the
staging area
status
Undo any action done previously in
this session.
26. Overview of
interactive
staging [2]
add untracked
Check the unstaged or staged
changes in the workspace.
patch
Add parts of a file to the staging area.
This allows you to split commits.
diff
Add new untracked files to the
repository.
27. I finally hit “p” for patch, select the file and ENTER:
What now> p
staged unstaged path
1: unchanged +3/-0 README.md
Patch update>> 1
staged unstaged path
* 1: unchanged +3/-0 README.md
Patch update>>
28. I finally hit “p” for patch, select the file and ENTER:
@@ -1,11 +1,14 @@
# Title
Content of my article
+Adding a second line to Title.
## Subtitle second heading
Some more paragraph content
+Adding another line to Subtitle 1
## Conclusions
Here are your conclusions
+Adding to the Conclusions.
Stage this
hunk?!?!
29.
30. A hunk is just a piece of text in a larger file.
Diff and patch commands tend to understand
changes by clustering them in blocks of
continuous text.
“
”
31.
32. If the default hunk size is too big, you can split it:
Stage this hunk [y,n,q,a,d,/,s,e,?]? s
Split into 3 hunks.
@@ -1,7 +1,8 @@
# Title
Content of my article
+Adding a second line to Title.
## Subtitle second heading
Some more paragraph content
33. Let’s stage this hunk, or add it to the staging area:
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y
@@ -4,8 +5,9 @@
## Subtitle second heading
Some more paragraph content
+Adding another line to Subtitle 1
## Conclusions
Here are your conclusions
Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]?
35. The result is a neat new commit and the rest left:
14a0be4 [4 minutes ago] (HEAD -> master) Add content to Title [Nick]
git diff
diff --git i/README.md w/README.md
index fc26295..0ef85c4 100644
--- i/README.md
+++ w/README.md
@@ -6,7 +6,9 @@ Adding a second line to Title.
## Subtitle second heading
Some more paragraph content
+Adding another line to Subtitle 1
## Conclusions
36. When you need help just press “?”
Stage this hunk [y,n,q,a,d,/,s,e,?]? ?
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
38. Cross VCS mergesUnify two reposFast migration from svn
Why collate history?
Migrate immediately
from Subversion, attach
the earlier history after
the migration.
You have two
repositories that should
actually be only one.
You need to perform
Subversion merges in a
Git branch
39. One relevant
example:
Linux kernel
Today use git replace
The entire history of the Linux kernel
is split over three different repos.
Originally in Grafts
Which are local pair of ids connecting
a commit id (SHA-1) to the next
Linux kernel is split
Available in the stock git distribution
since version 1.6.5
40. git replace is capable to replace any object
with any other object.
It tracks these swaps via refs which you can
push and pull between repositories.
“
”
41. git replace in practice
shallow
first
last
legacy
shallow clone with cut history
git replace first last
42. First commit of restarted repo
git checkout -b shallow origin/shallow
git log --max-parents=0 master
git tag 56eacf first -m”Tag… commit”
shallow
first
43. Last commit of legacy repo
git checkout -b legacy origin/legacy
git rev-parse --verify legacy
git tag 84abb last -m”Tag… commit”
last
legacy
44. git replace in practice
shallow
first
last
legacy
shallow clone with cut history
git replace first last