3

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?

Spacemoose
  • 3,856
  • 1
  • 27
  • 48

2 Answers2

5

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).

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • From what version of git is this available? It doesn't seem to work in 1.8.4 -- or I'm doing something wrong. – Spacemoose Nov 25 '15 at 09:29
  • This will have `HEAD` -> `ref that remote/branch1 points to`. If you want `HEAD` -> `local tracking branch branch1` -> `ref that remote/branch1 points to`, then you'll have to do something else. I can't think of how to do this other than a bash script. – Ari Sweedler Apr 25 '22 at 20:18
  • 1
    @AriSweedler I agree. That reminds me of the new (Git 2.36, Apr. 2022) [`git branch --recurse-submodules`](https://stackoverflow.com/a/71195953/6309). – VonC Apr 25 '22 at 20:27
0

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.

Ari Sweedler
  • 807
  • 7
  • 25