'git submodule foreach checkout supermodule branch

Consider a git repository Foo/, which has submodules bar1/ and bar2/.

Each of these has the same branches: 1 & 2.

I enter the supermodule, and I want to update the supermodule to contain the most recent commits from bar1 and bar2's origin. I've already init'd and updated the supermodule, so there's working trees in bar1 and bar2, but they are in a detached state. I can do the following:

cd foo;
git checkout 1
git submodule foreach git checkout 1
git pull

Now, what bugs me is repeating the branch identifier. Can I do something like "git submodule foreach git checkout $CURRENT_BRANCH_ID"? Is there a better alternative?



Solution 1:[1]

A submodule is always by default in detached HEAD mode.

You can make each submodule follow a branch.
See "How to make an existing submodule track a branch".

cd /path/to/your/parent/repo/Foo
git config -f .gitmodules submodule.bar1.branch branch1
git config -f .gitmodules submodule.bar2.branch branch2

Then all you need to do is:

git submodule update --remote

That will update each submodule to the latest of their respective upstream branch (fetch + checkout).

Solution 2:[2]

The code

Here is the script that I mentioned in my comment:

function checkout_branch_not_refs() {
  for line in $(git config --list | awk -F'[.=]' '/submodule.*branch/ {print $2","$4}'); do
    IFS=',' read -r submodule branch <<< "$line"
    if ! [ -d "$submodule" ]; then
      echo "Cannot switch branch to '$branch' for submodule '$submodule'"
      continue
    fi
    pushd "$submodule" && git switch "$branch" && popd
  done
}

to be used like

checkout_branch_not_refs
git submodule foreach git pull

Explanation of differences

Original answer

git submodule update --remote

does exactly what you ask of it. It updates the submodule by looking at the remote. The remote is configured in .gitmodules. The update --remote command looks for the submodule.<submodule_name>.branch key & checks out that commit directly.

ASCII art:

HEAD ------------\
                  \
                   V
remote branch --> Commit

My answer

checkout_branch_not_refs

This command will checkout the branch itself. HEAD -> Branch -> commit.

ASCII art:

HEAD --> local branch --> Commit

It is a prerequisite to this answer to understand the difference between a local branch and a remote branch. That's the answer to why we have to run git pull in the submodule after.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Ari Sweedler