Having Fun With Git Subtree

Posted by on March 1, 2011 in Development, General | 2 comments

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.

You need to have the git-subtree module installed. This is done by cloning the repository and running the install.sh script.

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:

Matthew usually does a “git fetch” + “git rebase” to keep branches he has tracking the remote repo up to date. “git pull” is the equivalent to “git fetch” + “git merge”, and, while it works, doesn’t keep a linear history of commits for that branch. If you started with “git pull”, however, you should stick to it. Otherwise, you will get issues.

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.

Who is Matthew??

Matthew Weier O’Phinney is project lead for Zend Framework. He is a vocal advocate for best practices and standards in PHP development, including version control, design patterns, and unit testing. While blogging is his normal communication medium, Matthew is also a regular speaker at PHP conferences.

2 Comments

  1. “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

  2. I really like this. I will use subtree merge for vendor libraries like ZF2 while using submodules for application modules.

Trackbacks/Pingbacks

  1. Git Subtree Merging Guide | Zend Framework University - [...] what I gave him worked for him, as he then requested if he could post my guide — which …
Fork me on GitHub