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.
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…