Is there a way to make git pull automatically update submodules?
Asked Answered
M

9

324

Is there a way to automatically have git submodule update (or preferably git submodule update --init called whenever git pull is done?

Looking for a git config setting, or a git alias to help with this.

Malposition answered 6/1, 2011 at 3:39 Comment(2)
Related: stackoverflow.com/questions/1899792/…Malposition
git aliases are nice because it encapsulates the command in the "git" namespace. You may as well ask why all git commands start with "git " instead of having their own names.Zigzagger
B
395

As of Git 2.14, you can use git pull --recurse-submodules (and alias it to whatever you like).

As of Git 2.15, you could set submodule.recurse to true to enable the desired behaviour.

You can do this globally by running:

git config --global submodule.recurse true
Blasto answered 22/3, 2018 at 11:12 Comment(16)
Confirmed with 2.16, setting this to true will cause git pull to also fetch a submodule and run submodule update. This really needs to be the accepted answer nowChemash
I was frustrated by submodules, then I did this. Now they work like I would expect. Is there a reason I’m not thinking of that this is not the default behavior?Henandchickens
They should enable that for git clone as well. And make it on by default. Otherwise, there will always be huge resistance to using submodules, as people's modules always get out of sync :-(Chubb
This works, but does not support on-demand semantics in the manner of fetch.recursesubmodules, which is unfortunate when you have a lot of submodules and the fetch is slow.Correctitude
@CiroSantilli新疆改造中心法轮功六四事件 Santilli git commands (like commit, fetch, pull, etc.) are designed to only be applied to the current repository. a submodule is another repository and should not be affected by commands executed in the parent-repository by default. this is a kind of design-decision by the git-developer.Cabbagehead
This is a dangerous setting if you care about local changes in the submodule. It seems to do the equivalent of --force, which will discard any changes in the index or working tree, and it will happily let you lose track of local commits (you'll have to resort to reflog)!Turnheim
@Blasto this global command does not work for me. The submodules aren't updated. I still need to do git submodule update --remote. I have git version 2.7.4 Anyone knows how to configure so I can use one single command like a git pull that will update all the submodules as well?Rissa
@Peggy, this command only works for git 2.15 or higher. For older versions (like yours 2.7.4) you could check other answers below.Blasto
@Henandchickens We have a huge repository with lots of submodules and I had to switch it off after a while because fetch would take ages to complete, even if there were no submodule changes.Journal
@Cerno, I wonder if there's a way to only talk to the submodule servers when git encounters an unknown submodule commit.Henandchickens
@Henandchickens That would be nice, but none that I know of. However, I don't have deep git knowledge, so there might be a way...Journal
@Andrea comment is spot on. I was about to use the global config for this when I realized it will not ask if there are local changes. Not sure there's an extra option yet to confirm in case of uncommited local changes?Arda
@Andrea It appears that this has been largely fixed now apart from an outstanding bug (v2.29.2) which causes silent loss of local changes if you switch to a branch that doesn't have the submodule, but that bug is known and a fix is in development.Tentation
This setting is really practical, however today it was driving me crazy whilte doing an interactive rebase and trying to squash two commits which were changing the git hash of a submodule. The squash operation was not working until I disabled this setting...Fife
for some reason this is not working for me. I'm using Git Bash on Windows, version 2.34.1.windows.1. After setting this doing a git clone <repo> still does not work. I still have to go in after the clone and do git submodule update --init.Polito
@Polito the answer mentions that it affects pull, not clone. In fact the 4th comment on this answer specifically mentions that it doesn't affect clone and wishes they'd implement it for that too.Wildfowl
Z
122

git config --global alias.pullall '!git pull && git submodule update --init --recursive'

If you want arguments to be passed to git pull, then use this instead:

git config --global alias.pullall '!f(){ git pull "$@" && git submodule update --init --recursive; }; f'
Zigzagger answered 6/1, 2011 at 3:48 Comment(1)
remember to use "git config --global" if you want this alias across all the git repos you useCorrectitude
G
45

Starting with Git 1.7.5 it should update submodules automatically by default like you want it to.

[EDIT: per comments: the new 1.7.5 behaviour is to automatically fetch the latest commits for submodules, but not to update them (in the git submodule update sense). So the information in this answer is relevant as background, but is not a complete answer by itself. You still need an alias to pull and update submodules in one command.]

The default behavior, "on-demand", is to update submodules whenever you fetch a commit that updates the submodule commit, and this commit isn't already located in your local clone.
You can also have it updated on every fetch or never (pre-1.7.5 behavior I assume).
The config option to change this behavior is fetch.recurseSubmodules.

This option can be either set to a boolean value or to on-demand.
Setting it to a boolean changes the behavior of fetch and pull to unconditionally recurse into submodules when set to true or to not recurse at all when set to false.

When set to on-demand (the default value), fetch and pull will only recurse into a populated submodule when its superproject retrieves a commit that updates the submodule’s reference.

See:

for more information.

git fetch --recurse-submodules[=yes|on-demand|no]
Griffen answered 27/4, 2011 at 10:53 Comment(3)
Watch out: as the answers below explain, this only fetches the changes automatically, you still have to do a submodule update -- so the alias answer is right.Inobservance
@Inobservance is correct. This answer, although useful, doesn't address the entire question. This setting simply performs a git fetch, not a git submodule update.Steppe
This answer is highly deceptive. Even when used with git pull, rather than git fetch, this option only makes the fetching recursive. It will not change what commit is checked out in the submodules at all. So git submodule update is still necessary, as noted by @Artem.Chappelka
T
41

I'm surprised nobody mentioned using git hooks to do this!

Just add files named post-checkout and post-merge to your .git/hooks directory of the relevant repositories, and put the following into each of them:

#!/bin/sh
git submodule update --init --recursive

Since you specfically asked for an alias, assuming you want to have this for many repositories, you can create an alias which adds these to a repository's .git/hooks for you.

Trotyl answered 23/5, 2016 at 5:50 Comment(5)
Is there a way to make this a global setting? Or one you get automatically when checking out the repository?Declare
The latest release of git, 2.9, has added a setting named core.hooksPath for a hooks directory, see the docs for git-config for more details.Trotyl
As for something received automatically when checking out, I searched but couldn't find anything of the sort. One source mentioned that this is purposely not supported for security issues, since it could rather easily be used to run arbitrary code on client machines.Trotyl
I see how that can be a security issue. After all, I want to use it to run code I program on my coworkers' computers without having to instruct them.Declare
This solution was my first thought, but then I realized it wouldn't cover people who use git pull --rebase :(Prophylaxis
Q
9

As others have mentioned, you can easily set this with:

git config --global submodule.recurse true

However, if you're like me and have a more complex .gitconfig setup (my main ~/.gitconfig file uses include to load in other .gitconfig files), and you can never remember how to convert between the command-line git config format and the .gitconfig format, here's how to add it to any of your .gitconfig files:

[submodule]
  recurse = true
Questa answered 6/9, 2018 at 18:58 Comment(1)
When I set this, I get a "did not exit clean" error when doing a pullKearney
W
8

An alias, as suggested by Kevin Ballard, is a perfectly good solution. Just to toss another option out there, you could also use a post-merge hook which simply runs git submodule update [--init].

Waksman answered 6/1, 2011 at 4:52 Comment(0)
B
8

You can create an alias for the git command that automatically handles submodule updating. Add the following to your .bashrc

# make git submodules usable
#   This overwrites the 'git' command with modifications where necessary, and
#   calls the original otherwise
git() {
    if [[ $@ == clone* ]]; then
        gitargs=$(echo "$@" | cut -c6-)
        command git clone --recursive $gitargs
    elif [[ $@ == pull* ]]; then
        command git "$@" && git submodule update --init --recursive
    elif [[ $@ == checkout* ]]; then
        command git "$@" && git submodule update --init --recursive
    else
        command git "$@"
    fi
}
Biller answered 21/8, 2015 at 22:50 Comment(1)
Instead of an alias for git, you can add aliases to git through the alias command or by creating commands in your path that start with git- (git-bettermodule)Playoff
S
4

As of Git 2.15, you could set submodule.recurse to true to enable the desired behaviour.

Actually, you won't have to do that.

Before Git 2.34 (Q4 2021), after "git clone --recurse-submodules"(man), all submodules are cloned but they are not by default recursed into by other commands.

With Git 2.34, and submodule.stickyRecursiveClone configuration set, submodule.recurse configuration is set to true in a repository created by "clone" with "--recurse-submodules" option.

See commit 48072e3 (14 Aug 2021) by Mahi Kolla (24mahik).
(Merged by Junio C Hamano -- gitster -- in commit 6d09fc5, 10 Sep 2021)

clone: set submodule.recurse=true if submodule.stickyRecursiveClone enabled

Signed-off-by: Mahi Kolla

Based on current experience, when running git clone --recurse-submodules(man), developers do not expect other commands such as pull or checkout to run recursively into active submodules.

However, setting submodule.recurse=true at this step could make for a simpler workflow by eliminating the need for the --recurse-submodules option in subsequent commands.

To collect more data on developers' preference in regards to making submodule.recurse=true a default config value in the future, deploy this feature under the opt in submodule.stickyRecursiveClone flag.


Warning: use Git 2.37 (Q3 2022):

"git pull"(man) without --recurse-submodules=<arg> made submodule.recurse take precedence over fetch.recurseSubmodules by mistake, which has been corrected with Git 2.37 (Q3 2022).

See commit 5819417 (10 May 2022) by Glen Choo (chooglen).
(Merged by Junio C Hamano -- gitster -- in commit ed54e1b, 20 May 2022)

pull: do not let submodule.recurse override fetch.recurseSubmodules

Reported-by: Huang Zou
Helped-by: Philippe Blain
Signed-off-by: Glen Choo

Fix a bug in "git pull"(man) where submodule.recurse is preferred over fetch.recurseSubmodules when performing a fetch (Documentation/config/fetch.txt says that fetch.recurseSubmodules should be preferred.).

Do this by passing the value of the "--recurse-submodules" CLI option to the underlying fetch, instead of passing a value that combines the CLI option and config variables.

In other words, this bug occurred because builtin/pull.c is conflating two similar-sounding, but different concepts:

  • Whether "git pull" itself should care about submodules e.g. whether it should update the submodule worktrees after performing a merge.
  • The value of "--recurse-submodules" to pass to the underlying git fetch".

Thus, when submodule.recurse is set, the underlying "git fetch"(man) gets invoked with --recurse-submodules[=value]", overriding the value of fetch.recurseSubmodules.

An alternative (and more obvious) approach to fix the bug would be to teach "git pull" to understand fetch.recurseSubmodules, but the proposed solution works better because:

  • We don't maintain two identical config-parsing implementions in "git pull" and git fetch".
  • It works better with other commands invoked by "git pull" e.g. 'git merge'(man) wont accidentally respect fetch.recurseSubmodules.
Sift answered 25/9, 2021 at 3:40 Comment(0)
U
1

Only way how I was able to get the submodules and nested submodules to update:

git submodule update --remote --merge --recursive; git submodule foreach --recursive "(git add .; git commit -m 'SubmoduleSync'; git push; git pull;);" git add .; git commit -m 'SubmodulesSynced'; git push; git pull;

I was struggling to create the alias through terminal due to the brackets so I had to manually add this to .gitconfig for global:

[alias] supdate = "!git submodule update --remote --merge --recursive; git submodule foreach --recursive '(git add .; git commit -m 'SubmoduleSync'; git push; git pull;);' git add .; git commit -m 'SubmodulesSynced'; git push; git pull;"

Any suggestions for how to run the commands or the alias automatically?

Unbelt answered 12/3, 2020 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.