Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git submodule foreach - Robust way to recursively commit a child module first?

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:

  • A
    • B
  • C

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?

like image 474
eacousineau Avatar asked Feb 13 '13 05:02

eacousineau


People also ask

How do I change a submodule to a specific commit?

Use the git submodule update command to set the submodules to the commit specified by the main repository. This means that if you pull in new changes into the submodules, you need to create a new commit in your main repository in order to track the updates of the nested submodules.

What is git submodule foreach?

This is taken from the manual: git help submodule : foreach Evaluates an arbitrary shell command in each checked out submodule. The command has access to the variables $name, $path, $sha1 and $toplevel: $name is the name of the relevant submodule section in .

What does recurse submodules mean?

If you pass --recurse-submodules to the git clone command, it will automatically initialize and update each submodule in the repository, including nested submodules if any of the submodules in the repository have submodules themselves.

When should you use submodules?

In most cases, Git submodules are used when your project becomes more complex, and while your project depends on the main Git repository, you might want to keep their change history separate. Using the above as an example, the Room repository depends on the House repository, but they operate separately.


2 Answers

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.

like image 200
mb14 Avatar answered Oct 18 '22 07:10

mb14


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 to eval.

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

like image 3
VonC Avatar answered Oct 18 '22 05:10

VonC