Subprojects with Git
I’m working on a fairly complex piece of OS X software right now; lots of moving parts.
I also have several elves working on these various parts. The parts are very well isolated from the main project in a plug-in-y sort of way.
The main project has some kinky dependencies that I really don’t want to have to help someone set up and there’s no real reason to. In the final build, it’s all there.
I’m paying them to help with the parts they’re good at, not dick around with installation and configuration and such.
This also means that each independent piece has to have its own completely separate test application/suite that demonstrates the component’s functionality while remaining completely uncoupled from the main app.
All is as it should be.
Except for the version control part.
Each component has its own Git repository, and every developer working on the component can check out the whole component’s repository. No problem.
Except that I’ve also got to be able to check out their work into my build tree to make the whole product.
Git Subprojects to the Rescue
I just picked up The Pragmatic Programmers’ Pragmatic Version Control Using Git. Haven’t had much time to get into it yet but I did jump on the chance to celebrate their 5th anniversary with a 30% off coupon. Congratulations to them, they really do publish some fine books and they deserve all their success.
Chapter 8, “Organizing Your Repository” has a section on using Git’s submodules feature to track external dependencies. These will be familiar to Subversion users as svn:externals.
Creating a Submodule
To illustrate, let’s just create a whole new structure starting with the root of the project.
# cd ~ # mkdir projectRoot # cd projectRoot # git init
Pretty straightforward. Make a subdirectory, initialize the git repository in it.
I’m going to follow the book here since there’s already a public repository out there and it’s not like a million people are going to read this drivel and rush out and knock github over.
# git submodule add \ git://github.com/tswicegood/hocus.git \ hocus
This creates the submodule hocus under projectRoot. What is not particularly clear is that this initializes the submodule to track the current HEAD of the external repository. It stores the revision number of the head in a configuration file called .gitmodules which you’ll add and track with the repository.
Unlike subversion, the submodule is bound to a particular revision within the external repository and will not follow the repository when modifications are made to it
git submodule command will give a hint of that but it’s not that obvious, especially if you’re used to Subversion’s behaviour.
# git submodule -20cc9ddc65b5f3ea3b871480c1e6d8085db48457 hocus
This shows that there’s a single submodule and will show a ‘-‘ sign next to it in the listing since it’s not been initialized.
To get it fired up:
# git submodule init hocus
That will register the hocus submodule.
To actually pull the contents of hocus, at the revision at which you ran
submodule add, into the hocus subdirectory:
# git submodule update hocus
It is possible to change the commit to which the submodule is bound but that’s for another day (or buy the book!).
There’s a really good (and fast!) overview of this process and the intricacies of checking out a new copy of a project with submodules at the Rubaidh Ltd. blog.