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.
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
.)
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:
Clone the submodule if needed, using the directives in the .gitmodules
file in the superproject.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With