Changing URLs of Git submodules

April 23rd 2021 Git

I prefer using Git over SSH which makes me a minority in most teams I work with. Fortunately, the way I connect to the repository usually doesn't matter, as all Git hosting services support both HTTPS and SSH. Git repositories with submodules are a different story, though.

Git submodules are defined in the .gitmodules file in the repository. Each submodule definition consists of a path inside the repository where the files from the submodule are placed and a URL of its repository, as in the following example:

[submodule "modules/mySubmodule"]
    path = modules/mySubmodule
    url = https://github.com/damirarh/mySubmodule.git

The issue with the above example for an SSH user is the absolute HTTPS path. Git can handle that but requires you to authenticate over HTTPS, effectively using two different authentication methods for a single repository.

For an SSH user, a correct configuration would be the following:

[submodule "modules/mySubmodule"]
    path = modules/mySubmodule
    url = git@github.com:damirarh/mySubmodule.git

Of course, that would cause problems for HTTPS users.

The solution is to use a relative URL instead:

[submodule "modules/mySubmodule"]
    path = modules/mySubmodule
    url = ../mySubmodule.git

This works for both HTTPS and SSH users because it uses the root repository URL as base onto which the relative path is applied. The ../mySubmodule.git example would work as long as the parent repository is in the same GitHub organization, e.g. https://github.com/damirarh/myProject.git or git@github.com:damirarh/myProject.git. Usually all repositories in a project are at least hosted in the same service, so this technique can be used.

To fix the issue for me (and other SSH users) in repositories which already contain submodules with HTTPS URLs, I have to change the URL. The easiest way I found to do that is as follows:

  1. Modify the URL value in the .gitmodules file to make it relative. This file gets committed to Git.

  2. Force submodules to resynchronize with the modified file using the following command in the folder with the modified .gitmodules file (not necessarily the repository root if its submodules contain other nested submodules):

    git submodule sync
    
  3. Update all modules from the now correct remote URL using the following command in the repository root (because it is called recursively on all submodules, even nested ones):

    git submodule update --init --recursive --remote
    

I would recommend using relative submodule URLs whenever possible. They don't force all developers to use HTTPS or SSH leaving them the freedom of choice. Additionally, they will make it easier to migrate your repositories to a different organization or Git host as you won't need to change the submodule configuration for that. You could even have multiple remotes at the same time, all working as expected.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Copyright
Creative Commons License