Bash: Git submodule foreach?
Asked Answered
E

4

12

I have sup aliased to submodule foreach 'git co master; git up' (co & up are aliases for checkout & pull --rebase, respectively.).

How do add a condition so that if the submodule name is Libraries/JSONKit, it checks out the branch named experimental, instead of master?

Esophagus answered 3/12, 2011 at 1:25 Comment(0)
E
1

Add the following to .git/config:

[alias]
    sup = "submodule foreach 'if [ $name == \"Libraries/JSONKit\" ]; then git co experimental; else git co master; fi; git up'"
Esophagus answered 3/12, 2011 at 18:4 Comment(1)
Why is this downvoted although it is the validated answer? Didn't tried the exact command myself, though adding an alias was very useful in my case to allow a complex LFS command to be easily launched in git foreach : [alias] track-large = !"git st --porcelain --ignore-submodules | grep -v \"D \" | awk '{ l=length($0); s=substr($0,4,l-1); print s}' | sed -n 's/\(\(.* -> *\)\\|\)\(.*\)/\\3/p' | xargs -I{} find {} -size +300k | xargs -I{} git lfs track \"{}\""Maxey
R
16

The script passwd to git submodule is run with it's working directory set to the top of the given submodule...so you can simply look at pwd to see if you're in you're in the particular submodule. However, if you take some time to read the git submodule documentation, it turns out to be even easier:

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 
    .gitmodules, $path is the name of the submodule directory
    relative to the superproject, $sha1 is the commit as recorded in the superproject, 
    and $toplevel is the absolute path to the top-level of the superproject.

So you can do something like this:

git submodule foreach '[ "$path" = "Libraries/JSONKit" ] \
  && branch=experimental \
  || branch=master; git co $branch'
Regulator answered 3/12, 2011 at 3:22 Comment(2)
for any googlers out there, I adapted this for nested submodules git submodule foreach 'git submodule init && git submodule update' - found it makes live easier for projects with plenty of plugins ;)Lovesome
submodule foreach also supports --recursive so you can walk nested submodules with the same shell command too.Difference
S
4

larsks's answer uses:

git submodule foreach '[ "$path" = "Libraries/JSONKit" ]

But it should now (2020) be

git submodule foreach '[ "$sm_path" = "Libraries/JSONKit" ]

With Git 2.26 (Q1 2020), The bulk of "git submodule foreach " has been rewritten in C, and its documentation evolves.

See commit fc1b924 (10 May 2018), and commit b6f7ac8, commit f0fd0dc, commit c033a2f (09 May 2018) by Prathamesh Chavan (pratham-pc).
(Merged by Junio C Hamano -- gitster -- in commit ea27893, 25 Jun 2018)

submodule foreach: document '$sm_path' instead of '$path'

As using a variable '$path' may be harmful to users due to capitalization issues, see 64394e3ae9 ("git submodule.sh: Don't use $path variable in eval_gettext string", 2012-04-17, Git v1.7.11-rc0 -- merge listed in batch #4).
Adjust the documentation to advocate for using $sm_path, which contains the same value.
We still make the 'path' variable available, and document it as a deprecated synonym of 'sm_path'.

Discussed-with: Ramsay Jones

The Documentation/git-submodule#foreach now includes:

foreach [--recursive] <command>:

Evaluates an arbitrary shell command in each checked out submodule.

The command has access to the variables $name, $sm_path, $sha1 and $toplevel:

  • $name is the name of the relevant submodule section in .gitmodules.
  • $sm_path is the path of the submodule as recorded in the immediate superproject,
  • $sha1 is the commit as recorded in the immediate superproject, and
  • $toplevel is the absolute path to the top-level of the immediate superproject.

Note that to avoid conflicts with '$PATH' on Windows, the '$path' variable is now a deprecated synonym of '$sm_path' variable.

Shapely answered 13/2, 2020 at 17:47 Comment(0)
E
1

Add the following to .git/config:

[alias]
    sup = "submodule foreach 'if [ $name == \"Libraries/JSONKit\" ]; then git co experimental; else git co master; fi; git up'"
Esophagus answered 3/12, 2011 at 18:4 Comment(1)
Why is this downvoted although it is the validated answer? Didn't tried the exact command myself, though adding an alias was very useful in my case to allow a complex LFS command to be easily launched in git foreach : [alias] track-large = !"git st --porcelain --ignore-submodules | grep -v \"D \" | awk '{ l=length($0); s=substr($0,4,l-1); print s}' | sed -n 's/\(\(.* -> *\)\\|\)\(.*\)/\\3/p' | xargs -I{} find {} -size +300k | xargs -I{} git lfs track \"{}\""Maxey
W
0

It would be normal practice now to say what branch you want within the .gitmodules file. Once you have done this, you can use the file for the config.

so if .gitmodules contains:

[submodule "JSONKit"]
    path = JSONKit
    url = https://github.com/RepoName/JSONKit.git
    branch = experimental

then you can say:

git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch ; git pull --rebase'

or on windows cmd:

git submodule foreach -q --recursive "branch=$(git config -f $toplevel/.gitmodules submodule.$name.branch) ; git checkout $branch ; git pull --rebase"
Wilone answered 15/5 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.