submodule.c: correctly handle nested submodules in is_submodule_modified

Suppose I have a superproject 'super', with two submodules 'super/sub' and 'super/sub1'. 'super/sub' itself contains a submodule 'super/sub/subsub'. Now suppose I run, from within 'super': echo hi >sub/subsub/stray-file echo hi >sub1/stray-file Currently we get would see the following output in git-status: git status --short m sub ? sub1 With this patch applied, the untracked file in the nested submodule is displayed as an untracked file on the 'super' level as well. git status --short ? sub ? sub1 This doesn't change the output of 'git status --porcelain=1' for nested submodules, because its output is always ' M' for either untracked files or local modifications no matter the nesting level of the submodule. 'git status --porcelain=2' is affected by this change in a nested submodule, though. Without this patch it would report the direct submodule as modified and having no untracked files. With this patch it would report untracked files. Chalk this up as a bug fix. This bug fix also affects the default output (non-short, non-porcelain) of git-status, which is not tested here. Signed-off-by: Stefan Beller <sbeller@google.com> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Stefan Beller committed Mar 29, 2017 at 15:26 UTC 40069d6e3a195c8c2414ea60ed75b84ae47f88a1
4 files changed +24 -5
Documentation/git-status.txt
+2
@@ -189,6 +189,8 @@ Submodules have more state and instead report
189 since modified content or untracked files in a submodule cannot be added
190 via `git add` in the superproject to prepare a commit.
191
192 +'m' and '?' are applied recursively. For example if a nested submodule
193 +in a submodule contains an untracked file, this is reported as '?' as well.
194
195 If -b is used the short-format status is preceded by a line
196
submodule.c
+19 -2
@@ -1078,8 +1078,25 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
1078 /* regular untracked files */
1079 if (buf.buf[0] == '?')
1080 dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
1081 - else
1082 - dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
1081 +
1082 + if (buf.buf[0] == 'u' ||
1083 + buf.buf[0] == '1' ||
1084 + buf.buf[0] == '2') {
1085 + /* T = line type, XY = status, SSSS = submodule state */
1086 + if (buf.len < strlen("T XY SSSS"))
1087 + die("BUG: invalid status --porcelain=2 line %s",
1088 + buf.buf);
1089 +
1090 + if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
1091 + /* nested untracked file */
1092 + dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
1093 +
1094 + if (buf.buf[0] == 'u' ||
1095 + buf.buf[0] == '2' ||
1096 + memcmp(buf.buf + 5, "S..U", 4))
1097 + /* other change */
1098 + dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
1099 + }
1100
1101 if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) &&
1102 ((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ||
t/t3600-rm.sh
+1 -1
@@ -659,7 +659,7 @@ test_expect_success 'rm of a populated nested submodule with nested untracked fi
659 test -d submod &&
660 test -f submod/.git &&
661 git status -s -uno --ignore-submodules=none >actual &&
662 - test_cmp expect.modified_inside actual &&
662 + test_cmp expect.modified_untracked actual &&
663 git rm -f submod &&
664 test ! -d submod &&
665 git status -s -uno --ignore-submodules=none >actual &&
t/t7506-status-submodule.sh
+2 -2
@@ -356,7 +356,7 @@ test_expect_success 'status with untracked file in nested submodule (porcelain=2
356 git -C super status --porcelain=2 >output &&
357 sanitize_output output &&
358 diff output - <<-\EOF
359 - 1 .M S.M. 160000 160000 160000 HASH HASH sub1
359 + 1 .M S..U 160000 160000 160000 HASH HASH sub1
360 1 .M S..U 160000 160000 160000 HASH HASH sub2
361 1 .M S..U 160000 160000 160000 HASH HASH sub3
362 EOF
@@ -365,7 +365,7 @@ test_expect_success 'status with untracked file in nested submodule (porcelain=2
365 test_expect_success 'status with untracked file in nested submodule (short)' '
366 git -C super status --short >output &&
367 diff output - <<-\EOF
368 - m sub1
368 + ? sub1
369 ? sub2
370 ? sub3
371 EOF