Chev Chev - 1 month ago 7
Git Question

What is the difference between "git submodule foreach git pull origin master" and "git pull origin master --recurse-submodules"

I have a dotfiles repository where all my vim plugins are stored as submodules so they are easy to update when they have changes. I thought these two commands did the same thing, but I noticed this must not be the case.

I knew I had updates to pull down in several submodules so I ran

git pull origin master --recurse-submodules
from the root of the parent repository. It appeared to iterate over each submodule, but only fetch updates from their origin repositories.

When I ran
git submodule foreach git pull origin master
then it actually ran
git pull origin master
within each repository, doing both the fetch and the merge.

What is the point of using
? I'm a little confused about what it's actually trying to do and Google was a bit cryptic with what I found. I thought maybe you smart folks would have a simpler explanation.


That option is mainly for fetching all the submodule commits, not just pulling one specific branch like master, for reasons detailed in the two following commits:
(note there is a bug fixed in Git 2.11, see at the end of this answer)

For git pull, this option has been introduced in (commit 7dce19d, Nov. 2010, git 1.7.4-rc0):

fetch/pull: Add the --recurse-submodules option

Until now you had to call "git submodule update" (without -N|--no-fetch option) or something like "git submodule foreach git fetch" to fetch new commits in populated submodules from their remote.

This could lead to "(commits not present)" messages in the output of "git diff --submodule" (which is used by "git gui" and "gitk") after fetching or pulling new commits in the superproject and is an obstacle for implementing recursive checkout of submodules.
Also "git submodule update" cannot fetch changes when disconnected, so it was very easy to forget to fetch the submodule changes before disconnecting only to discover later that they are needed.

This patch adds the "--recurse-submodules" option to recursively fetch each populated submodule from the url configured in the .git/config of the submodule at the end of each "git fetch" or during "git pull" in the superproject. The submodule paths are taken from the index.

Commit 88a2197 (March 2011, git 1.7.5-rc1) explains a bit more:

fetch/pull: recurse into submodules when necessary

To be able to access all commits of populated submodules referenced by the superproject, it is sufficient to only then let "git fetch" recurse into a submodule when the new commits fetched in the superproject record new commits for it.

  • Having these commits present is extremely useful when using the "--submodule" option to "git diff" (which is what "git gui" and "gitk" do since 1.6.6), as all submodule commits needed for creating a descriptive output can be accessed.
  • Also merging submodule commits (added in 1.7.3) depends on the submodule commits in question being present to work.
  • Last but not least this enables disconnected operation when using submodules, as all commits necessary for a successful "git submodule update -N" will have been fetched automatically.

So we choose this mode as the default for fetch and pull.

git pull origin master --recurse-submodules 
git submodule foreach git pull origin master

The first one should pull, not just fetch, and be equivalent to the second one. Maybe this is a parameter order issue:

git pull --recurse-submodules origin master 

However, it is not the recommended way to update submodule for a given branch: see the following section.

Note that the right way to actually pull from master would be to register the master branch to the submodule, making that submodule tracking master:

git config -f .gitmodules submodule.<path>.branch <branch>

Then a simple git submodule update --remote --recursive would be enough.
And the branch to fetch/pull is recorded in the parent repo (in the .gitmodules file), so you don't even have to remember which branch you want your submodule to update against.

Update Git 2.11 (Q4 2011)

Having a submodule whose ".git" repository is somehow corrupt caused a few commands that recurse into submodules loop forever.

See commit 10f5c52 (01 Sep 2016) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 293c232, 12 Sep 2016)