Large software projects often build their release from many repositories. It it tempting to set up a super-repository referencing all your shipping code through git submodules. Since each commit of your superproject contains an unambiguous reference to a particular commit of every submodule, you can tag your superproject to define a release or nightly build.
All it takes is a single command to retrieve all the source code for a particular release.
1 2 |
|
It is very useful for archival purposes or code escrow. In this post, we explore how to set that up.
Setting up submodules
There used to be no straightforward way to update your submodules. You would have to extract the SHA checksum of the desired commit of every submodule, and point your superproject to each one of them. git submodule update
would check out the submodule code. Add branching logic to the mix, and you ended up with fairly complex code.
Since git 1.8.2, it has become much easier. When defining a submodule, you can now specify which branch it is supposed to track.
Say you are building your superproject from components A and B. Your development builds are built from branch master
of component A and branch dev
of component B. The following commands will set up the superproject:
1 2 3 |
|
Git will store the relationship with the sumbodules in the .gitmodule file.
1 2 3 4 5 6 7 8 9 |
|
Then all it takes to fetch the last commits from the components is:
1
|
|
You can issue git submodule status
to verify that the commit SHA1 hashes match the latest commits of your component repositories:
1 2 3 |
|
Then your automated build system may just automatically tag nightlies for all your components every night:
1 2 3 4 5 |
|
Of course, this does not dispense you from tagging your component repositories individually.
Adding a branch
If your release branch is named “3.11” on both components, you may create a branch 3.11 on your superproject, delete the submodules (with the git submodule deinit
command available since release 1.8.3 of git), then recreate them again giving the correct --branch
option.
Or you may just edit your .gitmodules file and check it in to the repo.
1 2 3 4 5 6 7 8 9 |
|
Then, when on branch 3.11 of your superproject, git submodule update --remote
will fetch the latest release branch content from all submodules.
1 2 3 4 5 6 |
|
You may now tag and commit again:
1 2 |
|
You have now set a multi-branch superproject tracking all branches of all your components. Isn’t it nice ?
Thus said, a word of warning is necessary. Git submodules are recently receiving a lot of improvements, but they are no panacea. If your component repositories are very dependent on one another, and developers are likely to commit to several repositories, then you may be better off having one big repository. This model works well when your different components are worked on by different teams, and you are looking for an easy way to check out or tag all the code.
All the code used in this post is also available as a gist.