Having Fun With Git Subtree
At Sugar we are moving our our internal repositories off of SVN to Git, which is a good thing. Most of the repositories were strait forward moving since we didn’t do anything fancy but there was one that used svn:externals to deep link into one of our other repositories. After trying multiple things to get submodules to try and do what I wanted it just would work. I was getting really frustrated by this and i found an article on github.com about subtree merges. After reading it and trying it out it looked like it was going to be what I needed. But then when I tried to update a subtree that links into the subpath, nothing happened. I wasn’t sure what I did wrong but nothing would work. So I turned to twitter:
http://twitter.com/sidhighwind/status/40913654266347520
and shortly after I posted that Matthew Weier O’Phinney answered me
http://twitter.com/weierophinney/status/40917980527329280
This put me on the right track but I still couldn’t find anything so I pinged Matthew back and he offered to help me via email. Below are the steps which he gave me that worked.
Here’s my quick “subtree-merge” tutorial:
First, let’s assume some project structure like this:
library/
MyStuff/
...
tests/
MyStuff/
...
and we want to add in Zend\Log from the ZF2 repository. And only Zend\Log.
First, add a new remote:
Now check it out into a new branch:
From here, start a subtree merge. We’re going to check it out into its own branch, called “subtrees/zend_log”:
If we checkout the “subtrees/zend_log” branch, I’ll see the following:
Now, let’s fetch that into our master branch:
and you’ll see in ‘git log’ that you have a new merge:
Merge commit ‘…some ref…’ as ‘library/Zend/Log’
NOW we get to the problem of keeping it updated.
So, as a reminder, we first added a remote, “zf2″, pointing to the ZF2 repository. Second, we created several branches:
projects/zf2 — mirroring the ZF2 master branch
subtrees/zend_log — our subtree
To update, we update our ZF2 master branch:
Next, we run the subtree split again, exactly as we did before:
Once that’s done, we merge in the changes to our master (or other
branch); this is just like the “subtree add” command, but using “merge”
as the action instead:
Note we’re using the “–squash” option in the “add” and “merge” commands — this is because we typically don’t want the fully commit history of projects whose subtrees we’re tracking — just the result of those changes.
I hope this helps someone as much as it helped me. If you want to know more information on Matthew check out the box below.
“Matthew usually does a “git fetch” + “git rebase” to keep branches he has tracking the remote repo up to date.”
You can do that using git pull –rebase
I really like this. I will use subtree merge for vendor libraries like ZF2 while using submodules for application modules.