317

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.

Jon Garvin
  • 1,178
  • 9
  • 26
philfreo
  • 41,941
  • 26
  • 128
  • 141
  • 4
    Related: http://stackoverflow.com/questions/1899792/why-is-git-submodule-update-not-automatic – philfreo Jan 06 '11 at 03:40
  • 1
    Why is a git alias preferable to a shell alias? – wnoise Jan 06 '11 at 03:57
  • 21
    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. – Lily Ballard Jan 06 '11 at 04:00
  • 7
    For anyone finding this, the high-voted answers are currently out of date. Kane's answer is accurate: https://stackoverflow.com/a/49427199/3499424 – John Neuhaus Apr 27 '18 at 16:45
  • With Git 2.34, if the repository is cloned with the `--recurse-submodules`, a simple `git pull` will recurse into submodules. No more `git config --global submodule.recurse true`. This option/experimentation is activates with `git config submodule.stickyRecursiveClone true`. – VonC Sep 25 '21 at 03:53

9 Answers9

376

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
philb
  • 2,031
  • 15
  • 20
Kane
  • 5,595
  • 1
  • 18
  • 27
  • 10
    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 now – John Neuhaus Apr 27 '18 at 16:42
  • 1
    To set this globally: `git config --global submodule.recurse true` – wintersolutions May 11 '18 at 11:19
  • 45
    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? – Ben Nov 02 '18 at 11:44
  • 21
    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 :-( – Ciro Santilli OurBigBook.com Nov 30 '18 at 11:10
  • 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. – yoyo May 10 '19 at 20:41
  • 2
    @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. – anion Dec 06 '19 at 13:29
  • 13
    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`)! – Andrea Feb 17 '20 at 16:46
  • 1
    @Kane 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? – Peggy Jun 24 '20 at 03:20
  • @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. – Kane Jun 26 '20 at 13:44
  • @Ben 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. – Cerno Aug 27 '20 at 16:27
  • 1
    @Cerno, I wonder if there's a way to only talk to the submodule servers when git encounters an unknown submodule commit. – Ben Aug 27 '20 at 19:42
  • @Ben That would be nice, but none that I know of. However, I don't have deep git knowledge, so there might be a way... – Cerno Aug 28 '20 at 13:39
  • @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? – Kiteloopdesign Oct 23 '20 at 17:51
  • 3
    @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. – evo_race Jan 22 '21 at 11:35
  • 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... – Étienne Feb 18 '21 at 14:48
  • 2
    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 ` still does not work. I still have to go in after the clone and do `git submodule update --init`. – J-bob Dec 06 '21 at 17:52
  • 1
    @J-bob 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. – mtalexan May 16 '23 at 22:30
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'
crizCraig
  • 8,487
  • 6
  • 54
  • 53
Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • 5
    remember to use "git config --global" if you want this alias across all the git repos you use – yoyo Oct 08 '15 at 23:47
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]
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
Christopher Rogers
  • 6,759
  • 1
  • 22
  • 13
  • 28
    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. – Artem Nov 03 '11 at 16:02
  • 4
    @Artem is correct. This answer, although useful, doesn't address the entire question. This setting simply performs a `git fetch`, not a `git submodule update`. – Andrew Ferrier Apr 26 '14 at 13:16
  • 2
    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. – Mark Amery Feb 19 '15 at 10:12
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.

taleinat
  • 8,441
  • 1
  • 30
  • 44
  • 2
    Is there a way to make this a global setting? Or one you get automatically when checking out the repository? – Raoul Steffen Jul 13 '16 at 09:00
  • 3
    The latest release of git, 2.9, has [added a setting named `core.hooksPath` for a hooks directory](https://github.com/blog/2188-git-2-9-has-been-released#git-tidbits-gitbits-tidgits), see the docs for `git-config` for more details. – taleinat Jul 13 '16 at 16:29
  • 1
    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. – taleinat Jul 13 '16 at 16:32
  • 1
    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. – Raoul Steffen Jul 14 '16 at 10:51
  • 1
    This solution was my first thought, but then I realized it wouldn't cover people who use `git pull --rebase` :( – Tin Sep 21 '18 at 06:49
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
JacobEvelyn
  • 3,901
  • 1
  • 40
  • 51
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
}
Branden Ghena
  • 978
  • 6
  • 6
  • 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) – idbrii Oct 06 '16 at 17:17
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].

Cascabel
  • 479,068
  • 72
  • 370
  • 318
3

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.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
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?