239

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,160
  • 9
  • 26
philfreo
  • 36,787
  • 25
  • 119
  • 140
  • 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
  • 5
    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

8 Answers8

238

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
  • 98
  • 3
  • 7
Kane
  • 3,993
  • 1
  • 17
  • 25
  • 8
    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
  • 26
    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
  • 14
    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新疆棉花TRUMP BAN BAD 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
  • 7
    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
  • @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? – Almendrico Oct 23 '20 at 17:51
  • 1
    @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
  • @evo_race That's great news! – Andrea Jan 24 '21 at 00:05
  • 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
  • So if I read the docs for this option, "Specifies if commands recurse into submodules by default" it sounds like when I pull it's going to go into the submodule and do a "git pull," which is not what I want. I really want the effect of `git submodule update --recursive`; i.e. update the submodule to the commit referenced by the top repository's working state. Are the docs misleading me, or is this not the command I should use? – Dave Abrahams May 08 '21 at 01:07
116

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
  • 7,169
  • 4
  • 46
  • 50
Lily Ballard
  • 169,315
  • 25
  • 364
  • 333
  • 4
    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
43

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
  • 18,863
  • 8
  • 68
  • 65
Christopher Rogers
  • 6,659
  • 1
  • 20
  • 13
  • 27
    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
34

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
  • 7,784
  • 28
  • 39
  • 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` :( – Vaz Sep 21 '18 at 06:49
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
  • 422,485
  • 65
  • 357
  • 307
8

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,443
  • 1
  • 36
  • 47
7

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
0

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?