Here is my situation:
- I’m working in a repo with 40+ submodules
git submodule updatetake a LONG time (submodule update is several minutes)
- If I checkout a different commit and only a couple submodules have been changed, I can see the submodules that need updating using
git status, then skip the long wait of a full
git submodule updateby doing
git submodule update <submodule path> <submodule path>
This will only update the submodules listed, taking only a few seconds
Is there a way to have
git submodule update only update the modules that actually need it, instead of every one? I don’t mind listing out a couple submodules manually, but when there’s 6+, it’d be nice for git to somehow use the
git status result to only run
git submodule update on the ones that need it.
Does anyone know of any git command tricks I can do to achieve this and speed up my submodule updates? If not, is there a trick I can use to make a bash script to extract the necessary information from
git status and build & run a
git submodule update <> <> <> command for me?
Bonus: is there a way to achieve a similar result on submodules that have had their content modified? That is, the submodule needs to be
git reset --hard HEAD, not checked out to a new commit. But doing this without entering EVERY submodule, such as
git submodule foreach git reset --hard HEAD, only ones that need it?
git status --porcelain
$ git status --porcelain M ABC M XYZ M XXX M YYY M FOO/BAR
You can write your own Git script to do what you want.
My high level answer
The logic your are looking for does not already exist as a Git command, but it is easy for you to implement via your own git script.
Create a script that uses
git status to get the submodules to update and then calls
git submodule update with the list of submodules.
Let’s call this script
git-subm-update. Make sure it’s executable, and on your PATH, then when you type `git subm-update it will get called and do the operation in the way you’ll have optimized it.
An actual script prototype
First, kudos to @torek for the
--porcelain=v2 option, since that gives us what we need.
For example, I have a repo with submodule
foo and modified file
$ git status --porcelain=v2 1 .M N... 100644 100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 bar 1 .M S..U 160000 160000 160000 bb765d402fb5c361a998d80363eaac41b3e27886 bb765d402fb5c361a998d80363eaac41b3e27886 foo
This is ugly but easy to parse by machine, e.g., with grep and sed (or awk or choose your favourite text manipulation tool).
Search for "Porcelain format version 2" on https://git-scm.com/docs/git-status for the full explanation. Here, I note that a dirty submodule has an
M in column 4 and an
S in column 6, with additional codes indicating more details, but I don’t think you need them for your use case. And the submodule name is the last token on the line.
git status --porcelain=v2 | grep 'M S' | sed 's/.* //' will give me
foo, or the full list of dirty submodules if you have more, and I’ll use that in my script.
I’m being a bit lazy here, you could certainly make this command a lot more robust, but here’s a prototype script which should work for you, based on it:
git-subm-update, make it executable and place it somewhere on your PATH (see https://stackoverflow.com/a/54115621/3216427), with these contents, for example:
#!/bin/bash # Run "git subm-update -n" to see what command would get run but not run it. if [[ "$1" =~ "-n" ]]; then NOT_REALLY=1 else NOT_REALLY= fi # List dirty submodules dirty_submodules=$( git status --porcelain=v2 | grep "M S" | sed 's/.* //' ) if [[ -n "$dirty_submodules" ]]; then echo Updating these dirty submodules: $dirty_submodules if [[ $NOT_REALLY ]]; then echo Would execute: git submodule update $dirty_submodules else git submodule update $dirty_submodules fi else echo No submodules to update fi
Then you can run
git subm-update to update the dirty submodules or
git subm-update -n to see what command this would run without running it.
Possible tweak: you might want
grep "M SC" instead of
grep "M S" to list only dirty modules where the commit has been updated, thus excluding modules where you’ve made local changes only.
Answered By – joanis