5

I'm trying to setup a generic .gitmodules file to be used as a template for a certain static number of submodules new projects always require. Then use the technique shown in Restore git submodules from .gitmodules to init the submodules in one go:

#!/bin/sh

#set -e

git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
    while read path_key path
    do
        url_key=$(echo $path_key | sed 's/\.path/.url/')
        url=$(git config -f .gitmodules --get "$url_key")
        branch_key=$(echo $path_key | sed 's/\.path/.branch/')
        branch=$(git config -f .gitmodules --get "$branch_key")
        if [ ! -d "$path" ]; then
            echo URL - $url, Path - $path, Branch - $branch
            if [ -n "$branch" ]; then
                branch="-b $branch"
            fi
            git submodule add --force $branch $url $path
        fi
    done

However, it seems impossible to specify a tag (as opposed to a branch) in the .gitmodules files:

[submodule "externals/asio"]
    path = externals/asio
    url = https://github.com/chriskohlhoff/asio.git
    branch = asio-1-11-0

which results in:

fatal: Cannot update paths and switch to branch 'asio-1-11-0' at the same time.
Did you intend to checkout 'origin/asio-1-11-0' which can not be resolved as commit?
Unable to checkout submodule 'externals/asio'

It is perfectly possible to do this though:

cd externals/asio
git co asio-1-11-0

Any ideas on how to specify a specific tag ?

No answers on Stackoverflow I have found, even suggested duplicates, show if it is possible to specify a tag in .gitmodules. Also, the questions I've found relate to using git submodule, not using a .gitmodules file to initialize a repo from scratch.

Robert
  • 2,090
  • 28
  • 43
  • 2
    Possible duplicate of [Git submodules: Specify a branch/tag](https://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag) – GolezTrol Mar 26 '18 at 11:32
  • 1
    @GolezTrol Unfortunately I find no answer to this there... – Robert Mar 26 '18 at 11:34
  • 3
    The answer seems to be it is not possible. So I opted to reverting to checkout of the tag if the submodule update fails. That seems to work fine. – Robert Mar 26 '18 at 11:45

1 Answers1

0

What I think is the answer you need (logically this goes after the next section)

I suppose the issue is that the current index does not yet have the submodule in it. What you want to do is to clone the submodule into place first (using any git clone command that you find appropriate), check out the desired commit (by whatever means is appropriate—possibly that same git clone command), and only then use git submodule add:

If <path> exists and is already a valid Git repository, then it is staged for commit without cloning.

In other words, this will create the entry in the superproject's .gitmodules file, and then add the currently checked out commit hash ID of the submodule into the superproject's index. You don't add with a branch here, you just add—which this uses the checked-out commit like a tag.

You may want to run git submodule absorbgitdirs at the end of all of this, so that all submodule .git repositories migrate into the superproject's .git directory. (There is no requirement for this, and if your Git is older, it won't have absorbgitdirs.)

Setup: or, Read this first if the above makes no sense

Submodule checkouts are normally detached. That is, you have a "detached HEAD" in the Git repository that is the submodule: the contents of its HEAD file are the 41 bytes making up a hash ID.

When you first run git submodule update --checkout, the default action is to:

  1. Clone the submodule if needed, using the directives in the .gitmodules file in the superproject.

  2. Check out the specific commit identified by the superproject's gitlink. This is a hash ID stored in the index for the work-tree for the superproject.

    (Annoyingly, it's slightly difficult to see the index entry, and hence the corresponding hash ID. You can use git ls-files --stage <path> or git rev-parse :0:<path> to see it. The nice front-end interface, git show, cannot show subproject commit hashes! This seems like a bug.)

This happens regardless of whether there is a branch setting. With git submodule update --rebase or git submodule update --merge, the branch setting begins to matter.

You can also set submodule.name.update to checkout, rebase, or merge, in which case git submodule update --init obeys whatever you set here. Then the branch setting will once again matter. But if you don't set those, git submodule update --init defaults to git submodule update --checkout.

Checking out a specific commit, by its hash ID, results in a detached HEAD.

Checking out a tag by name results in a detached HEAD as well—specifically, the hash ID to which the tag name resolves.

Tag names are never supposed to change. Assume this is true. That means that if you record, as a raw hash ID in the gitlink, the hash ID to which the tag name resolves, the git submodule update action will result in checking out the same commit hash ID, with the same detached HEAD, as checking out the tag. Hence there's no need to set a tag name here, so don't use the -b <branch> option at all.

Community
  • 1
  • 1
torek
  • 330,127
  • 43
  • 437
  • 552
  • Thanks, I ended up doing it this way: Having a "template" modules file (having both branch and tag specified), then parsing that file and setting up the submodule structure, doing checkouts on the added submodules as appropriate. It is about as neat as it can get. – Robert Mar 27 '18 at 07:16
  • The answer to OP's question is: *It is not possible to specify the tag in .gitmodules*. – foki Oct 14 '20 at 21:42
  • That you can't specify the tag in `.gitmodules`: it doesn't matter, because the commit specifies the hash ID, which is just as good. – torek Oct 15 '20 at 02:50