Reputation: 3533
Is there a robust way to do a recursive depth-first git submodule foreach
command? I am using the foreach --recursive
command which does the job, except it is breadth-first. This is a problem because if I have the following structure:
And I have commits in all three, a foreach --recursive add -A && git commit ...
will hit A, B, C, which is problematic if I want the supermodule to capture the commits of B at that time.
I found this discussion from 2008, but it does not look like any of the suggested features are in the current version of Git that I have (1.7.9.5).
I wrote a small bash function to do this (excuse the shorthand naming):
function git-sfed() { git submodule foreach "git submodule foreach '$*' && $*"; }
And testing it with the following fanciful command seems to work:
git-sfed 'python -c "import sys; print sys.argv" $path'
Does this command seem robust, or are there other common existing methods?
Upvotes: 13
Views: 8540
Reputation: 961
Your method actually will only do two levels of depth. To implement the full recursion, you'll want to call your script itself recursively. Something like the below should do...
#!/bin/bash
SCRIPT=$(realpath "$0")
SCRIPTDIR=$(dirname "$SCRIPT")
git submodule foreach "$SCRIPT '$1' && $1"
Upvotes: 0
Reputation: 1328522
I didn't find any other way than your function to perform a depth-first foreach
command.
The test would be to check if it does achieve recursive for a depth of more than one.
A
B
D
C
I've been having trouble with by yours and my command when trying to put in single quotes (kinda sucks not being able to write them) - escaping with multiple levels of bash commands is a little confusing.
This (quotes issue) should be simplified in Git 1.9/2.0 (Q1 2014), with commit 1c4fb13 from Anders Kaseorg (andersk):
'
eval "$@"
' creates an extra layer of shell interpretation, which is probably not expected by a user who passes multiple arguments to git submodule foreach:
$ git grep "'"
[searches for single quotes]
$ git submodule foreach git grep "'"
Entering '[submodule]'
/usr/lib/git-core/git-submodule: 1: eval: Syntax error: Unterminated quoted string
Stopping at '[submodule]'; script returned non-zero status.
To fix this, if the user passes more than one argument, execute "
$@
" directly instead of passing it toeval
.Examples:
- Typical usage when adding an extra level of quoting is to pass a single argument representing the entire command to be passed to the shell.
This doesn't change that.- One can imagine someone feeding untrusted input as an argument:
git submodule foreach git grep "$variable"
That currently results in a nonobvious shell code injection vulnerability.
Executing the command named by the arguments directly, as in this patch, fixes it.
Since Git 2.21 (Q2 2017), you have git grep -e "bar" --recurse-submodules
Upvotes: 3
Reputation: 22636
You can try this
git submodule foreach --recursive | tail -r | sed 's/Entering//' | xargs -I% cd % ; git add -A \& git commit
This list (recursively) all the submodules , then reverse the list, tail -r
so you get the directories in the order you want (child first), enter the directory and do what ever you want in it.
Upvotes: 18