Skip to content

Commit c033a2f

Browse files
pratham-pcgitster
authored andcommitted
submodule foreach: correct '$path' in nested submodules from a subdirectory
When running 'git submodule foreach --recursive' from a subdirectory of your repository, nested submodules get a bogus value for $path: For a submodule 'sub' that contains a nested submodule 'nested', running 'git -C dir submodule foreach echo $path' from the root of the superproject would report path='../nested' for the nested submodule. The first part '../' is derived from the logic computing the relative path from $pwd to the root of the superproject. The second part is the submodule path inside the submodule. This value is of little use and is hard to document. Also, in git-submodule.txt, $path is documented to be the "name of the submodule directory relative to the superproject", but "the superproject" is ambiguous. To resolve both these issues, we could: (a) Change "the superproject" to "its immediate superproject", so $path would be "nested" instead of "../nested". (b) Change "the superproject" to "the superproject the original command was run from", so $path would be "sub/nested" instead of "../nested". (c) Change "the superproject" to "the directory the original command was run from", so $path would be "../sub/nested" instead of "../nested". The behavior for (c) was attempted to be introduced in 091a6eb (submodule: drop the top-level requirement, 2013-06-16) with the intent for $path to be relative from $pwd to the submodule worktree, but that did not work for nested submodules, as the intermittent submodules were not included in the path. If we were to fix the meaning of the $path using (a), we would break any existing submodule user that runs foreach from non-root of the superproject as the non-nested submodule '../sub' would change its path to 'sub'. If we were to fix the meaning of $path using (b), then we would break any user that uses nested submodules (even from the root directory) as the 'nested' would become 'sub/nested'. If we were to fix the meaning of $path using (c), then we would break the same users as in (b) as 'nested' would become 'sub/nested' from the root directory of the superproject. All groups can be found in the wild. The author has no data if one group outweighs the other by large margin, and offending each one seems equally bad at first. However in the authors imagination it is better to go with (a) as running from a sub directory sounds like it is carried out by a human rather than by some automation task. With a human on the keyboard the feedback loop is short and the changed behavior can be adapted to quickly unlike some automation that can break silently. Discussed-with: Ramsay Jones <[email protected]> Signed-off-by: Prathamesh Chavan <[email protected]> Signed-off-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Stefan Beller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ccdcbd5 commit c033a2f

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

git-submodule.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ cmd_foreach()
345345
prefix="$prefix$sm_path/"
346346
sanitize_submodule_env
347347
cd "$sm_path" &&
348-
sm_path=$(git submodule--helper relative-path "$sm_path" "$wt_prefix") &&
349348
# we make $path available to scripts ...
350349
path=$sm_path &&
351350
if test $# -eq 1

t/t7407-submodule-foreach.sh

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ test_expect_success 'test basic "submodule foreach" usage' '
8282

8383
cat >expect <<EOF
8484
Entering '../sub1'
85-
$pwd/clone-foo1-../sub1-$sub1sha1
85+
$pwd/clone-foo1-sub1-$sub1sha1
8686
Entering '../sub3'
87-
$pwd/clone-foo3-../sub3-$sub3sha1
87+
$pwd/clone-foo3-sub3-$sub3sha1
8888
EOF
8989

9090
test_expect_success 'test "submodule foreach" from subdirectory' '
@@ -196,6 +196,38 @@ test_expect_success 'test messages from "foreach --recursive" from subdirectory'
196196
) &&
197197
test_i18ncmp expect actual
198198
'
199+
sub1sha1=$(cd clone2/sub1 && git rev-parse HEAD)
200+
sub2sha1=$(cd clone2/sub2 && git rev-parse HEAD)
201+
sub3sha1=$(cd clone2/sub3 && git rev-parse HEAD)
202+
nested1sha1=$(cd clone2/nested1 && git rev-parse HEAD)
203+
nested2sha1=$(cd clone2/nested1/nested2 && git rev-parse HEAD)
204+
nested3sha1=$(cd clone2/nested1/nested2/nested3 && git rev-parse HEAD)
205+
submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEAD)
206+
207+
cat >expect <<EOF
208+
Entering '../nested1'
209+
toplevel: $pwd/clone2 name: nested1 path: nested1 hash: $nested1sha1
210+
Entering '../nested1/nested2'
211+
toplevel: $pwd/clone2/nested1 name: nested2 path: nested2 hash: $nested2sha1
212+
Entering '../nested1/nested2/nested3'
213+
toplevel: $pwd/clone2/nested1/nested2 name: nested3 path: nested3 hash: $nested3sha1
214+
Entering '../nested1/nested2/nested3/submodule'
215+
toplevel: $pwd/clone2/nested1/nested2/nested3 name: submodule path: submodule hash: $submodulesha1
216+
Entering '../sub1'
217+
toplevel: $pwd/clone2 name: foo1 path: sub1 hash: $sub1sha1
218+
Entering '../sub2'
219+
toplevel: $pwd/clone2 name: foo2 path: sub2 hash: $sub2sha1
220+
Entering '../sub3'
221+
toplevel: $pwd/clone2 name: foo3 path: sub3 hash: $sub3sha1
222+
EOF
223+
224+
test_expect_success 'test "submodule foreach --recursive" from subdirectory' '
225+
(
226+
cd clone2/untracked &&
227+
git submodule foreach --recursive "echo toplevel: \$toplevel name: \$name path: \$sm_path hash: \$sha1" >../../actual
228+
) &&
229+
test_i18ncmp expect actual
230+
'
199231

200232
cat > expect <<EOF
201233
nested1-nested1

0 commit comments

Comments
 (0)