Introducing Git Submodules in Tower
Table of Contents
Submodules help you to keep external libraries cleanly separated from your own code. Although generally a great feature, submodules can be quite difficult to work with from the command line. Unfortunately, this causes a lot of people to avoid them and not use them at all. With Tower, we would like to change this.
How Git Submodules Work
Git submodules are just other Git repositories that are cloned somewhere into your project’s working tree. Each submodule is registered in a special configuration file called .gitmodules in your project’s root directory, containing the remote repository URL and the path where it resides in your work tree. This makes your repository the super repository for all submodules.
Git looks at the currently checked out revision of your submodule repository and records this information – the revision pointer – in its tree under the submodule path which can then be committed just as any other change.
With this information, other contributors can re-create each submodule’s state for each revision. Each contributor has to initially clone each submodule, though, as only the revision for an external repository is committed and not the repository itself.
If you want to use a different version of the library in your project, say 1.1 instead of 1.0, you simply check out the revision you want in the submodule and commit the modified revision pointer of the submodule.
When working with submodules, you will encounter the term “update submodule”. This operation will try to check out the revision that is currently recorded in the Git index. It will also fetch the submodule repository if the revision is not known (e.g. after a merge).
The Trouble with Submodules
Managing submodules is cumbersome. One of the drawbacks with Git submodules is that Git does not automatically update the revision pointer of a submodule in your working tree if the information about it changes (like it does for files), leaving your repository in an inconsistent state: the exact code of a submodule at a specific revision may be critical to the super repository.
For example, when you receive a change to the revision pointer of a submodule (e.g. through a merge or rebase, checkout or reset), Git will leave your submodule’s pointer where it was before the operation, creating a “Modified” status for it, as your current revision pointer is still the old one. You need to manually update the submodule every time after such operations to have your revision pointer be moved to the correct commit.
In such a case, it can be very hard to figure out what revision a submodule is supposed to point to and if you are not familiar with Git submodules there is also a good chance you may accidentally revert the change.
Also, when you switch to a branch where a particular submodule does not exist, Git will leave the submodule directory in your working tree as an untracked folder. Again, this creates an opportunity for users to mess things up.
There may be reasons for Git not to keep submodules in sync, but this is where we wanted Tower to mostly improve on the behavior of submodules.
Managing Submodules in Tower
As soon as you start using them, Submodules can become an essential part of your code management. Tower displays all submodules in its sidebar, giving you a constant overview and quick access. You can add new submodules, rename or delete existing ones by using a submodule’s contextual menu or the menu at the bottom of the sidebar. You can also issue fetches and updates from the contextual menu.
Additionally, you can manage your submodules in the repository settings, where you can view detailed information about the submodule and edit various additional settings and behaviors.
Fetching Submodules
All submodules are automatically fetched when you invoke a fetch on the super repository. This is a Git default and there are config settings to change this behavior. For example, you can exclude certain submodules from being automatically fetched.
Tower will honor these settings and provide options for them in the new repository preferences pane (see “Managing Submodules” above).
Moving the Revision Pointer of a Submodule
Moving the revision pointer of a submodule is as easy as checking out a specific branch, tag or revision in the submodule. However, this involves quite a few steps on the command line: go into the submodule directory, look for and check out the revision, go back to the super repository to stage the changed pointer…
In Tower you can simply right-click on a submodule, either in the sidebar or in your Status view, and choose from all branches and tags to checkout.
If you need a specific revision, going with “Other Revision…” will let you choose any revision in the submodule.
Receiving Changes for a Submodule
When someone else has moved the revision pointer for a submodule and you merge in this change, your revision pointer will not automatically be updated by Git (see “The Trouble with Submodules” above).
Tower will notify you if a submodule’s pointer has been changed after an operation and will ask you to update the revision pointer accordingly. You can also set “Always update submodule” for each submodule to have its revision pointer moved automatically for you without being notified. This makes working with submodules a lot easier – especially in the (very likely) case that you treat submodules as read-only libraries in your project where you always want to update the revision pointer.
Switching Branches with Submodules
Automatic updating also works when switching branches: if the revision pointer of any submodule changes, Tower will offer to update it for you.
By default, Tower will also remove submodules from the working tree for you that do not exist on the current branch. By default, Git just leaves them as untracked folders in your working tree – a very irritating side effect. However, this is only supported for submodules that have been created with Git version 1.7.8 or greater, as from this version on Git introduced an important improvement to submodules that does not require you to fully re-clone a submodule when you fully delete it from the working tree.
Working with Submodule Repositories
If your submodule is a library that should be developed along with your super project, you may want to make changes to the submodule’s repository directly. As it is just another Git repository, you can open it in Tower, make any changes to it you would like to, and then switch back to your super repository.
When you open a submodule repository in Tower from within your super repository (e.g. by simply double-clicking it in the sidebar), it will not be added permanently to your bookmarks.
There is no functionality to actually modify the submodule repository from within the super repository as it makes more sense to view them separately. So, if you need to make modifications to the submodule’s sources, you open it and gain full control over the repository.
If you would like to give Tower's submodule support a try, you can download the latest version from our website.