Thread (12 messages) 12 messages, 2 authors, 4d ago

[PATCH v2 3/3] submodule: add --reversive shorthand to foreach

flat view

From: William Hatfield <hidden>
Date: 2026-10-28 00:15:35
Subsystem: documentation, the rest · Maintainers: Jonathan Corbet, Linus Torvalds

Visiting each submodule before its superproject, ending with the
top-level superproject, takes all of --recursive, --reverse-traversal
and --include-superproject. Those are three options to remember and to
type for what is, for this purpose, a single thing.

Add --reversive as a shorthand for the three of them. The options keep
working on their own, for the cases that need only one or two of them.

Signed-off-by: William Hatfield <redacted>
---
 Documentation/git-submodule.adoc       | 14 ++++++++++----
 builtin/submodule--helper.c            | 11 ++++++++++-
 contrib/completion/git-completion.bash |  2 +-
 git-submodule.sh                       |  7 ++++++-
 t/t7427-submodule-foreach-reversive.sh | 14 ++++++++++++--
 5 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/Documentation/git-submodule.adoc b/Documentation/git-submodule.adoc
index 5d4b06cb96..8f4bc002cc 100644
--- a/Documentation/git-submodule.adoc
+++ b/Documentation/git-submodule.adoc
@@ -18,7 +18,7 @@ git submodule [--quiet] update [<options>] [--] [<path>...]
 git submodule [--quiet] set-branch [<options>] [--] <path>
 git submodule [--quiet] set-url [--] <path> <newurl>
 git submodule [--quiet] summary [<options>] [--] [<path>...]
-git submodule [--quiet] foreach [--recursive] [--reverse-traversal] [--include-superproject] <command>
+git submodule [--quiet] foreach [--recursive] [--reverse-traversal] [--include-superproject] [--reversive] <command>
 git submodule [--quiet] sync [--recursive] [--] [<path>...]
 git submodule [--quiet] absorbgitdirs [--] [<path>...]
 
@@ -222,7 +222,7 @@ specifications.
 Using the `--submodule=log` option with linkgit:git-diff[1] will provide that
 information too.
 
-`foreach [--recursive] [--reverse-traversal] [--include-superproject] <command>`::
+`foreach [--recursive] [--reverse-traversal] [--include-superproject] [--reversive] <command>`::
 	Evaluate an arbitrary shell _<command>_ in each checked out submodule.
 	The command has access to the variables `$name`, `$sm_path`, `$displaypath`,
 	`$sha1` and `$toplevel`:
@@ -255,6 +255,8 @@ superproject, that is, at the top level of the repository `foreach` was
 started in, after all the submodules. There, Git sets `$displaypath` to
 the name of that directory and sets none of the other variables listed
 above, although they may come from the environment.
+`--reversive` is a shorthand for giving `--recursive`,
+`--reverse-traversal` and `--include-superproject` together.
 A non-zero return from the command in any submodule causes
 the processing to terminate. This can be overridden by adding ++||:++
 to the end of the command.
@@ -270,8 +272,7 @@ And this shows the path of each submodule and then of the superproject,
 visiting the submodules nested in a submodule before the submodule itself:
 +
 --------------
-git submodule --quiet foreach --recursive --reverse-traversal \
-	--include-superproject 'echo $displaypath'
+git submodule --quiet foreach --reversive 'echo $displaypath'
 --------------
 
 `sync [--recursive] [--] [<path>...]`::
@@ -473,6 +474,11 @@ NOTE: See the NOTE above for the `--reference` option.
 	Also evaluate the command in the superproject, after all the
 	submodules. This option is only valid for the `foreach` command.
 
+`--reversive`::
+	A shorthand for `--recursive --reverse-traversal
+	--include-superproject`. This option is only valid for the `foreach`
+	command.
+
 `--depth=<depth>`::
 	Create a 'shallow' clone with a history truncated to the _<depth>_ revisions.
 	This option is valid for `add` and `update` commands. See linkgit:git-clone[1]
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index fff5142eda..f923d2e926 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -485,6 +485,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix,
 	struct pathspec pathspec = { 0 };
 	struct module_list list = MODULE_LIST_INIT;
 	int i, j;
+	int reversive = 0;
 	struct option module_foreach_options[] = {
 		OPT__SUPER_PREFIX(&info.super_prefix),
 		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
@@ -494,10 +495,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix,
 			 N_("visit submodules in the reverse of the usual order")),
 		OPT_BOOL(0, "include-superproject", &info.include_superproject,
 			 N_("also run the command in the superproject, last")),
+		OPT_BOOL(0, "reversive", &reversive,
+			 N_("shorthand for --recursive --reverse-traversal --include-superproject")),
 		OPT_END()
 	};
 	const char *const git_submodule_helper_usage[] = {
-		N_("git submodule foreach [--quiet] [--recursive] [--reverse-traversal] [--include-superproject] [--] <command>"),
+		N_("git submodule foreach [--quiet] [--recursive] [--reverse-traversal] [--include-superproject] [--reversive] [--] <command>"),
 		NULL
 	};
 	int ret = 1;
@@ -505,6 +508,12 @@ static int module_foreach(int argc, const char **argv, const char *prefix,
 	argc = parse_options(argc, argv, prefix, module_foreach_options,
 			     git_submodule_helper_usage, 0);
 
+	if (reversive) {
+		info.recursive = 1;
+		info.reverse_traversal = 1;
+		info.include_superproject = 1;
+	}
+
 	if (module_list_compute(NULL, prefix, &pathspec, &list) < 0)
 		goto cleanup;
 
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index f47459d589..69a31316ca 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -3645,7 +3645,7 @@ _git_submodule ()
 		__gitcomp "--cached --files --summary-limit"
 		;;
 	foreach,--*)
-		__gitcomp "--recursive --reverse-traversal --include-superproject"
+		__gitcomp "--recursive --reverse-traversal --include-superproject --reversive"
 		;;
 	sync,--*)
 		__gitcomp "--recursive"
diff --git a/git-submodule.sh b/git-submodule.sh
index 964f5a8bf0..c86cbe76d2 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -14,7 +14,7 @@ USAGE="[--quiet] [--cached]
    or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>
    or: $dashless [--quiet] set-url [--] <path> <newurl>
    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
-   or: $dashless [--quiet] foreach [--recursive] [--reverse-traversal] [--include-superproject] <command>
+   or: $dashless [--quiet] foreach [--recursive] [--reverse-traversal] [--include-superproject] [--reversive] <command>
    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]
    or: $dashless [--quiet] absorbgitdirs [--] [<path>...]"
 OPTIONS_SPEC=
@@ -38,6 +38,7 @@ cached=
 recursive=
 reverse_traversal=
 include_superproject=
+reversive=
 init=
 require_init=
 files=
@@ -181,6 +182,9 @@ cmd_foreach()
 		--include-superproject)
 			include_superproject=$1
 			;;
+		--reversive)
+			reversive=$1
+			;;
 		-*)
 			usage
 			;;
@@ -196,6 +200,7 @@ cmd_foreach()
 		$recursive \
 		$reverse_traversal \
 		$include_superproject \
+		$reversive \
 		-- \
 		"$@"
 }
diff --git a/t/t7427-submodule-foreach-reversive.sh b/t/t7427-submodule-foreach-reversive.sh
index a53ea0b851..d5aa29f08e 100755
--- a/t/t7427-submodule-foreach-reversive.sh
+++ b/t/t7427-submodule-foreach-reversive.sh
@@ -3,13 +3,14 @@
 # Copyright (c) 2026 William Hatfield
 #
 
-test_description='git submodule foreach --reverse-traversal and --include-superproject
+test_description='git submodule foreach --reverse-traversal, --include-superproject and --reversive
 
 Check that --reverse-traversal visits submodules in the reverse of their
 usual order, and that, together with --recursive, each submodule is
 visited after the submodules nested in it. Check that
 --include-superproject also runs the command in the superproject, after
-all the submodules.
+all the submodules, and that --reversive is a shorthand for all three of
+these options.
 '
 
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
@@ -416,4 +417,13 @@ test_expect_success 'committing in the submodules and the superproject leaves no
 	done
 '
 
+test_expect_success '--reversive is --recursive --reverse-traversal --include-superproject' '
+	git -C reversive/top submodule --quiet foreach --recursive \
+		--reverse-traversal --include-superproject \
+		"echo \$displaypath" >expect &&
+	git -C reversive/top submodule --quiet foreach --reversive \
+		"echo \$displaypath" >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.56.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help