Git Submodules like svn:externals

One critical difference between Git submodules and Subversion "externals" is the concept that submodules are locked to a particular commit. Normally this is a "good thing" because blindly attaching yourself to a particular branch in Subversion can have interesting an unexpected consequences when the branch changes out from underneath you. Subversion provides a way to "lock" to a particular revision via the "-r" parameter in the svn:externals declaration, e.g."name –r commit_url".

One of the great benefits and drawbacks about Git is that it doesn't protect you from the itself. It's very much a leaky abstraction. Because of this, you have the power you can do pretty much anything you want to a Git repository—effectively carte blanche. One area in which this does not apply is submodules. Submodules are locked to exactly one revision and that's the way it is as far as Git is concerned.

There are three ways to update submodules to a new commit.

  1. By hand—via git pull within the submodule and then a commit on the supermodule.
  2. With a script to be invoked by hand or automatically by a build server which performs the operation of # 1 but in a consistent fashion.
  3. A post-checkout script automatically invoked by Git.

We have opted for option # 2, at least for the time being.

A Better Way

Unfortunately as of this writing, there doesn't appear to be a better way to solve this issue. This is why I propose the "—track" option for submodules.

Git branches can be tracked by using the "–track" option when creating a branch. This same approach would make sense for a submodule as well. Why not, when creating a submodule have something like this:

git submodule add --track BRANCH_TO_TRACK>

The idea would be that the submodule would "track" the current head of a particular repository branch. In this way, the default behavior is preserved and those that *want* enough rope to hang themselves if they aren't careful may do so at their own risk.

The .gitmodules file and .git/config file would be modified to have the following attribute:

[submodule "local/path"]

path = local/path

url = remote_url.git

track = remote_branch_name

In our current build infrastructure, we currently modify the .gitmodules file with the "track" option and have a script check for the track option so that we can follow a particular branch when the script is invoked.