Using git submodules with GitHub repositories


I’ve been pretty lazy with git so far, and only used it through the GitHub for Windows GUI. But, I wanted to use submodules in a couple of my repositories and GitHub for Windows doesn’t support that (yet?) so it seems it was time I got my hands dirty…

So, what are git submodules?

With git submodules a repository can contain a checkout of another repository as a subdirectory. (The containing repository is often referred to as the “superproject”.)

The superproject stores the submodule repository location and a commit ID. This means you can, for example, keep some common code in a separate repository and use a specific, known-working version of this code in other projects.

If the repository containing the common code gets an update, any superprojects using it as a submodule will not get updated until you specifically pull the changes into them. Also, you can make changes to the common code from within a superproject and push those changes to the submodule’s repository to make them available to other projects. I’ll go through how to deal with these cases later in the post, but first…

Creating a submodule

Suppose submodule-test is a GitHub repository containing the common code and superproject-test is another GitHub repository that needs to use that common code as a submodule.

To add the submodule to the superproject use the git submodule add command, specifying the remote url of the submodule repository and the subdirectory where the submodule files will be added.


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git submodule add https://github.com/ianreah/submodule-test.git common-code
Cloning into 'common-code'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (6/6), done.

Note: It’s a common scenario for the submodule code to have previously existed within the superproject before it was pulled out to be shared between projects. In this situation you may get an error like common-code already exists in the index. To fix this, first execute git rm -r common-code (obviously where common-code is the name of the subdirectory where you want to add the submodule files) and then try the git submodule add command again.

If you look at the files in the superproject now you should see the subdirectory containing the submodule repository…

submodule directory structure

Notice also the new file .gitmodules. This is a configuration file that stores the mapping between the submodule’s remote repository url and the local subdirectory you’ve pulled it into…

[submodule "common-code"]
	path = common-code
	url = https://github.com/ianreah/submodule-test.git

Now commit & push the changes.


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git commit -m "Added common-code as a submodule"
[master 67225a2] Added common-code as a submodule
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 common-code
Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git push
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 447 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/ianreah/superproject-test.git
   850ec91..67225a2  master -> master

If you look at the superproject repository in GitHub you’ll see that it doesn’t actually know about any of the files in the submodule. Instead it just contains a link to a specific commit of the submodule code.

submodule link in a github repository

Pulling submodule updates into the superproject

It’s a great advantage of submodules that the submodule code within a superproject is tied to a specific commit, but at some point you’re going to want to pull in any changes to the submodule code so you get the latest & greatest version in your superproject.

To do this just move into your submodule subdirectory and pull…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ cd common-code

Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test/common-code (master)
$ git pull origin master
remote: Counting objects: 5, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 3 (delta 0) Unpacking objects: 100% (3/3), done. From https://github.com/ianreah/submodule-test * branch master -> FETCH_HEAD Updating 61885e4..b0d106a Fast-forward common code | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)

Notice that the superproject repository recognises the modification but it is not yet ‘staged for commit’…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test/common-code (master)
$ cd ..

Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git status
# On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: common-code (new commits) # no changes added to commit (use "git add" and/or "git commit -a")

To add the change to the staging area and commit it at the same time, use the -a parameter with the git commit command…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git commit -am "Pulling latest into submodule"
[master 290cb32] Pulling latest into submodule
 1 file changed, 1 insertion(+), 1 deletion(-)

Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 257 bytes, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://github.com/ianreah/superproject-test.git
   67225a2..290cb32  master -> master

And, once the changes have been pushed you will see that the GitHub superproject repository now links to the updated version of the submodule…

submodule updated in the github repository

Updating the submodule code from within the superproject

If you make some changes to the common code while working in the superproject you should commit and push the changes from the submodule subdirectory first, (remembering the -a parameter with the commit command)…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ cd common-code

Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test/common-code (master)
$ git commit -am "Updating submodule from within superproject"
[master b4bf0d7] Updating submodule from within superproject 1 file changed, 2 insertions(+), 1 deletion(-) Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test/common-code (master) $ git push
Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 361 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/ianreah/submodule-test.git b0d106a..b4bf0d7 master -> master

And then move back up to the superproject main directory and commit the change to update the submodule link in the superproject…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test/common-code (master)
$ cd ..

Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master)
$ git commit -am "Updating submodule"
[master f853528] Updating submodule 1 file changed, 1 insertion(+), 1 deletion(-) Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-test (master) $ git push
Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 249 bytes, done. Total 2 (delta 1), reused 0 (delta 0) To https://github.com/ianreah/superproject-test.git 290cb32..f853528 master -> master

Working with cloned repositories containing submodules

If you’re working with GitHub for Windows then you don’t need to do anything special when cloning a repository that contains submodules. Using the “Clone in Windows” button will pull down the superproject files and the appropriate versions of the submodule files in one go.

However, if you clone the repository with the git clone command you’ll notice that the submodule directory will be there but it will be empty. To pull down the submodule files you need the following two commands after cloning the repository…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone (master)
$ git submodule init
Submodule 'common-code' (https://github.com/ianreah/submodule-test.git) registered for path 'common-code' Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone (master) $ git submodule update
Cloning into 'common-code'... remote: Counting objects: 12, done. remote: Compressing objects: 100% (10/10), done. remote: Total 12 (delta 1), reused 8 (delta 0) Unpacking objects: 100% (12/12), done. Submodule path 'common-code': checked out 'b4bf0d799697a111c79d4b2420d74784240bd570'

One important thing to be aware of is that when you clone a repository containing a submodule you’ll find that, within the submodule, you are not working on a branch. Or, in git speak, because it has checked out a specific commit of the submodule code, which may not necessarily be a branch tip, you have a detached head!


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone (master)
$ cd common-code
Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone/common-code ((b4bf0d7...)) $ git branch
* (no branch) master

This means that if you want to make any changes to the submodule code from within the superproject (as described earlier) you need to either switch to an existing branch…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone/common-code ((b4bf0d7...))
$ git checkout master
Switched to branch 'master' Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone/common-code (master) $ git branch
* master

Or, create a new branch…


Ian Reah@IANREAH-PC ~/Dropbox/GitHub/superproject-clone/common-code ((b4bf0d7...))
$ git checkout -b new-branch
Switched to a new branch 'new-branch'

And finally…

If you’re going to be working with submodules a lot, be sure to read up on the pitfalls! Also, there are details of some of the more finer points of working with submodules in the user’s manual and in the Pro Git book.


A Tale of Two Coverflows


I recently set myself the task of developing two versions of a simple coverflow control - one in Silverlight and one in JavaScript. The completion of the task provoked the following tweet…

As a .NET developer, how come the Silverlight version seemed to take WAY more effort than the JavaScript version?

…which surprised me because I have much more experience developing .NET applications than JavaScript.

In hindsight the tweet was probably a little unfair. The JavaScript version only works in WebKit browsers and I suspect it’ll require quite a lot more effort in order to improve its browser coverage, whereas the Silverlight version should already work, as it is, in any browser provided there’s an appropriate plug in available.

It was still interesting to go back over and compare the two implementations, so I’ve written a CodeProject article which gives a high level overview of the two implementations and gives some thoughts as to what might have contributed to the above reaction…

The Code Project Article

“For an exercise of this nature, the static type checks and better tooling support available when developing the Silverlight version didn’t seem to have as big an impact as they might on a larger more complex project. However, the streamlined feedback & debugging experience of the JavaScript development did make a big difference.

“Being able to change some JavaScript and simply refresh the browser to see the effect of the changes is a big advantage. Also, using the in-browser debugging tools to examine the state of elements and experiment with different values for their attributes while the UI updates ‘on the fly’ helped to quickly understand & solve many problems.”

Head over to Code Project if you want to read the full article. Also, you can see the two coverflows in action here:


A Kiln Glaze for Keeping Track of Your Code Reviews


Kiln - Mercurial Version Control and Code Review Software from Fog Creek Software

Our team uses Fog Creek’s Kiln for our source control and a while ago we started making use of its Code Review features. We decided that we’d start out by reviewing everything that gets pushed to the kiln repository. We could pull back on this in the future if reviewing everything became too much and instead leave it to the developer pushing the code to decide if a review is required.

I think it’s working really well and I don’t think we should pull back on what we’re reviewing. The reviews help to spread the knowledge of the code that’s being worked on and they’re helping to keep our code quality high.

Effortless Reviews, Inline Commenting

If it really is something that doesn’t need a review then it shouldn’t take up a lot of time anyway. If we start choosing what to review then there’s a danger we’d end up reviewing less and less of our code and eventually get out of the habit of reviewing all together.

We don’t require a new review for each commit. A series of commits can be combined into a single review - just as long as each commit is part of a review somewhere. Even so, on our team of 9 developers, there are quite a lot of code reviews flying around, and I’ve found it quite frustrating trying to keep track of which reviews require my attention.

What I really want to see is a list containing:

  1. The reviews I need to do (where I am a reviewer and I have not yet approved/rejected)
  2. Reviews of my code that have been rejected (so I can follow up and fix the code as necessary).

The kiln reviews dashboard just doesn’t provide this at the minute. After taking some pointers from Fog Creek’s customer support I came up with the following kiln glaze to help highlight the reviews requiring your attention.

Note: It is definitely a rough, temporary solution. I didn’t want to spend a lot of time on it in case Fog Creek come up with a better, more permanent solution themselves. It hasn’t had a lot of testing and comes with no guarantees, but feel free to try it if you think it will help you also.

name:        Show Reviews To Do
description: With &showTodos=true on the url, lists only reviews that require
             your attention (i.e., undecided by you if viewing reviews with
             you as reviewer, or rejected reviews if viewing reviews of your
             code).
author:      Ian Reah
version:     1.0.0.0

js:

$(document).ready(function() {
  function querystring(key) {
    var regex=new RegExp('(?:\\?|&)'+key+'=(.*?)(?=&|$)','gi');
    var result=[], match;
    while ((match=regex.exec(document.location.search)) != null) {
      result.push(match[1]);
    }
    return result;
  }
  
  function hideReviewsExcept(dontHide) {
    allReviewLists = $('.reviewsList');
    reviewList = allReviewLists[allReviewLists.length - 1];
    reviews = reviewList.children;
  
    for (i=0; i < reviews.length; i++) {
      value = reviews[i].childNodes[5].innerText.toLowerCase();
		  
      if (value.indexOf(dontHide) == -1) 
      {
        reviews[i].hidden = true;
      }
    }
  }
  
  if(querystring('showTodos') == 'true') {
    if(querystring('ixPersonReviewer').length > 0) {
      hideReviewsExcept('undecided by you');
    } else if(querystring('ixPersonAuthor').length > 0) {
      hideReviewsExcept('rejected');
    }
  }
});

It works by looking for a parameter on the url showTodos=true. If this parameter is present then it will hide all reviews, other than those that require your attention.

The way it determines which reviews to hide depends on the type of reviews you are listing. If you’re listing reviews of your code then it will only show reviews that have been rejected - so you can easily see which reviews you need to follow up on and fix. If you’re listing reviews that have you as a reviewer then it will only show reviews marked as “undecided by you” - so you see which reviews you still need to do.

The best way I’ve found to use it is to save two bookmarks; one listing reviews of your code, and one listing code you’re reviewing - each with the showTodos parameter on and specifying a large number of days (to make sure old reviews don’t get missed)…

  • https://example.kilnhg.com/Reviews?ixPersonReviewer=insert-your-user-number-here&showTodos=true&activeInDays=365
  • https://example.kilnhg.com/Reviews?ixPersonAuthor=insert-your-user-number-here&showTodos=true&activeInDays=365

You still have two separate lists, rather than the single ‘These Reviews Require Your Attention’ list I was hoping for, but it’s definitely an improvement.


I work as a Software Developer at Nonlinear Dynamics Limited, a developer of proteomics and metabolomics software.

My day job mainly involves developing Windows desktop applications with C# .NET.

My hobby/spare-time development tends to focus on playing around with some different technologies (which, at the minute seems to be web application development with JavaScript).

It’s this hobby/spare-time development that you’re most likely to read about here.

Ian Reah

Full blog »