This is an old revision of the document!


git-subtree

Sometimes projects can have complex relationships. Perhaps a project develops a utility or libary internally that ends up becoming its own separate project. Perhaps a project uses a particular library, but adds some features to it in their own repository. How are these commits reconciled? One method is the use of the script git-subtree. It is a very handy tool that allows for a repository to be associated with a directory or subtree of a different repository, yet allow for bi-directional transfer of commits. In Arch Linux, git-subtree is in the AUR as git-subtree-git so it can be installed with yaourt with yaourt -S git-subtree-git.

Some time ago, I started working on a project that involved using XBee ZigBee radios from Digi. Unfortunately, the software provided is windows-only and is lacking some very important features, like packet generation and decoding. As a part of the project, I worked on a cross-platform open source re-implementation of a ZigBee terminal that can talk to the XBee radios in packet mode and create and decode packets with a nice interface. The application evolved to the point where it would be nice to split it off into its own repository. So, I installed git-subtree and went to work. Or not. The documentation is really bad if you're not a git expert. After consulting the oracle of google, I discovered a very good blog post on the matter. Please see the link for the details as Jakub does a much better job of explaining it than myself.

Before the split, the repository looked like this:

  • cansat-2012
    • admin
    • AUTHORS
    • docs
    • firmware
    • ground-station
    • MCAD
    • pcb
    • README
    • zigbee-terminal

I wanted to extract the zigbee-terminal tree and all of its commits into its own repository. First, I split the commits into a new branch like so:

git subtree split -P zigbee-terminal -b export

Then I created a new repository and imported the branch:

cd ~/Projects
mkdir zigbee-terminal
cd zigbee-terminal
git init
git fetch ../cansat-2012 export
git checkout -b master FETCH_HEAD

Then I pushed the commits to the new repository:

git remote add github git@github.com:alexforencich/zigbee-terminal.git
git push github master

After that, I went back the old repository and removed the old folder:

git rm -rf zigbee-terminal
git commit -m "Removed zigbee-terminal"

Then I added the remote to the original repository as well:

git remote add zbt git@github.com:alexforencich/zigbee-terminal.git

And finally I added the project back as a subtree:

git subtree add -P zigbee-terminal -m "Added zigbee-terminal as a subproject" zbt/master

Now, to push commits back to the zigbee-terminal repository, I would run:

git subtree split -P zigbee-terminal -b zbtbackport
git push zbt zbtbackport:master

And to pull commits from the zigbee-terminal repository, I would run:

git fetch zbt
git subtree merge -P zigbee-terminal -m "merged changes in zigbee-terminal" zbt/master

Slick. Now that that's taken care of, time to get back to the real engineering…