status/commit: show staged submodules regardless of ignore config

Currently setting submodule.<name>.ignore and/or diff.ignoreSubmodules to "all" suppresses all output of submodule changes for the diff family, status and commit. For status and commit this is really confusing, as it even when the user chooses to record a new commit for an ignored submodule by adding it manually this change won't show up under the to-be-committed changes. To add insult to injury, a later "git commit" will error out with "nothing to commit" when only ignored submodules are staged. Fix that by making wt_status always print staged submodule changes, no matter what ignore settings are configured. The only exception is when the user explicitly uses the "--ignore-submodules=all" command line option, in that case the submodule output is still suppressed. This also makes "git commit" work again when only modifications of ignored submodules are staged, as that command uses the "commitable" member of the wt_status struct to determine if staged changes are present. But this only happens when the commit command uses the wt_status* functions to produce status output for human consumption (when forking an editor or with --dry-run), in all other cases (e.g. when run in a script with '-m') another code path is taken which uses index_differs_from() to determine if any changes are staged which still ignores submodules according to their configuration. This will be fixed in a follow-up commit. Change t7508 to reflect this new behavior and add three new tests to show that a single staged submodule configured to be ignored will be committed when the status output is generated and won't be if not. Also update the documentation of the ignore config options accordingly. Signed-off-by: Jens Lehmann <Jens.Lehmann@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jens Lehmann committed Apr 5, 2014 at 18:59 UTC 1d2f393ac9bfb4c20f14d6ead7bb4c56e766ab77
4 files changed +92 -6
Documentation/config.txt
+6 -2
@@ -2227,7 +2227,9 @@ status.submodulesummary::
2227 --summary-limit option of linkgit:git-submodule[1]). Please note
2228 that the summary output command will be suppressed for all
2229 submodules when `diff.ignoreSubmodules` is set to 'all' or only
2230 - for those submodules where `submodule.<name>.ignore=all`. To
2230 + for those submodules where `submodule.<name>.ignore=all`. The only
2231 + exception to that rule is that status and commit will show staged
2232 + submodule changes. To
2233 also view the summary for ignored submodules you can either use
2234 the --ignore-submodules=dirty command line option or the 'git
2235 submodule summary' command, which shows a similar output but does
@@ -2258,7 +2260,9 @@ submodule.<name>.fetchRecurseSubmodules::
2260 submodule.<name>.ignore::
2261 Defines under what circumstances "git status" and the diff family show
2262 a submodule as modified. When set to "all", it will never be considered
2261 - modified, "dirty" will ignore all changes to the submodules work tree and
2263 + modified (but it will nonetheless show up in the output of status and
2264 + commit when it has been staged), "dirty" will ignore all changes
2265 + to the submodules work tree and
2266 takes only differences between the HEAD of the submodule and the commit
2267 recorded in the superproject into account. "untracked" will additionally
2268 let submodules with modified tracked files in their work tree show up.
Documentation/gitmodules.txt
+3 -1
@@ -67,7 +67,9 @@ submodule.<name>.fetchRecurseSubmodules::
67 submodule.<name>.ignore::
68 Defines under what circumstances "git status" and the diff family show
69 a submodule as modified. When set to "all", it will never be considered
70 - modified, "dirty" will ignore all changes to the submodules work tree and
70 + modified (but will nonetheless show up in the output of status and
71 + commit when it has been staged), "dirty" will ignore all changes
72 + to the submodules work tree and
73 takes only differences between the HEAD of the submodule and the commit
74 recorded in the superproject into account. "untracked" will additionally
75 let submodules with modified tracked files in their work tree show up.
t/t7508-status.sh
+72 -2
@@ -1380,7 +1380,32 @@ EOF
1380 test_i18ncmp expect output
1381 '
1382
1383 -test_expect_success '.gitmodules ignore=all suppresses submodule summary' '
1383 +test_expect_success '.gitmodules ignore=all suppresses unstaged submodule summary' '
1384 + cat > expect << EOF &&
1385 +On branch master
1386 +Changes to be committed:
1387 + (use "git reset HEAD <file>..." to unstage)
1388 +
1389 + modified: sm
1390 +
1391 +Changes not staged for commit:
1392 + (use "git add <file>..." to update what will be committed)
1393 + (use "git checkout -- <file>..." to discard changes in working directory)
1394 +
1395 + modified: dir1/modified
1396 +
1397 +Untracked files:
1398 + (use "git add <file>..." to include in what will be committed)
1399 +
1400 + .gitmodules
1401 + dir1/untracked
1402 + dir2/modified
1403 + dir2/untracked
1404 + expect
1405 + output
1406 + untracked
1407 +
1408 +EOF
1409 git config --add -f .gitmodules submodule.subname.ignore all &&
1410 git config --add -f .gitmodules submodule.subname.path sm &&
1411 git status > output &&
@@ -1388,7 +1413,7 @@ test_expect_success '.gitmodules ignore=all suppresses submodule summary' '
1413 git config -f .gitmodules --remove-section submodule.subname
1414 '
1415
1391 -test_expect_success '.git/config ignore=all suppresses submodule summary' '
1416 +test_expect_success '.git/config ignore=all suppresses unstaged submodule summary' '
1417 git config --add -f .gitmodules submodule.subname.ignore none &&
1418 git config --add -f .gitmodules submodule.subname.path sm &&
1419 git config --add submodule.subname.ignore all &&
@@ -1461,4 +1486,49 @@ test_expect_success 'Restore default test environment' '
1486 git config --unset status.showUntrackedFiles
1487 '
1488
1489 +test_expect_success 'git commit will commit a staged but ignored submodule' '
1490 + git config --add -f .gitmodules submodule.subname.ignore all &&
1491 + git config --add -f .gitmodules submodule.subname.path sm &&
1492 + git config --add submodule.subname.ignore all &&
1493 + git status -s --ignore-submodules=dirty >output &&
1494 + test_i18ngrep "^M. sm" output &&
1495 + GIT_EDITOR="echo hello >>\"\$1\"" &&
1496 + export GIT_EDITOR &&
1497 + git commit -uno &&
1498 + git status -s --ignore-submodules=dirty >output &&
1499 + test_i18ngrep ! "^M. sm" output
1500 +'
1501 +
1502 +test_expect_success 'git commit --dry-run will show a staged but ignored submodule' '
1503 + git reset HEAD^ &&
1504 + git add sm &&
1505 + cat >expect << EOF &&
1506 +On branch master
1507 +Changes to be committed:
1508 + (use "git reset HEAD <file>..." to unstage)
1509 +
1510 + modified: sm
1511 +
1512 +Changes not staged for commit:
1513 + (use "git add <file>..." to update what will be committed)
1514 + (use "git checkout -- <file>..." to discard changes in working directory)
1515 +
1516 + modified: dir1/modified
1517 +
1518 +Untracked files not listed (use -u option to show untracked files)
1519 +EOF
1520 + git commit -uno --dry-run >output &&
1521 + test_i18ncmp expect output &&
1522 + git status -s --ignore-submodules=dirty >output &&
1523 + test_i18ngrep "^M. sm" output
1524 +'
1525 +
1526 +test_expect_failure 'git commit -m will commit a staged but ignored submodule' '
1527 + git commit -uno -m message &&
1528 + git status -s --ignore-submodules=dirty >output &&
1529 + test_i18ngrep ! "^M. sm" output &&
1530 + git config --remove-section submodule.subname &&
1531 + git config -f .gitmodules --remove-section submodule.subname
1532 +'
1533 +
1534 test_done
wt-status.c
+11 -1
@@ -486,9 +486,19 @@ static void wt_status_collect_changes_index(struct wt_status *s)
486 opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;
487 setup_revisions(0, NULL, &rev, &opt);
488
489 + DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
490 if (s->ignore_submodule_arg) {
490 - DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
491 handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
492 + } else {
493 + /*
494 + * Unless the user did explicitly request a submodule ignore
495 + * mode by passing a command line option we do not ignore any
496 + * changed submodule SHA-1s when comparing index and HEAD, no
497 + * matter what is configured. Otherwise the user won't be
498 + * shown any submodules she manually added (and which are
499 + * staged to be committed), which would be really confusing.
500 + */
501 + handle_ignore_submodules_arg(&rev.diffopt, "dirty");
502 }
503
504 rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;