{"thread":{"id":"59235","subject":"[RFC PATCH 0/6] add: block invalid submodules","startedAt":"2023-02-13T18:22:17Z","lastAt":"2023-03-07T02:04:24Z","messageCount":40,"participants":["Calvin Wan","Junio C Hamano","Jeff King","Glen Choo"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"472013","messageId":"20230213182134.2173280-1-calvinwan@google.com","threadId":"59235","inReplyTo":null,"subject":"[RFC PATCH 0/6] add: block invalid submodules","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:28Z","receivedAt":"2023-02-13T18:22:17Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"I will be taking over a series that Josh was working on before he\nwent on parental leave. For this RFC, I was wondering whether this\napproach to blocking users from eventually commiting invalid\nsubmodules is feasible. Eg. should we block at commit time instead?\nAnd if so, how would that approach look?\n\n=== Cover letter ===\n\nAt $dayjob, we believe that we need to change the default behavior\naround adding embedded repositories. Currently, we issue advice that\nembedded repositories cannot be checked out when the top-level repo is\ncloned, and that the user should probably use a submodule instead.\n\nHowever, our experience is that many users ignore this advice, and\ncommit embedded repositories to shared projects. This causes toil for\nrepo administrators who must correct these mistakes.\n\nThe main point of this series is to change the warning issued in this\ncase into a fatal error. However, this breaks lots of test cases that\nwere implemented prior to the original creation of the warning, so the\nbulk of the changes are test cleanups.\n\nFor reviewer convenience, I've tried to group the test changes with\nsimilar structure into the same commits:\n* Patch 1: Fixes a leak in submodule-config.c\n* Patch 2: Move setup code into test_expect blocks\n* Patch 3: Substitute `git submodule add` instead of `git add` for\n  simple cases (no other adjustments necessary)\n* Patch 4: As in patch 2, but also adjust expected diff output\n* Patch 5: As in patch 2, but also adjust expected status output\n* Patch 6: Change the embedded repo warning to a fatal error\n\nAn open question:\n* Currently we can bypass the embedded repo check with\n  `--no-warn-embedded-repo`. I've kept the name of the flag the same for\n  backwards compatibility. Should we instead rename the flag?\n\nCalvin Wan (1):\n  leak fix: cache_put_path\n\nJosh Steadmon (5):\n  t4041, t4060: modernize test style\n  tests: Use `git submodule add` instead of `git add`\n  tests: use `git submodule add` and fix expected diffs\n  tests: use `git submodule add` and fix expected status\n  add: reject nested repositories\n\n Documentation/git-add.txt                    |   7 +-\n builtin/add.c                                |  28 ++-\n submodule-config.c                           |   4 +-\n t/t0008-ignores.sh                           |   2 +-\n t/t2013-checkout-submodule.sh                |   4 +-\n t/t2103-update-index-ignore-missing.sh       |   2 +-\n t/t2107-update-index-basic.sh                |   2 +-\n t/t3040-subprojects-basic.sh                 |   5 +-\n t/t3050-subprojects-fetch.sh                 |   3 +-\n t/t3404-rebase-interactive.sh                |   3 +-\n t/t3701-add-interactive.sh                   |   5 +-\n t/t4010-diff-pathspec.sh                     |   2 +-\n t/t4020-diff-external.sh                     |   2 +-\n t/t4027-diff-submodule.sh                    |  17 +-\n t/t4035-diff-quiet.sh                        |   1 +\n t/t4041-diff-submodule-option.sh             | 228 +++++++++++++++----\n t/t4060-diff-submodule-option-diff-format.sh | 224 +++++++++++++-----\n t/t5531-deep-submodule-push.sh               |   4 +-\n t/t6416-recursive-corner-cases.sh            |  12 +-\n t/t6430-merge-recursive.sh                   |   1 +\n t/t6437-submodule-merge.sh                   |  12 +-\n t/t7400-submodule-basic.sh                   |   4 +-\n t/t7401-submodule-summary.sh                 |   4 +-\n t/t7402-submodule-rebase.sh                  |   2 +-\n t/t7412-submodule-absorbgitdirs.sh           |   2 +-\n t/t7414-submodule-mistakes.sh                |  21 +-\n t/t7450-bad-git-dotfiles.sh                  |   2 +-\n t/t7506-status-submodule.sh                  |  15 +-\n t/t7508-status.sh                            | 134 +++++++++--\n 29 files changed, 569 insertions(+), 183 deletions(-)\n\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472014","messageId":"20230213182134.2173280-2-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:29Z","receivedAt":"2023-02-13T18:22:35Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"hashmap_put returns a pointer if the key was found and subsequently\nreplaced. Free this pointer so it isn't leaked.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n submodule-config.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 4dc61b3a78..90cab34568 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -128,9 +128,11 @@ static void cache_put_path(struct submodule_cache *cache,\n \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n \t\t\t\t\t    submodule->path);\n \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n+\tstruct hashmap_entry *replaced;\n \thashmap_entry_init(&e->ent, hash);\n \te->config = submodule;\n-\thashmap_put(&cache->for_path, &e->ent);\n+\treplaced = hashmap_put(&cache->for_path, &e->ent);\n+\tfree(replaced);\n }\n \n static void cache_remove_path(struct submodule_cache *cache,\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472015","messageId":"20230213182134.2173280-4-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 3/6] tests: Use `git submodule add` instead of `git add`","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:31Z","receivedAt":"2023-02-13T18:22:37Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nSince 532139940c (add: warn when adding an embedded repository,\n2017-06-14), we have recognized that adding embedded repositories is a\nsubpar user experience compared to submodules. Embedded repositories\nlack a .gitmodules entry, which means clones of the top-level repo will\nbe unable to obtain the nested repo. We issue advice about this\nsituation in the case where a user adds an embedded repository.\n\nHowever, many tests predate this advice, and directly add embedded\nrepositories instead of using submodules. This commit cleans up such\ntest cases where minimal other changes are required (e.g., committing\nlater changes to .gitmodules or changing the counts of committed files\nin the worktree). Future commits will handle tests requiring more\ncomplicated adjustments.\n\nThese changes will enable us to switch the default behavior of git-add\nfrom warning about embedded repositories to rejecting them outright. See\nlater commits for a further discussion of that topic.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t0008-ignores.sh                     |  2 +-\n t/t2013-checkout-submodule.sh          |  4 +++-\n t/t2103-update-index-ignore-missing.sh |  2 +-\n t/t2107-update-index-basic.sh          |  2 +-\n t/t3040-subprojects-basic.sh           |  2 +-\n t/t3050-subprojects-fetch.sh           |  3 ++-\n t/t3404-rebase-interactive.sh          |  3 ++-\n t/t3701-add-interactive.sh             |  5 +++--\n t/t4010-diff-pathspec.sh               |  2 +-\n t/t4020-diff-external.sh               |  2 +-\n t/t4035-diff-quiet.sh                  |  1 +\n t/t5531-deep-submodule-push.sh         |  4 ++--\n t/t6416-recursive-corner-cases.sh      | 12 ++++++------\n t/t6430-merge-recursive.sh             |  1 +\n t/t6437-submodule-merge.sh             | 12 ++++++------\n t/t7401-submodule-summary.sh           |  4 ++--\n t/t7402-submodule-rebase.sh            |  2 +-\n 17 files changed, 35 insertions(+), 28 deletions(-)\n\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c70d11bc91..ea58d415ba 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -191,7 +191,7 @@ test_expect_success 'setup' '\n \t\tgit add a &&\n \t\tgit commit -m\"commit in submodule\"\n \t) &&\n-\tgit add a/submodule &&\n+\tgit submodule add ./a/submodule ./a/submodule &&\n \tcat <<-\\EOF >.gitignore &&\n \t\tone\n \t\tignored-*\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex b2bdd1fcb4..dd2858648b 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -10,7 +10,7 @@ test_expect_success 'setup' '\n \t(cd submodule &&\n \t git init &&\n \t test_commit first) &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \ttest_tick &&\n \tgit commit -m superproject &&\n \t(cd submodule &&\n@@ -51,6 +51,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .gitm\n \tgit config diff.ignoreSubmodules none &&\n \tgit config -f .gitmodules submodule.submodule.path submodule &&\n \tgit config -f .gitmodules submodule.submodule.ignore untracked &&\n+\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n \tgit checkout HEAD >actual 2>&1 &&\n \ttest_must_be_empty actual\n '\n@@ -59,6 +60,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n \tgit config -f .gitmodules submodule.submodule.ignore none &&\n \tgit config submodule.submodule.path submodule &&\n \tgit config submodule.submodule.ignore all &&\n+\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n \tgit checkout HEAD >actual 2>&1 &&\n \ttest_must_be_empty actual\n '\ndiff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\nindex e9451cd567..f43a57350c 100755\n--- a/t/t2103-update-index-ignore-missing.sh\n+++ b/t/t2103-update-index-ignore-missing.sh\n@@ -36,7 +36,7 @@ test_expect_success basics '\n \t\tgit add file &&\n \t\tgit commit -m \"sub initial\"\n \t) &&\n-\tgit add xyzzy &&\n+\tgit submodule add ./xyzzy &&\n \n \ttest_tick &&\n \tgit commit -m initial &&\ndiff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh\nindex 07e6de84e6..465b41ccdc 100755\n--- a/t/t2107-update-index-basic.sh\n+++ b/t/t2107-update-index-basic.sh\n@@ -49,7 +49,7 @@ test_expect_success '--cacheinfo does not accept blob null sha1' '\n test_expect_success '--cacheinfo does not accept gitlink null sha1' '\n \tgit init submodule &&\n \t(cd submodule && test_commit foo) &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \tgit rev-parse :submodule >expect &&\n \ttest_must_fail git update-index --cacheinfo 160000 $ZERO_OID submodule &&\n \tgit rev-parse :submodule >actual &&\ndiff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh\nindex bd65dfcffc..61da7e3b94 100755\n--- a/t/t3040-subprojects-basic.sh\n+++ b/t/t3040-subprojects-basic.sh\n@@ -69,7 +69,7 @@ test_expect_success 'check if clone works' '\n test_expect_success 'removing and adding subproject' '\n \tgit update-index --force-remove -- sub2 &&\n \tmv sub2 sub3 &&\n-\tgit add sub3 &&\n+\tgit submodule add ./sub3 &&\n \tgit commit -q -m \"renaming a subproject\" &&\n \ttest_expect_code 1 git diff -M --name-status --exit-code HEAD^ HEAD\n '\ndiff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh\nindex f1f09abdd9..9a692274b9 100755\n--- a/t/t3050-subprojects-fetch.sh\n+++ b/t/t3050-subprojects-fetch.sh\n@@ -14,7 +14,8 @@ test_expect_success setup '\n \t\tgit commit -m \"subproject commit #1\"\n \t) &&\n \t>mainfile &&\n-\tgit add sub mainfile &&\n+\tgit add mainfile &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"superproject commit #1\"\n '\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 462cefd25d..1d0574216b 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -675,7 +675,8 @@ test_expect_success 'submodule rebase setup' '\n \t\tgit add elif && git commit -m \"submodule initial\"\n \t) &&\n \techo 1 >file1 &&\n-\tgit add file1 sub &&\n+\tgit add file1 &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"One\" &&\n \techo 2 >file1 &&\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb..715c4fcc62 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -913,8 +913,9 @@ test_expect_success 'setup different kinds of dirty submodules' '\n \t\t) &&\n \t\tcp -R dirty-head dirty-otherwise &&\n \t\tcp -R dirty-head dirty-both-ways &&\n-\t\tgit add dirty-head &&\n-\t\tgit add dirty-otherwise dirty-both-ways &&\n+\t\tgit submodule add ./dirty-head &&\n+\t\tgit submodule add ./dirty-otherwise &&\n+\t\tgit submodule add ./dirty-both-ways &&\n \t\tgit commit -m initial &&\n \n \t\tcd dirty-head &&\ndiff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh\nindex 9d9650eba7..844258c418 100755\n--- a/t/t4010-diff-pathspec.sh\n+++ b/t/t4010-diff-pathspec.sh\n@@ -117,7 +117,7 @@ test_expect_success 'setup submodules' '\n \ttest_tick &&\n \tgit init submod &&\n \t( cd submod && test_commit first ) &&\n-\tgit add submod &&\n+\tgit submodule add ./submod &&\n \tgit commit -m first &&\n \t( cd submod && test_commit second ) &&\n \tgit add submod &&\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex c1ac09ecc7..ca2a23a78f 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -253,7 +253,7 @@ test_expect_success 'clean up crlf leftovers' '\n test_expect_success 'submodule diff' '\n \tgit init sub &&\n \t( cd sub && test_commit sub1 ) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"add submodule\" &&\n \t( cd sub && test_commit sub2 ) &&\ndiff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh\nindex 76f8034c60..23ef222006 100755\n--- a/t/t4035-diff-quiet.sh\n+++ b/t/t4035-diff-quiet.sh\n@@ -66,6 +66,7 @@ test_expect_success 'git diff-index --cached HEAD^' '\n test_expect_success 'git diff-index --cached HEAD^' '\n \techo text >>b &&\n \techo 3 >c &&\n+\tgit submodule add ./test-outside/repo ./test-outside/repo &&\n \tgit add . &&\n \ttest_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt &&\n \ttest_line_count = 0 cnt\ndiff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\nindex 302e4cbdba..f8ef70b5a2 100755\n--- a/t/t5531-deep-submodule-push.sh\n+++ b/t/t5531-deep-submodule-push.sh\n@@ -28,7 +28,7 @@ test_expect_success setup '\n \t\t\tgit add junk &&\n \t\t\tgit commit -m \"Initial junk\"\n \t\t) &&\n-\t\tgit add gar/bage &&\n+\t\tgit submodule add ./gar/bage ./gar/bage &&\n \t\tgit commit -m \"Initial superproject\"\n \t)\n '\n@@ -367,7 +367,7 @@ test_expect_success 'push succeeds if submodule has no remote and is on the firs\n \t\t\tgit add junk &&\n \t\t\tgit commit -m \"initial\"\n \t\t) &&\n-\t\tgit add b &&\n+\t\tgit submodule add ./b &&\n \t\tgit commit -m \"added submodule\" &&\n \t\tgit push --recurse-submodules=check origin main\n \t)\ndiff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh\nindex 17b54d625d..b366dd77e5 100755\n--- a/t/t6416-recursive-corner-cases.sh\n+++ b/t/t6416-recursive-corner-cases.sh\n@@ -1270,7 +1270,7 @@ test_expect_success 'setup submodule modify/modify' '\n \t\t) &&\n \n \t\tgit -C submod reset --hard A &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m A &&\n \t\tgit tag A &&\n \n@@ -1303,7 +1303,7 @@ test_expect_merge_algorithm failure success 'check submodule modify/modify' '\n \t\ttest_must_fail git merge -s recursive E^0 &&\n \n \t\tgit ls-files -s >out &&\n-\t\ttest_line_count = 3 out &&\n+\t\ttest_line_count = 4 out &&\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 3 out &&\n \t\tgit ls-files -o >out &&\n@@ -1364,12 +1364,12 @@ test_expect_success 'setup submodule add/add' '\n \n \t\tgit checkout -b B A &&\n \t\tgit -C submod reset --hard B &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m B &&\n \n \t\tgit checkout -b C A &&\n \t\tgit -C submod reset --hard C &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m C &&\n \n \t\tgit checkout -q B^0 &&\n@@ -1391,7 +1391,7 @@ test_expect_merge_algorithm failure success 'check submodule add/add' '\n \t\ttest_must_fail git merge -s recursive E^0 &&\n \n \t\tgit ls-files -s >out &&\n-\t\ttest_line_count = 3 out &&\n+\t\ttest_line_count = 4 out &&\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 2 out &&\n \t\tgit ls-files -o >out &&\n@@ -1439,7 +1439,7 @@ test_expect_success 'setup conflicting entry types (submodule vs symlink)' '\n \n \t\tgit checkout -b B A &&\n \t\tgit -C path reset --hard B &&\n-\t\tgit add path &&\n+\t\tgit submodule add ./path &&\n \t\tgit commit -m B &&\n \n \t\tgit checkout -b C A &&\ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex 07067bb347..8962db8faa 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -677,6 +677,7 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n \techo content3 >sub2/file3 &&\n \tmkdir simple &&\n \techo base >simple/bar &&\n+\tgit -c protocol.file.allow=always submodule add ./sym &&\n \tgit add -A &&\n \ttest_tick &&\n \tgit commit -m base &&\ndiff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\nindex c9a86f2e94..7f6e89f541 100755\n--- a/t/t6437-submodule-merge.sh\n+++ b/t/t6437-submodule-merge.sh\n@@ -30,7 +30,7 @@ test_expect_success setup '\n \t git add file &&\n \t test_tick &&\n \t git commit -m sub-root) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m root &&\n \n@@ -85,7 +85,7 @@ test_expect_success 'setup for merge search' '\n \t git branch sub-a) &&\n \tgit commit --allow-empty -m init &&\n \tgit branch init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"a\" &&\n \tgit branch a &&\n \n@@ -132,7 +132,7 @@ test_expect_success 'finish setup for merge-search' '\n \tgit checkout -b g init &&\n \t(cd sub &&\n \t git checkout -b sub-g sub-c) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -a -m \"g\")\n '\n \n@@ -296,7 +296,7 @@ test_expect_success 'setup for recursive merge with submodule' '\n \t  git checkout -b sub-cb sub-c &&\n \t  git merge sub-b &&\n \t  git checkout main) &&\n-\t git add sub &&\n+\t git submodule add ./sub &&\n \t git commit -m a &&\n \t git checkout -b top-b main &&\n \t (cd sub && git checkout sub-b) &&\n@@ -520,7 +520,7 @@ test_expect_success 'setup for null merge base' '\n \tgit commit --allow-empty -m init &&\n \tgit branch init &&\n \tgit checkout -b a init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"a\" &&\n \tgit switch main &&\n \t(cd sub &&\n@@ -532,7 +532,7 @@ test_expect_success 'setup for null merge base' '\n test_expect_success 'merging should fail with no merge base' '\n \t(cd no-merge-base &&\n \tgit checkout -b b init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"b\" &&\n \ttest_must_fail git merge a >actual &&\n \tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\ndiff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh\nindex 542b3331a7..73fd09edb6 100755\n--- a/t/t7401-submodule-summary.sh\n+++ b/t/t7401-submodule-summary.sh\n@@ -45,7 +45,7 @@ add_file . foo >/dev/null\n head1=$(add_file sm1 foo1 foo2)\n \n test_expect_success 'added submodule' \"\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n \tgit submodule summary >actual &&\n \tcat >expected <<-EOF &&\n \t* sm1 0000000...$head1 (2):\n@@ -253,7 +253,7 @@ test_expect_success 'deleted submodule' \"\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead7=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2\n '\n \n test_expect_success 'multiple submodules' \"\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a71..abc2092741 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -14,7 +14,7 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit clone . submodule &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \ttest_tick &&\n \tgit commit -m submodule &&\n \techo second line >> file &&\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472016","messageId":"20230213182134.2173280-5-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 4/6] tests: use `git submodule add` and fix expected diffs","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:32Z","receivedAt":"2023-02-13T18:22:39Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nThis commit continues the previous work of updating the test suite to\nuse `git submodule add` to create submodules instead of using `git add`\nto include embedded repositories. Specifically, in this commit we update\ntest cases where expected diffs must change due to the presence of a\n.gitmodules file.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t3040-subprojects-basic.sh                 |   3 +-\n t/t4041-diff-submodule-option.sh             | 153 ++++++++++++++++++-\n t/t4060-diff-submodule-option-diff-format.sh | 125 +++++++++++++--\n t/t7506-status-submodule.sh                  |  15 +-\n 4 files changed, 278 insertions(+), 18 deletions(-)\n\ndiff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh\nindex 61da7e3b94..a0f14db3d2 100755\n--- a/t/t3040-subprojects-basic.sh\n+++ b/t/t3040-subprojects-basic.sh\n@@ -19,11 +19,12 @@ test_expect_success 'setup: create subprojects' '\n \t( cd sub2 && git init && : >Makefile && git add * &&\n \tgit commit -q -m \"subproject 2\" ) &&\n \tgit update-index --add sub1 &&\n-\tgit add sub2 &&\n+\tgit submodule add ./sub2 &&\n \tgit commit -q -m \"subprojects added\" &&\n \tGIT_PRINT_SHA1_ELLIPSIS=\"yes\" git diff-tree --abbrev=5 HEAD^ HEAD |cut -d\" \" -f-3,5- >current &&\n \tgit branch save HEAD &&\n \tcat >expected <<-\\EOF &&\n+\t:000000 100644 00000... A\t.gitmodules\n \t:000000 160000 00000... A\tsub1\n \t:000000 160000 00000... A\tsub2\n \tEOF\ndiff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\nindex 556682b18b..6c666d2b7a 100755\n--- a/t/t4041-diff-submodule-option.sh\n+++ b/t/t4041-diff-submodule-option.sh\n@@ -50,9 +50,19 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'added submodule' '\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n+\tgitmodules_hash1=$(git rev-parse --short $(git hash-object .gitmodules)) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tEOF\n \ttest_cmp expected actual\n@@ -63,6 +73,15 @@ test_expect_success 'added submodule, set diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tEOF\n \tgit config --unset diff.submodule &&\n@@ -74,6 +93,15 @@ test_expect_success '--submodule=short overrides diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --submodule=short --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -89,6 +117,15 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_config diff.submodule log &&\n \tgit diff-index -p HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -105,6 +142,15 @@ test_expect_success 'modified submodule(forward)' '\n \thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head1..$head2:\n \t  > Add foo3 ($added foo3)\n \tEOF\n@@ -154,6 +200,15 @@ test_expect_success 'modified submodule(backward)' '\n \t) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2..$head3 (rewind):\n \t  < Add foo3 ($added foo3)\n \t  < Add foo2 ($added foo2)\n@@ -165,6 +220,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2...$head4:\n \t  > Add foo5 ($added foo5)\n \t  > Add foo4 ($added foo4)\n@@ -187,6 +251,15 @@ test_expect_success 'setup - change sm1 to a blob' '\n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=log --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -219,6 +292,15 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -238,6 +320,15 @@ test_expect_success 'nonexistent commit' '\n \tfullhead6=$(cd sm1 && git rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...$head6 (commits not present)\n \tEOF\n \ttest_cmp expected actual\n@@ -436,12 +527,24 @@ test_expect_success 'deleted submodule' '\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead7=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2 &&\n+\tgitmodules_hash2=$(git rev-parse --short $(git hash-object .gitmodules))\n '\n \n test_expect_success 'multiple submodules' '\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -460,6 +563,17 @@ test_expect_success 'given commit' '\n \tcommit_file sm2 &&\n \tgit diff-index -p --submodule=log HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -469,6 +583,17 @@ test_expect_success 'given commit' '\n test_expect_success 'given commit --submodule' '\n \tgit diff-index -p --submodule HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -479,6 +604,17 @@ test_expect_success 'given commit --submodule=short' '\n \tfullhead7=$(cd sm2 && git rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=short HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tdiff --git a/sm1 b/sm1\n \tdeleted file mode 160000\n \tindex $head6..0000000\n@@ -507,6 +643,17 @@ test_expect_success 'setup .git file for sm2' '\n test_expect_success 'diff --submodule with .git file' '\n \tgit diff --submodule HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -525,7 +672,7 @@ test_expect_success 'diff --submodule with objects referenced by alternates' '\n \t(cd super &&\n \t\tgit clone -s ../sub_alt sub &&\n \t\tgit init &&\n-\t\tgit add sub &&\n+\t\tgit submodule add ./sub &&\n \t\tgit commit -m \"sub a\"\n \t) &&\n \t(cd sub_alt &&\ndiff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh\nindex 3cda8ffd14..6bee3ac628 100755\n--- a/t/t4060-diff-submodule-option-diff-format.sh\n+++ b/t/t4060-diff-submodule-option-diff-format.sh\n@@ -61,9 +61,18 @@ test_expect_success 'setup repository' '\n '\n \n test_expect_success 'added submodule' '\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tnew file mode 100644\n@@ -88,6 +97,15 @@ test_expect_success 'added submodule, set diff.submodule' '\n \tgit add sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tnew file mode 100644\n@@ -112,6 +130,15 @@ test_expect_success '--submodule=short overrides diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --submodule=short --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -127,6 +154,15 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_config diff.submodule log &&\n \tgit diff-index -p HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -143,6 +179,15 @@ test_expect_success 'modified submodule(forward)' '\n \thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head1..$head2:\n \tdiff --git a/sm1/foo3 b/sm1/foo3\n \tnew file mode 100644\n@@ -203,6 +248,15 @@ test_expect_success 'modified submodule(backward)' '\n \t) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2..$head3 (rewind):\n \tdiff --git a/sm1/foo2 b/sm1/foo2\n \tdeleted file mode 100644\n@@ -226,6 +280,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2...$head4:\n \tdiff --git a/sm1/foo2 b/sm1/foo2\n \tdeleted file mode 100644\n@@ -272,6 +335,15 @@ test_expect_success 'setup - change sm1 to a blob' '\n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=diff --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tdeleted file mode 100644\n@@ -346,6 +418,15 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -364,6 +445,15 @@ test_expect_success 'nonexistent commit' '\n \thead6=$(add_file sm1 foo6 foo7) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...$head6 (commits not present)\n \tEOF\n \tdiff_cmp expected actual\n@@ -655,12 +745,23 @@ test_expect_success 'deleted submodule' '\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead9=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2\n '\n \n test_expect_success 'multiple submodules' '\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex 2334463..8809a9f 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head9 (new submodule)\n \tdiff --git a/sm2/foo8 b/sm2/foo8\n@@ -717,11 +818,13 @@ test_expect_success 'given commit' '\n \tgit diff-index -p --submodule=diff HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/.gitmodules b/.gitmodules\n-\tnew file mode 100644\n-\tindex 1234567..89abcde\n-\t--- /dev/null\n+\tindex 1234567..89abcde 100644\n+\t--- a/.gitmodules\n \t+++ b/.gitmodules\n-\t@@ -0,0 +1,3 @@\n+\t@@ -1,3 +1,3 @@\n+\t-[submodule \"sm1\"]\n+\t-\tpath = sm1\n+\t-\turl = ./sm1\n \t+[submodule \"sm2\"]\n \t+path = sm2\n \t+url = bogus_url\n@@ -753,11 +856,13 @@ test_expect_success 'diff --submodule=diff with .git file' '\n \tgit diff --submodule=diff HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/.gitmodules b/.gitmodules\n-\tnew file mode 100644\n-\tindex 1234567..89abcde\n-\t--- /dev/null\n+\tindex 1234567..89abcde 100644\n+\t--- a/.gitmodules\n \t+++ b/.gitmodules\n-\t@@ -0,0 +1,3 @@\n+\t@@ -1,3 +1,3 @@\n+\t-[submodule \"sm1\"]\n+\t-\tpath = sm1\n+\t-\turl = ./sm1\n \t+[submodule \"sm2\"]\n \t+path = sm2\n \t+url = bogus_url\ndiff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh\nindex d050091345..9dbd9ff266 100755\n--- a/t/t7506-status-submodule.sh\n+++ b/t/t7506-status-submodule.sh\n@@ -31,7 +31,8 @@ sanitize_diff () {\n test_expect_success 'setup' '\n \ttest_create_repo_with_commit sub &&\n \techo output > .gitignore &&\n-\tgit add sub .gitignore &&\n+\tgit submodule add ./sub &&\n+\tgit add .gitignore &&\n \tgit commit -m \"Add submodule sub\"\n '\n \n@@ -243,7 +244,7 @@ test_expect_success 'status -a clean (empty submodule dir)' '\n '\n \n cat >status_expect <<\\EOF\n-AA .gitmodules\n+UU .gitmodules\n A  sub1\n EOF\n \n@@ -277,7 +278,10 @@ cat >diff_expect <<\\EOF\n diff --cc .gitmodules\n --- a/.gitmodules\n +++ b/.gitmodules\n-@@@ -1,3 -1,3 +1,9 @@@\n+@@@ -1,6 -1,6 +1,12 @@@\n+  [submodule \"sub\"]\n+  \tpath = sub\n+  \turl = ./sub\n ++<<<<<<< HEAD\n  +[submodule \"sub2\"]\n  +\tpath = sub2\n@@ -293,7 +297,10 @@ cat >diff_submodule_expect <<\\EOF\n diff --cc .gitmodules\n --- a/.gitmodules\n +++ b/.gitmodules\n-@@@ -1,3 -1,3 +1,9 @@@\n+@@@ -1,6 -1,6 +1,12 @@@\n+  [submodule \"sub\"]\n+  \tpath = sub\n+  \turl = ./sub\n ++<<<<<<< HEAD\n  +[submodule \"sub2\"]\n  +\tpath = sub2\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472017","messageId":"20230213182134.2173280-6-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 5/6] tests: use `git submodule add` and fix expected status","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:33Z","receivedAt":"2023-02-13T18:22:41Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nThis commit continues the previous work of updating the test suite to\nuse `git submodule add` to create submodules instead of using `git add`\nto include embedded repositories.\n\nIn this commit, we update test cases where the expected status output\nmust change due to the presence of a .gitmodules file. We use the\npre-existing expected output as a template for cases where .gitmodules\nhas been modified but not committed.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t4027-diff-submodule.sh |  17 +++--\n t/t7508-status.sh         | 134 ++++++++++++++++++++++++++++++++------\n 2 files changed, 128 insertions(+), 23 deletions(-)\n\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 40164ae07d..2ee9f18b38 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -18,7 +18,8 @@ test_expect_success setup '\n \n \ttest_tick &&\n \techo frotz >nitfol &&\n-\tgit add nitfol sub &&\n+\tgit add nitfol &&\n+\tgit submodule add ./sub &&\n \tgit commit -m superproject &&\n \n \t(\n@@ -122,25 +123,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n '\n \n test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n+\tgit branch pristine-gitmodules &&\n \tgit config diff.ignoreSubmodules dirty &&\n \tgit diff HEAD >actual &&\n \ttest_must_be_empty actual &&\n \tgit config --add -f .gitmodules submodule.subname.ignore none &&\n \tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n \tgit config -f .gitmodules submodule.subname.ignore all &&\n \tgit config -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual3.body &&\n \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n \tgit config submodule.subname.ignore none &&\n@@ -152,7 +158,7 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n \tgit config --unset diff.ignoreSubmodules &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n@@ -190,12 +196,15 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n \tgit config --add -f .gitmodules submodule.subname.ignore all &&\n \tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \ttest_must_be_empty actual3 &&\n \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n \tgit config submodule.subname.ignore none &&\n@@ -206,7 +215,7 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)\n \ttest_cmp expect.body actual.body &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff between submodule commits' '\n@@ -243,7 +252,7 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' '\n \texpect_from_to >expect.body $subtip $subprev &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff (empty submodule dir)' '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 2b7ef6c41a..5808339997 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -892,7 +892,7 @@ test_expect_success 'setup status submodule summary' '\n \t\tgit add foo &&\n \t\tgit commit -m \"Add foo\"\n \t) &&\n-\tgit add sm\n+\tgit submodule add ./sm\n '\n \n test_expect_success 'status submodule summary is disabled by default' '\n@@ -904,6 +904,7 @@ and have 1 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -931,6 +932,7 @@ test_expect_success 'status --untracked-files=all does not show submodule' '\n '\n \n cat >expect <<EOF\n+A  .gitmodules\n  M dir1/modified\n A  dir2/added\n A  sm\n@@ -961,6 +963,7 @@ and have 1 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -998,6 +1001,7 @@ test_expect_success 'commit with submodule summary ignores status.displayComment\n '\n \n cat >expect <<EOF\n+A  .gitmodules\n  M dir1/modified\n A  dir2/added\n A  sm\n@@ -1068,6 +1072,7 @@ and have 2 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --source=HEAD^1 --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -1134,7 +1139,6 @@ Submodule changes to be committed:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1152,8 +1156,37 @@ test_expect_success '.gitmodules ignore=untracked suppresses submodules with unt\n \ttest_cmp expect output &&\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1163,7 +1196,7 @@ test_expect_success '.git/config ignore=untracked suppresses submodules with unt\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname\n '\n@@ -1180,7 +1213,7 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with untrack\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1190,7 +1223,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with untrack\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1205,7 +1238,7 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with modifie\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1215,7 +1248,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1245,7 +1278,6 @@ Submodule changes to be committed:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1259,8 +1291,39 @@ EOF\n test_expect_success \".gitmodules ignore=untracked doesn't suppress submodules with modified content\" '\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+  (commit or discard the untracked or modified content in submodules)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\tmodified:   sm (modified content)\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1270,7 +1333,7 @@ test_expect_success \".git/config ignore=untracked doesn't suppress submodules wi\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1306,7 +1369,6 @@ Submodules changed but not updated:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1318,10 +1380,45 @@ EOF\n '\n \n test_expect_success \".gitmodules ignore=untracked doesn't suppress submodule summary\" '\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\tmodified:   sm (new commits)\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Submodules changed but not updated:\n+\n+* sm $new_head...$head2 (1):\n+  > 2nd commit\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1331,7 +1428,7 @@ test_expect_success \".git/config ignore=untracked doesn't suppress submodule sum\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1344,7 +1441,7 @@ test_expect_success \".gitmodules ignore=dirty doesn't suppress submodule summary\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1354,7 +1451,7 @@ test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1387,7 +1484,6 @@ cat > expect << EOF\n ;\n ; Untracked files:\n ;   (use \"git add <file>...\" to include in what will be committed)\n-;\t.gitmodules\n ;\tdir1/untracked\n ;\tdir2/modified\n ;\tdir2/untracked\n@@ -1420,7 +1516,6 @@ Changes not staged for commit:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1446,11 +1541,11 @@ Changes to be committed:\n Changes not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n \tmodified:   dir1/modified\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1566,6 +1661,7 @@ Changes to be committed:\n Changes not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n \tmodified:   dir1/modified\n \n Untracked files not listed (use -u option to show untracked files)\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472018","messageId":"20230213182134.2173280-7-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 6/6] add: reject nested repositories","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:34Z","receivedAt":"2023-02-13T18:22:43Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nAs noted in 532139940c (add: warn when adding an embedded repository,\n2017-06-14), adding embedded repositories results in subpar experience\ncompared to submodules, due to the lack of a corresponding .gitmodules\nentry, which means later clones of the top-level repository cannot\nlocate the embedded repo. We expect that this situation is usually\nunintentional, which is why 532139940c added a warning message and\nadvice when users attempt to add an embedded repo.\n\nAt $dayjob, we have found that even this advice is insufficient to stop\nusers from committing unclonable embedded repos in shared projects.\nThis causes toil for the owners of the top-level project repository as\nthey must clean up the resulting gitlinks. Additionally, these mistakes\nare often made by partners outside of $dayjob, which means that a simple\norganization-wide change to the default Git config would be insufficient\nto prevent these mistakes.\n\nDue to this experience, we believe that Git's default behavior should be\nchanged to disallow adding embedded repositories. This commit changes\nthe existing warning into a fatal error while preserving the\n`--no-warn-embedded-repo` flag as a way to bypass this check.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n Documentation/git-add.txt          |  7 ++++---\n builtin/add.c                      | 28 ++++++++++++++++++++--------\n t/t7400-submodule-basic.sh         |  4 ++--\n t/t7412-submodule-absorbgitdirs.sh |  2 +-\n t/t7414-submodule-mistakes.sh      | 21 ++++++++++-----------\n t/t7450-bad-git-dotfiles.sh        |  2 +-\n 6 files changed, 38 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex a030d33c6e..b7fb95b061 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -177,10 +177,11 @@ for \"git add --no-all <pathspec>...\", i.e. ignored removed files.\n \ttree or not.\n \n --no-warn-embedded-repo::\n-\tBy default, `git add` will warn when adding an embedded\n+\tBy default, `git add` will error out when adding an embedded\n \trepository to the index without using `git submodule add` to\n-\tcreate an entry in `.gitmodules`. This option will suppress the\n-\twarning (e.g., if you are manually performing operations on\n+\tcreate an entry in `.gitmodules`. This option will allow the\n+\tembedded repository to be added and suppress the error.\n+\t(e.g., if you are manually performing operations on\n \tsubmodules).\n \n --renormalize::\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 76277df326..795d9251b9 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -421,36 +421,45 @@ static const char embedded_advice[] = N_(\n \"\\n\"\n \"\tgit rm --cached %s\\n\"\n \"\\n\"\n-\"See \\\"git help submodule\\\" for more information.\"\n+\"See \\\"git help submodule\\\" for more information.\\n\"\n+\"\\n\"\n+\"If you cannot use submodules, you may bypass this check with:\\n\"\n+\"\\n\"\n+\"\tgit add --no-warn-embedded-repo %s\\n\"\n );\n \n-static void check_embedded_repo(const char *path)\n+static int check_embedded_repo(const char *path)\n {\n+\tint ret = 0;\n \tstruct strbuf name = STRBUF_INIT;\n \tstatic int adviced_on_embedded_repo = 0;\n \n \tif (!warn_on_embedded_repo)\n-\t\treturn;\n+\t\tgoto cleanup;\n \tif (!ends_with(path, \"/\"))\n-\t\treturn;\n+\t\tgoto cleanup;\n+\n+\tret = 1;\n \n \t/* Drop trailing slash for aesthetics */\n \tstrbuf_addstr(&name, path);\n \tstrbuf_strip_suffix(&name, \"/\");\n \n-\twarning(_(\"adding embedded git repository: %s\"), name.buf);\n+\terror(_(\"cannot add embedded git repository: %s\"), name.buf);\n \tif (!adviced_on_embedded_repo &&\n \t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n-\t\tadvise(embedded_advice, name.buf, name.buf);\n+\t\tadvise(embedded_advice, name.buf, name.buf, name.buf);\n \t\tadviced_on_embedded_repo = 1;\n \t}\n \n+cleanup:\n \tstrbuf_release(&name);\n+\treturn ret;\n }\n \n static int add_files(struct dir_struct *dir, int flags)\n {\n-\tint i, exit_status = 0;\n+\tint i, exit_status = 0, embedded_repo = 0;\n \tstruct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;\n \n \tif (dir->ignored_nr) {\n@@ -476,10 +485,13 @@ static int add_files(struct dir_struct *dir, int flags)\n \t\t\t\tdie(_(\"adding files failed\"));\n \t\t\texit_status = 1;\n \t\t} else {\n-\t\t\tcheck_embedded_repo(dir->entries[i]->name);\n+\t\t\tembedded_repo |= check_embedded_repo(dir->entries[i]->name);\n \t\t}\n \t}\n \n+\tif (embedded_repo)\n+\t\tdie(_(\"refusing to add embedded git repositories\"));\n+\n \tif (matched_sparse_paths.nr) {\n \t\tadvise_on_updating_sparse_paths(&matched_sparse_paths);\n \t\texit_status = 1;\ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex eae6a46ef3..e0bcecba6e 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -118,7 +118,7 @@ test_expect_success 'setup - repository in init subdirectory' '\n test_expect_success 'setup - commit with gitlink' '\n \techo a >a &&\n \techo z >z &&\n-\tgit add a init z &&\n+\tgit add --no-warn-embedded-repo a init z &&\n \tgit commit -m \"super commit 1\"\n '\n \n@@ -771,7 +771,7 @@ test_expect_success 'set up for relative path tests' '\n \t\t\tgit init &&\n \t\t\ttest_commit foo\n \t\t) &&\n-\t\tgit add sub &&\n+\t\tgit add --no-warn-embedded-repo sub &&\n \t\tgit config -f .gitmodules submodule.sub.path sub &&\n \t\tgit config -f .gitmodules submodule.sub.url ../subrepo &&\n \t\tcp .git/config pristine-.git-config &&\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex 2859695c6d..365953b558 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -100,7 +100,7 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n \tgit init sub2 &&\n \ttest_commit -C sub2 first &&\n-\tgit add sub2 &&\n+\tgit add --no-warn-embedded-repo sub2 &&\n \tgit commit -m superproject\n '\n \ndiff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh\nindex 101afff30f..dbdcbe909d 100755\n--- a/t/t7414-submodule-mistakes.sh\n+++ b/t/t7414-submodule-mistakes.sh\n@@ -10,31 +10,30 @@ test_expect_success 'create embedded repository' '\n \ttest_commit -C embed one\n '\n \n-test_expect_success 'git-add on embedded repository warns' '\n-\ttest_when_finished \"git rm --cached -f embed\" &&\n-\tgit add embed 2>stderr &&\n-\ttest_i18ngrep warning stderr\n+test_expect_success 'git-add on embedded repository dies' '\n+\ttest_must_fail git add embed 2>stderr &&\n+\ttest_i18ngrep fatal stderr\n '\n \n-test_expect_success '--no-warn-embedded-repo suppresses warning' '\n+test_expect_success '--no-warn-embedded-repo suppresses error message' '\n \ttest_when_finished \"git rm --cached -f embed\" &&\n \tgit add --no-warn-embedded-repo embed 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\ttest_i18ngrep ! fatal stderr\n '\n \n-test_expect_success 'no warning when updating entry' '\n+test_expect_success 'no error message when updating entry' '\n \ttest_when_finished \"git rm --cached -f embed\" &&\n-\tgit add embed &&\n+\tgit add --no-warn-embedded-repo embed &&\n \tgit -C embed commit --allow-empty -m two &&\n \tgit add embed 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\ttest_i18ngrep ! fatal stderr\n '\n \n-test_expect_success 'submodule add does not warn' '\n+test_expect_success 'submodule add does not issue error message' '\n \ttest_when_finished \"git rm -rf submodule .gitmodules\" &&\n \tgit -c protocol.file.allow=always \\\n \t\tsubmodule add ./embed submodule 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\ttest_i18ngrep ! fatal stderr\n '\n \n test_done\ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex ba1f569bcb..6fbcf36ae9 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -307,7 +307,7 @@ test_expect_success 'git dirs of sibling submodules must not be nested' '\n \t\tEOF\n \t\tgit clone . thing1 &&\n \t\tgit clone . thing2 &&\n-\t\tgit add .gitmodules thing1 thing2 &&\n+\t\tgit add --no-warn-embedded-repo .gitmodules thing1 thing2 &&\n \t\ttest_tick &&\n \t\tgit commit -m nested\n \t) &&\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472019","messageId":"20230213182134.2173280-3-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[RFC PATCH 2/6] t4041, t4060: modernize test style","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-13T18:21:30Z","receivedAt":"2023-02-13T18:22:46Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nIn preparation for later changes, move setup code into test_expect\nblocks. Smaller sections are moved into existing blocks, while larger\nsections with a standalone purpose are given their own new blocks.\n\nThis makes sure that later changes that may break the test setup are\neasier to diagnose, because errors will caught immediately rather than\nin later unrelated test_expect blocks.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t4041-diff-submodule-option.sh             | 75 +++++++--------\n t/t4060-diff-submodule-option-diff-format.sh | 99 ++++++++++----------\n 2 files changed, 87 insertions(+), 87 deletions(-)\n\ndiff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\nindex 0c1502d4b0..556682b18b 100755\n--- a/t/t4041-diff-submodule-option.sh\n+++ b/t/t4041-diff-submodule-option.sh\n@@ -42,11 +42,12 @@ commit_file () {\n \tgit commit \"$@\" -m \"Commit $*\" >/dev/null\n }\n \n-test_create_repo sm1 &&\n-add_file . foo >/dev/null\n-\n-head1=$(add_file sm1 foo1 foo2)\n-fullhead1=$(cd sm1; git rev-parse --verify HEAD)\n+test_expect_success 'setup' '\n+\ttest_create_repo sm1 &&\n+\tadd_file . foo >/dev/null &&\n+\thead1=$(add_file sm1 foo1 foo2) &&\n+\tfullhead1=$(cd sm1 && git rev-parse --verify HEAD)\n+'\n \n test_expect_success 'added submodule' '\n \tgit add sm1 &&\n@@ -99,10 +100,9 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head2=$(add_file sm1 foo3)\n-\n test_expect_success 'modified submodule(forward)' '\n+\tcommit_file sm1 &&\n+\thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head1..$head2:\n@@ -129,8 +129,8 @@ test_expect_success 'modified submodule(forward) --submodule' '\n \ttest_cmp expected actual\n '\n \n-fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'modified submodule(forward) --submodule=short' '\n+\tfullhead2=$(cd sm1 && git rev-parse --verify HEAD) &&\n \tgit diff --submodule=short >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -144,14 +144,14 @@ test_expect_success 'modified submodule(forward) --submodule=short' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head3=$(\n-\tcd sm1 &&\n-\tgit reset --hard HEAD~2 >/dev/null &&\n-\tgit rev-parse --short --verify HEAD\n-)\n \n test_expect_success 'modified submodule(backward)' '\n+\tcommit_file sm1 &&\n+\thead3=$(\n+\t\tcd sm1 &&\n+\t\tgit reset --hard HEAD~2 >/dev/null &&\n+\t\tgit rev-parse --short --verify HEAD\n+\t) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2..$head3 (rewind):\n@@ -161,8 +161,8 @@ test_expect_success 'modified submodule(backward)' '\n \ttest_cmp expected actual\n '\n \n-head4=$(add_file sm1 foo4 foo5)\n test_expect_success 'modified submodule(backward and forward)' '\n+\thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2...$head4:\n@@ -174,13 +174,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-mv sm1 sm1-bak &&\n-echo sm1 >sm1 &&\n-head5=$(git hash-object sm1 | cut -c1-7) &&\n-git add sm1 &&\n-rm -f sm1 &&\n-mv sm1-bak sm1\n+test_expect_success 'setup - change sm1 to a blob' '\n+\tcommit_file sm1 &&\n+\tmv sm1 sm1-bak &&\n+\techo sm1 >sm1 &&\n+\thead5=$(git hash-object sm1 | cut -c1-7) &&\n+\tgit add sm1 &&\n+\trm -f sm1 &&\n+\tmv sm1-bak sm1\n+'\n \n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=log --cached >actual &&\n@@ -212,9 +214,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \ttest_cmp expected actual\n '\n \n-rm -rf sm1 &&\n-git checkout-index sm1\n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\trm -rf sm1 &&\n+\tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n@@ -229,11 +231,11 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \ttest_cmp expected actual\n '\n \n-rm -f sm1 &&\n-test_create_repo sm1 &&\n-head6=$(add_file sm1 foo6 foo7)\n-fullhead6=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'nonexistent commit' '\n+\trm -f sm1 &&\n+\ttest_create_repo sm1 &&\n+\thead6=$(add_file sm1 foo6 foo7) &&\n+\tfullhead6=$(cd sm1 && git rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...$head6 (commits not present)\n@@ -241,8 +243,8 @@ test_expect_success 'nonexistent commit' '\n \ttest_cmp expected actual\n '\n \n-commit_file\n test_expect_success 'typechanged submodule(blob->submodule)' '\n+\tcommit_file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -257,8 +259,8 @@ test_expect_success 'typechanged submodule(blob->submodule)' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n test_expect_success 'submodule is up to date' '\n+\tcommit_file sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \ttest_must_be_empty actual\n '\n@@ -327,9 +329,9 @@ test_expect_success 'submodule contains modified content' '\n \ttest_cmp expected actual\n '\n \n-(cd sm1; git commit -mchange foo6 >/dev/null) &&\n-head8=$(cd sm1; git rev-parse --short --verify HEAD) &&\n test_expect_success 'submodule is modified' '\n+\t(cd sm1 && git commit -mchange foo6 >/dev/null) &&\n+\thead8=$(cd sm1 && git rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head6..$head8:\n@@ -422,8 +424,8 @@ test_expect_success 'modified submodule contains modified content' '\n \ttest_cmp expected actual\n '\n \n-rm -rf sm1\n test_expect_success 'deleted submodule' '\n+\trm -rf sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n@@ -454,8 +456,8 @@ test_expect_success 'path filter' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm2\n test_expect_success 'given commit' '\n+\tcommit_file sm2 &&\n \tgit diff-index -p --submodule=log HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n@@ -473,9 +475,8 @@ test_expect_success 'given commit --submodule' '\n \ttest_cmp expected actual\n '\n \n-fullhead7=$(cd sm2; git rev-parse --verify HEAD)\n-\n test_expect_success 'given commit --submodule=short' '\n+\tfullhead7=$(cd sm2 && git rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=short HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\ndiff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh\nindex 97c6424cd5..3cda8ffd14 100755\n--- a/t/t4060-diff-submodule-option-diff-format.sh\n+++ b/t/t4060-diff-submodule-option-diff-format.sh\n@@ -138,10 +138,9 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head2=$(add_file sm1 foo3)\n-\n test_expect_success 'modified submodule(forward)' '\n+\tcommit_file sm1 &&\n+\thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head1..$head2:\n@@ -180,8 +179,8 @@ test_expect_success 'modified submodule(forward) --submodule' '\n \tdiff_cmp expected actual\n '\n \n-fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'modified submodule(forward) --submodule=short' '\n+\tfullhead2=$(cd sm1 && git rev-parse --verify HEAD) &&\n \tgit diff --submodule=short >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -195,14 +194,13 @@ test_expect_success 'modified submodule(forward) --submodule=short' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head3=$(\n-\tcd sm1 &&\n-\tgit reset --hard HEAD~2 >/dev/null &&\n-\tgit rev-parse --short --verify HEAD\n-)\n-\n test_expect_success 'modified submodule(backward)' '\n+\tcommit_file sm1 &&\n+\thead3=$(\n+\t\tcd sm1 &&\n+\t\tgit reset --hard HEAD~2 >/dev/null &&\n+\t\tgit rev-parse --short --verify HEAD\n+\t) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2..$head3 (rewind):\n@@ -224,8 +222,8 @@ test_expect_success 'modified submodule(backward)' '\n \tdiff_cmp expected actual\n '\n \n-head4=$(add_file sm1 foo4 foo5)\n test_expect_success 'modified submodule(backward and forward)' '\n+\thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2...$head4:\n@@ -261,13 +259,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-mv sm1 sm1-bak &&\n-echo sm1 >sm1 &&\n-head5=$(git hash-object sm1 | cut -c1-7) &&\n-git add sm1 &&\n-rm -f sm1 &&\n-mv sm1-bak sm1\n+test_expect_success 'setup - change sm1 to a blob' '\n+\tcommit_file sm1 &&\n+\tmv sm1 sm1-bak &&\n+\techo sm1 >sm1 &&\n+\thead5=$(git hash-object sm1 | cut -c1-7) &&\n+\tgit add sm1 &&\n+\trm -f sm1 &&\n+\tmv sm1-bak sm1\n+'\n \n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=diff --cached >actual &&\n@@ -341,9 +341,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tdiff_cmp expected actual\n '\n \n-rm -rf sm1 &&\n-git checkout-index sm1\n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\trm -rf sm1 &&\n+\tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n@@ -358,10 +358,10 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tdiff_cmp expected actual\n '\n \n-rm -f sm1 &&\n-test_create_repo sm1 &&\n-head6=$(add_file sm1 foo6 foo7)\n test_expect_success 'nonexistent commit' '\n+\trm -f sm1 &&\n+\ttest_create_repo sm1 &&\n+\thead6=$(add_file sm1 foo6 foo7) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...$head6 (commits not present)\n@@ -369,8 +369,8 @@ test_expect_success 'nonexistent commit' '\n \tdiff_cmp expected actual\n '\n \n-commit_file\n test_expect_success 'typechanged submodule(blob->submodule)' '\n+\tcommit_file &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -399,8 +399,8 @@ test_expect_success 'typechanged submodule(blob->submodule)' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n test_expect_success 'submodule is up to date' '\n+\tcommit_file sm1 &&\n \thead7=$(git -C sm1 rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \ttest_must_be_empty actual\n@@ -492,9 +492,9 @@ test_expect_success 'submodule contains modified content' '\n \tdiff_cmp expected actual\n '\n \n-(cd sm1; git commit -mchange foo6 >/dev/null) &&\n-head8=$(cd sm1; git rev-parse --short --verify HEAD) &&\n test_expect_success 'submodule is modified' '\n+\t(cd sm1 && git commit -mchange foo6 >/dev/null) &&\n+\thead8=$(cd sm1 && git rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7..$head8:\n@@ -643,8 +643,8 @@ test_expect_success 'modified submodule contains modified content' '\n \tdiff_cmp expected actual\n '\n \n-rm -rf sm1\n test_expect_success 'deleted submodule' '\n+\trm -rf sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n@@ -703,13 +703,15 @@ test_expect_success 'path filter' '\n \tdiff_cmp expected actual\n '\n \n-cat >.gitmodules <<-EOF\n-[submodule \"sm2\"]\n-\tpath = sm2\n-\turl = bogus_url\n-EOF\n-git add .gitmodules\n-commit_file sm2 .gitmodules\n+test_expect_success 'setup - construct .gitmodules' '\n+\tcat >.gitmodules <<-EOF &&\n+\t[submodule \"sm2\"]\n+\t\tpath = sm2\n+\t\turl = bogus_url\n+\tEOF\n+\tgit add .gitmodules &&\n+\tcommit_file sm2 .gitmodules\n+'\n \n test_expect_success 'given commit' '\n \tgit diff-index -p --submodule=diff HEAD^ >actual &&\n@@ -779,9 +781,8 @@ test_expect_success 'diff --submodule=diff with .git file' '\n \tdiff_cmp expected actual\n '\n \n-mv sm2 sm2-bak\n-\n test_expect_success 'deleted submodule with .git file' '\n+\tmv sm2 sm2-bak &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n@@ -804,9 +805,8 @@ test_expect_success 'deleted submodule with .git file' '\n \tdiff_cmp expected actual\n '\n \n-echo submodule-to-blob>sm2\n-\n test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n+\techo submodule-to-blob>sm2 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n@@ -836,10 +836,9 @@ test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n \tdiff_cmp expected actual\n '\n \n-rm sm2\n-mv sm2-bak sm2\n-\n test_expect_success 'setup nested submodule' '\n+\trm sm2 &&\n+\tmv sm2-bak sm2 &&\n \tgit -c protocol.file.allow=always -C sm2 submodule add ../sm2 nested &&\n \tgit -C sm2 commit -a -m \"nested sub\" &&\n \thead10=$(git -C sm2 rev-parse --short --verify HEAD)\n@@ -910,13 +909,11 @@ test_expect_success 'diff --submodule=diff recurses into nested submodules' '\n \tdiff_cmp expected actual\n '\n \n-(cd sm2; commit_file nested)\n-commit_file sm2\n-head12=$(cd sm2; git rev-parse --short --verify HEAD)\n-\n-mv sm2 sm2-bak\n-\n test_expect_success 'diff --submodule=diff recurses into deleted nested submodules' '\n+\t(cd sm2 && commit_file nested) &&\n+\tcommit_file sm2 &&\n+\thead12=$(cd sm2 && git rev-parse --short --verify HEAD) &&\n+\tmv sm2 sm2-bak &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n \tSubmodule sm2 $head12...0000000 (submodule deleted)\n@@ -971,6 +968,8 @@ test_expect_success 'diff --submodule=diff recurses into deleted nested submodul\n \tdiff_cmp expected actual\n '\n \n-mv sm2-bak sm2\n+test_expect_success 'submodule cleanup' '\n+\tmv sm2-bak sm2\n+'\n \n test_done\n-- \n2.39.1.581.gbfd45094c4-goog\n\n"},{"id":"472024","messageId":"xmqqk00lbc8k.fsf@gitster.g","threadId":"59235","inReplyTo":"20230213182134.2173280-2-calvinwan@google.com","subject":"Re: [RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-13T19:23:55Z","receivedAt":"2023-02-13T19:24:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> hashmap_put returns a pointer if the key was found and subsequently\n> replaced. Free this pointer so it isn't leaked.\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n>  submodule-config.c | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n>\n> diff --git a/submodule-config.c b/submodule-config.c\n> index 4dc61b3a78..90cab34568 100644\n> --- a/submodule-config.c\n> +++ b/submodule-config.c\n> @@ -128,9 +128,11 @@ static void cache_put_path(struct submodule_cache *cache,\n>  \tunsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n>  \t\t\t\t\t    submodule->path);\n>  \tstruct submodule_entry *e = xmalloc(sizeof(*e));\n> +\tstruct hashmap_entry *replaced;\n>  \thashmap_entry_init(&e->ent, hash);\n>  \te->config = submodule;\n> -\thashmap_put(&cache->for_path, &e->ent);\n> +\treplaced = hashmap_put(&cache->for_path, &e->ent);\n> +\tfree(replaced);\n>  }\n\nOut of curiosity, I've checked all the grep hits from hashmap_put()\nin the codebase and this seems to be the only one.  Everybody else\neither calls hashmap_put() only after hashmap_get() sees that there\nis no existing one, or unconditionally calls hashmap_put() and dies\nif an earlier registration is found.\n\nThe callers of oidmap_put() in sequencer.c I didn't check.  There\nmight be similar leaks there, or they may be safe---I dunno.  But\nall other callers of oidmap_put() also seem to be safe.\n\nBack to the patch itself.  The only caller of this function does\n\n\tif (submodule->path) {\n\t\tcache_remove_path(me->cache, submodule);\n\t\tfree(submodule->path);\n\t}\n\tsubmodule->path = xstrdup(value);\n\tcache_put_path(me->cache, submodule);\n\nIt is curious how the same submodule->path is occupied by more than\none submodule?  Isn't that a configuration error we want to report\nto the user somehow (not necessarily error/die), instead of silently\nreplacing with the \"last one wins\" precedence?\n\nAssuming that the \"last one wins\" is the sensible thing to do, the\nchange proposed by this patch does seem reasonable way to plug the\nleak.\n\nThanks.\n"},{"id":"472025","messageId":"xmqqedqtbbf4.fsf@gitster.g","threadId":"59235","inReplyTo":"20230213182134.2173280-3-calvinwan@google.com","subject":"Re: [RFC PATCH 2/6] t4041, t4060: modernize test style","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-13T19:41:35Z","receivedAt":"2023-02-13T19:42:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> From: Josh Steadmon <steadmon@google.com>\n>\n> In preparation for later changes, move setup code into test_expect\n> blocks. Smaller sections are moved into existing blocks, while larger\n> sections with a standalone purpose are given their own new blocks.\n\nNice.\n\n> -test_create_repo sm1 &&\n> -add_file . foo >/dev/null\n> -\n> -head1=$(add_file sm1 foo1 foo2)\n> -fullhead1=$(cd sm1; git rev-parse --verify HEAD)\n> +test_expect_success 'setup' '\n> +\ttest_create_repo sm1 &&\n> +\tadd_file . foo >/dev/null &&\n\nNow this is inside test_expect_success, redirection to /dev/null is\nunnecessary.\n\n> +\thead1=$(add_file sm1 foo1 foo2) &&\n> +\tfullhead1=$(cd sm1 && git rev-parse --verify HEAD)\n> +'\n\nOr \"fullhead1=$(git -C sm1 rev-parse ...)\".\n\nBoth of the above can be ignored if we are trying to be a strict\nrewrite of the original, but moving code inside test_expect_success\nblock is a large enough change that there may not be much point in\navoiding such an obvious modernization \"while at it\".\n\n\n> -rm sm2\n> -mv sm2-bak sm2\n> -\n>  test_expect_success 'setup nested submodule' '\n> +\trm sm2 &&\n> +\tmv sm2-bak sm2 &&\n\nTo me, this looks more like something test_when_finished in the test\nthat wanted not to have sm2 (i.e. \"deleted submodule with .git file\")\nshould have done as part of its own clean-up.\n\nThere certainly can be two schools of thought when it comes to how to\narrange the precondition of subsequent tests.  More modern tests tend\nto clean after themselves by reverting the damage they made to the\nenvironment inside test_when_finished in themselves.  This one, as\nthe posted patch does, goes to the other extreme and forces the\nsubsequent test to undo the damage done by the previous ones.\n\nThe latter approach has two major downsides.  It would not work if\nthe tester wants to skip an earlier step, or if an earlier step\nfailed to cause the expected damage this step wants to undo.  The\ncorrectness of \"what we should see as sm2 here must be in sm2-bak\nbecause we know an earlier step should have moved it there\" can\neasily be broken.  It also makes it harder to update the earlier\nstep to cause different damage to the environment---the \"undoing the\ndamage done by the previous step(s)\" done as early parts of this\nstep also needs to be updated.\n\nWhichever approach we pick to use in each script, it would be better\nto stick to one philosophy, and if we can make each step revert the\ndamage it caused when it is done, that would be nice.\n\n> -mv sm2-bak sm2\n> +test_expect_success 'submodule cleanup' '\n> +\tmv sm2-bak sm2\n> +'\n>  \n>  test_done\n\nLikewise.\n\nThanks.\n"},{"id":"472027","messageId":"Y+qgwHx52DSAfsEb@coredump.intra.peff.net","threadId":"59235","inReplyTo":"20230213182134.2173280-7-calvinwan@google.com","subject":"Re: [RFC PATCH 6/6] add: reject nested repositories","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-02-13T20:42:40Z","receivedAt":"2023-02-13T20:42:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 13, 2023 at 06:21:34PM +0000, Calvin Wan wrote:\n\n> As noted in 532139940c (add: warn when adding an embedded repository,\n> 2017-06-14), adding embedded repositories results in subpar experience\n> compared to submodules, due to the lack of a corresponding .gitmodules\n> entry, which means later clones of the top-level repository cannot\n> locate the embedded repo. We expect that this situation is usually\n> unintentional, which is why 532139940c added a warning message and\n> advice when users attempt to add an embedded repo.\n\nAs the author of 532139940c, this escalation to an error seems like a\nreasonable step to me.\n\nThe patch looks pretty reasonable to me from a cursory read, but here a\nfew small comments:\n\n> diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\n> index a030d33c6e..b7fb95b061 100644\n> --- a/Documentation/git-add.txt\n> +++ b/Documentation/git-add.txt\n> @@ -177,10 +177,11 @@ for \"git add --no-all <pathspec>...\", i.e. ignored removed files.\n>  \ttree or not.\n>  \n>  --no-warn-embedded-repo::\n> -\tBy default, `git add` will warn when adding an embedded\n> +\tBy default, `git add` will error out when adding an embedded\n\nThe option name here is rather unfortunate, since it's no longer a\nwarning. But keeping it as-is for historical compatibility may be the\nbest option. In retrospect, I wish I'd called it --allow-embedded-repos\nor something.\n\n> diff --git a/builtin/add.c b/builtin/add.c\n> index 76277df326..795d9251b9 100644\n> --- a/builtin/add.c\n> +++ b/builtin/add.c\n> @@ -421,36 +421,45 @@ static const char embedded_advice[] = N_(\n>  \"\\n\"\n>  \"\tgit rm --cached %s\\n\"\n>  \"\\n\"\n> -\"See \\\"git help submodule\\\" for more information.\"\n> +\"See \\\"git help submodule\\\" for more information.\\n\"\n> +\"\\n\"\n> +\"If you cannot use submodules, you may bypass this check with:\\n\"\n> +\"\\n\"\n> +\"\tgit add --no-warn-embedded-repo %s\\n\"\n>  );\n\nI was a little surprised by this hunk, but I guess if we are going to\nblock the user's operation from completing, we might want to tell them\nhow to get around it. But it seems odd to me that the instructions to\n\"git rm --cached\" the submodule remain. If this situation is now an\nerror and not a warning, there is nothing to roll back from the index,\nsince we will have bailed before writing it.\n\nIf we are going to start recommending --no-warn-embedded-repo here,\nwould we want to promote it from being OPT_HIDDEN_BOOL()? We do document\nit in the manpage, but just omit it from the \"-h\" output, since it\nshould be rarely used. Maybe it is OK to stay that way; you don't need\nit until you run into this situation, at which point the advice\nhopefully has guided you in the right direction.\n\n> -static void check_embedded_repo(const char *path)\n> +static int check_embedded_repo(const char *path)\n>  {\n> +\tint ret = 0;\n>  \tstruct strbuf name = STRBUF_INIT;\n>  \tstatic int adviced_on_embedded_repo = 0;\n>  \n>  \tif (!warn_on_embedded_repo)\n> -\t\treturn;\n> +\t\tgoto cleanup;\n>  \tif (!ends_with(path, \"/\"))\n> -\t\treturn;\n> +\t\tgoto cleanup;\n> +\n> +\tret = 1;\n\nI wondered about these \"goto cleanup\" calls here, since there is nothing\nto clean up yet. But you are just piggy-backing on the \"return ret\",\nrather than a separate \"return 0\" here.\n\nAnd I was surprised by returning at all, since the point is to make this\na hard error. But it looks like the intent is to report an error for\nevery such case, and then a final die, like:\n\n  $ git add .\n  error: cannot add embedded git repository: foo\n  advice: ...\n  error: cannot add embedded git repository: bar\n  fatal: refusing to add embedded git repositories\n\nOK. I doubt anybody cares much either way (it is more convenient if you\nhave a lot of cases, at the expense of making the error more verbose\nwhen there is only one case), so this is fine.\n\n>  \t/* Drop trailing slash for aesthetics */\n>  \tstrbuf_addstr(&name, path);\n>  \tstrbuf_strip_suffix(&name, \"/\");\n>  \n> -\twarning(_(\"adding embedded git repository: %s\"), name.buf);\n> +\terror(_(\"cannot add embedded git repository: %s\"), name.buf);\n>  \tif (!adviced_on_embedded_repo &&\n>  \t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n> -\t\tadvise(embedded_advice, name.buf, name.buf);\n> +\t\tadvise(embedded_advice, name.buf, name.buf, name.buf);\n\nThis triple name.buf that must match the earlier string is horrible, of\ncourse, but nothing new in your patch. If you drop the \"rm --cached\"\npart from the advice, it can remain as a horrible double-mention of\nname.buf. :)\n\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index eae6a46ef3..e0bcecba6e 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -118,7 +118,7 @@ test_expect_success 'setup - repository in init subdirectory' '\n>  test_expect_success 'setup - commit with gitlink' '\n>  \techo a >a &&\n>  \techo z >z &&\n> -\tgit add a init z &&\n> +\tgit add --no-warn-embedded-repo a init z &&\n>  \tgit commit -m \"super commit 1\"\n>  '\n>  \n> @@ -771,7 +771,7 @@ test_expect_success 'set up for relative path tests' '\n>  \t\t\tgit init &&\n>  \t\t\ttest_commit foo\n>  \t\t) &&\n> -\t\tgit add sub &&\n> +\t\tgit add --no-warn-embedded-repo sub &&\n>  \t\tgit config -f .gitmodules submodule.sub.path sub &&\n>  \t\tgit config -f .gitmodules submodule.sub.url ../subrepo &&\n>  \t\tcp .git/config pristine-.git-config &&\n\nOK, these are cases that are warning now (because they are trying to do\nsomething clever with the setup), but which will be blocked. Arguably\nthey should have --no-warn-embedded-repo already, but nobody cared\nso far that their stderr was a little noisy.\n\nI do wonder if there are any users who might do clever things like this\nthemselves, but they'd already have been nagged by the warning (and\nhopefully discovered --no-warn-embedded-repo on their own).\n\n-Peff\n"},{"id":"472035","messageId":"xmqqy1p188rj.fsf@gitster.g","threadId":"59235","inReplyTo":"20230213182134.2173280-5-calvinwan@google.com","subject":"Re: [RFC PATCH 4/6] tests: use `git submodule add` and fix expected diffs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-13T23:07:12Z","receivedAt":"2023-02-13T23:07:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> From: Josh Steadmon <steadmon@google.com>\n>\n> This commit continues the previous work of updating the test suite to\n> use `git submodule add` to create submodules instead of using `git add`\n> to include embedded repositories. Specifically, in this commit we update\n> test cases where expected diffs must change due to the presence of a\n> .gitmodules file.\n\nGood that these \"same\" tasks are split into two steps, ones that\ndon't notice the additional presence of .gitmodules (i.e. the\nprevious step) and the result that do.\n\nStrictly speaking, gitlink support in the index and trees does not\nhave to be used to record submodules, and changing all \"git add\" to\n\"git submodule add\" is somewhat a sad change that closes the door to\nthose folks who want to use the mechanism for implementing \"better\nsubmodules\" that do not depend on a separate .gitmodules files, for\nexample.  To leave the door open, \"git add\" may need to learn an\noverriding mechanism allow adding a gitlink to the index without\nanything else.  And then this step could use \"git add -f\" (or\nwhategver the overriding mechanism) instead of \"git submodule add\",\nwithout changing the expected diff output.\n\nWould such a tweak make this step better?  I dunno.\n\n>  t/t3040-subprojects-basic.sh                 |   3 +-\n>  t/t4041-diff-submodule-option.sh             | 153 ++++++++++++++++++-\n>  t/t4060-diff-submodule-option-diff-format.sh | 125 +++++++++++++--\n>  t/t7506-status-submodule.sh                  |  15 +-\n>  4 files changed, 278 insertions(+), 18 deletions(-)\n"},{"id":"472036","messageId":"xmqqttzp887h.fsf@gitster.g","threadId":"59235","inReplyTo":"xmqqy1p188rj.fsf@gitster.g","subject":"Re: [RFC PATCH 4/6] tests: use `git submodule add` and fix expected diffs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-13T23:19:14Z","receivedAt":"2023-02-13T23:19:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Calvin Wan <calvinwan@google.com> writes:\n>\n>> From: Josh Steadmon <steadmon@google.com>\n>>\n>> This commit continues the previous work of updating the test suite to\n>> use `git submodule add` to create submodules instead of using `git add`\n>> to include embedded repositories. Specifically, in this commit we update\n>> test cases where expected diffs must change due to the presence of a\n>> .gitmodules file.\n>\n> Good that these \"same\" tasks are split into two steps, ones that\n> don't notice the additional presence of .gitmodules (i.e. the\n> previous step) and the result that do.\n>\n> Strictly speaking, gitlink support in the index and trees does not\n> have to be used to record submodules, and changing all \"git add\" to\n> \"git submodule add\" is somewhat a sad change that closes the door to\n> those folks who want to use the mechanism for implementing \"better\n> submodules\" that do not depend on a separate .gitmodules files, for\n> example.  To leave the door open, \"git add\" may need to learn an\n> overriding mechanism allow adding a gitlink to the index without\n> anything else.  And then this step could use \"git add -f\" (or\n> whategver the overriding mechanism) instead of \"git submodule add\",\n> without changing the expected diff output.\n>\n> Would such a tweak make this step better?  I dunno.\n\nThe other side of the coin is that the tests that were touched by\nthe previous step were not testing half of what \"submodule add\" is\ndoing.  Not all the \"let's add submodule here\" test may not have to\nverify the resulting .gitmodules file (e.g. ones that want to see\nthe low-level diff machinery works correctly by taking output from\n\"git diff --cached --raw\" would be primarily interested in what\nhappens to the index and not to .gitmodules at all), but some of\nthem should.  A rough rule of thumb might be that the tests that are\nabout \"submodules\" should care what \".gitmodules\" has, while the\ntests tare are about \"gitlink\" should not.  It might even make sense\nto use \"add -f\" (or whatever override to allow adding a gitlink only\nto the index without touching .gitmodules and other things), not\n\"submodule add\", for the latter class of tests.\n\nThanks.\n\n\n"},{"id":"472041","messageId":"xmqqilg57zxq.fsf@gitster.g","threadId":"59235","inReplyTo":"Y+qgwHx52DSAfsEb@coredump.intra.peff.net","subject":"Re: [RFC PATCH 6/6] add: reject nested repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-14T02:17:53Z","receivedAt":"2023-02-14T02:17:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>>  \"\tgit rm --cached %s\\n\"\n>>  \"\\n\"\n>> -\"See \\\"git help submodule\\\" for more information.\"\n>> +\"See \\\"git help submodule\\\" for more information.\\n\"\n>> +\"\\n\"\n>> +\"If you cannot use submodules, you may bypass this check with:\\n\"\n>> +\"\\n\"\n>> +\"\tgit add --no-warn-embedded-repo %s\\n\"\n>>  );\n>\n> I was a little surprised by this hunk, but I guess if we are going to\n> block the user's operation from completing, we might want to tell them\n> how to get around it. But it seems odd to me that the instructions to\n> \"git rm --cached\" the submodule remain. If this situation is now an\n> error and not a warning, there is nothing to roll back from the index,\n> since we will have bailed before writing it.\n>\n> If we are going to start recommending --no-warn-embedded-repo here,\n> would we want to promote it from being OPT_HIDDEN_BOOL()? We do document\n> it in the manpage, but just omit it from the \"-h\" output, since it\n> should be rarely used. Maybe it is OK to stay that way; you don't need\n> it until you run into this situation, at which point the advice\n> hopefully has guided you in the right direction.\n\nIf we are keeping the escape hatch, it would make sense to actually\nuse that escape hatch to protect existing \"git add\" with that,\ninstead of turning them into \"git submodule add\" and then adjust the\ntests for the consequences (i.e. \"submodule add\" does more than what\n\"git add [--no-warn-embedded-repo]\" would), at least for these tests\nin [3,4,5/6].  \n\nAlso I do not think it is too late for a more natural UI, e.g.\n\"--allow-embedded-repo=[yes/no/warn]\", to deprecate the\n\"--[no-]warn-*\" option.\n"},{"id":"472057","messageId":"Y+ux3DEd/p5emFWs@coredump.intra.peff.net","threadId":"59235","inReplyTo":"xmqqilg57zxq.fsf@gitster.g","subject":"Re: [RFC PATCH 6/6] add: reject nested repositories","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-02-14T16:07:56Z","receivedAt":"2023-02-14T16:08:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 13, 2023 at 06:17:53PM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> >>  \"\tgit rm --cached %s\\n\"\n> >>  \"\\n\"\n> >> -\"See \\\"git help submodule\\\" for more information.\"\n> >> +\"See \\\"git help submodule\\\" for more information.\\n\"\n> >> +\"\\n\"\n> >> +\"If you cannot use submodules, you may bypass this check with:\\n\"\n> >> +\"\\n\"\n> >> +\"\tgit add --no-warn-embedded-repo %s\\n\"\n> >>  );\n> >\n> > I was a little surprised by this hunk, but I guess if we are going to\n> > block the user's operation from completing, we might want to tell them\n> > how to get around it. But it seems odd to me that the instructions to\n> > \"git rm --cached\" the submodule remain. If this situation is now an\n> > error and not a warning, there is nothing to roll back from the index,\n> > since we will have bailed before writing it.\n> >\n> > If we are going to start recommending --no-warn-embedded-repo here,\n> > would we want to promote it from being OPT_HIDDEN_BOOL()? We do document\n> > it in the manpage, but just omit it from the \"-h\" output, since it\n> > should be rarely used. Maybe it is OK to stay that way; you don't need\n> > it until you run into this situation, at which point the advice\n> > hopefully has guided you in the right direction.\n> \n> If we are keeping the escape hatch, it would make sense to actually\n> use that escape hatch to protect existing \"git add\" with that,\n> instead of turning them into \"git submodule add\" and then adjust the\n> tests for the consequences (i.e. \"submodule add\" does more than what\n> \"git add [--no-warn-embedded-repo]\" would), at least for these tests\n> in [3,4,5/6].\n\nGood point. I did not really look at the test modifications, but\nanywhere that is triggering the current warning is arguably a good spot\nto be using --no-warn-embedded-repo already. It is simply that the test\ndid not bother to look at their noisy stderr. And such a modification is\nobviously correct, as there are no further implications for the test.\n\n> Also I do not think it is too late for a more natural UI, e.g.\n> \"--allow-embedded-repo=[yes/no/warn]\", to deprecate the\n> \"--[no-]warn-*\" option.\n\nTrue. We have to keep the existing form for backwards compatibility, but\nwe can certainly add a new one.\n\nI kind of doubt that --allow-embedded-repo=warn is useful, though. If a\ncaller knows what it is doing is OK, then it would say \"yes\". And\notherwise, you'd want \"no\". There is no situation where a caller is\nunsure.\n\n-Peff\n"},{"id":"472059","messageId":"xmqqr0us6we1.fsf@gitster.g","threadId":"59235","inReplyTo":"Y+ux3DEd/p5emFWs@coredump.intra.peff.net","subject":"Re: [RFC PATCH 6/6] add: reject nested repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-14T16:32:06Z","receivedAt":"2023-02-14T16:32:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>> If we are keeping the escape hatch, it would make sense to actually\n>> use that escape hatch to protect existing \"git add\" with that,\n>> instead of turning them into \"git submodule add\" and then adjust the\n>> tests for the consequences (i.e. \"submodule add\" does more than what\n>> \"git add [--no-warn-embedded-repo]\" would), at least for these tests\n>> in [3,4,5/6].\n>\n> Good point. I did not really look at the test modifications, but\n> anywhere that is triggering the current warning is arguably a good spot\n> to be using --no-warn-embedded-repo already. It is simply that the test\n> did not bother to look at their noisy stderr. And such a modification is\n> obviously correct, as there are no further implications for the test.\n\nI did not mean that no \"git add\" that create a gitlink in existing\ntests should be made into \"git submodule add\".  The ones that\nclearly wanted to set up tests to see what happens in a top-level\nwith a subproject may become more realistic tests by switching to\n\"git submodule add\" and updating the expected \"git diff HEAD\" output\nto include a newly created .gitmodules file.  But some of the tests\nare merely to see what happens with an index with a gitlink in it,\nand \"add --no-warn\" would be more appropriate for them.\n\n>> Also I do not think it is too late for a more natural UI, e.g.\n>> \"--allow-embedded-repo=[yes/no/warn]\", to deprecate the\n>> \"--[no-]warn-*\" option.\n>\n> True. We have to keep the existing form for backwards compatibility, but\n> we can certainly add a new one.\n>\n> I kind of doubt that --allow-embedded-repo=warn is useful, though. If a\n> caller knows what it is doing is OK, then it would say \"yes\". And\n> otherwise, you'd want \"no\". There is no situation where a caller is\n> unsure.\n\nYeah, if the default becomes \"no\", then there isn't much point,\nother than just for completeness, to have \"warn\" as a choice.\n\nThanks.\n"},{"id":"472072","messageId":"CAFySSZBAXCGTEhTK+rpLaZz4_RhdEDV5e5QewUwN-LHgSOTe2g@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqk00lbc8k.fsf@gitster.g","subject":"Re: [RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-14T19:56:50Z","receivedAt":"2023-02-14T19:57:04Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Mon, Feb 13, 2023 at 11:23 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > hashmap_put returns a pointer if the key was found and subsequently\n> > replaced. Free this pointer so it isn't leaked.\n> >\n> > Signed-off-by: Calvin Wan <calvinwan@google.com>\n> > ---\n> >  submodule-config.c | 4 +++-\n> >  1 file changed, 3 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/submodule-config.c b/submodule-config.c\n> > index 4dc61b3a78..90cab34568 100644\n> > --- a/submodule-config.c\n> > +++ b/submodule-config.c\n> > @@ -128,9 +128,11 @@ static void cache_put_path(struct submodule_cache *cache,\n> >       unsigned int hash = hash_oid_string(&submodule->gitmodules_oid,\n> >                                           submodule->path);\n> >       struct submodule_entry *e = xmalloc(sizeof(*e));\n> > +     struct hashmap_entry *replaced;\n> >       hashmap_entry_init(&e->ent, hash);\n> >       e->config = submodule;\n> > -     hashmap_put(&cache->for_path, &e->ent);\n> > +     replaced = hashmap_put(&cache->for_path, &e->ent);\n> > +     free(replaced);\n> >  }\n>\n> Out of curiosity, I've checked all the grep hits from hashmap_put()\n> in the codebase and this seems to be the only one.  Everybody else\n> either calls hashmap_put() only after hashmap_get() sees that there\n> is no existing one, or unconditionally calls hashmap_put() and dies\n> if an earlier registration is found.\n>\n> The callers of oidmap_put() in sequencer.c I didn't check.  There\n> might be similar leaks there, or they may be safe---I dunno.  But\n> all other callers of oidmap_put() also seem to be safe.\n>\n> Back to the patch itself.  The only caller of this function does\n>\n>         if (submodule->path) {\n>                 cache_remove_path(me->cache, submodule);\n>                 free(submodule->path);\n>         }\n>         submodule->path = xstrdup(value);\n>         cache_put_path(me->cache, submodule);\n>\n> It is curious how the same submodule->path is occupied by more than\n> one submodule?  Isn't that a configuration error we want to report\n> to the user somehow (not necessarily error/die), instead of silently\n> replacing with the \"last one wins\" precedence?\n>\n> Assuming that the \"last one wins\" is the sensible thing to do, the\n> change proposed by this patch does seem reasonable way to plug the\n> leak.\n\nSwapping this functionality to \"first one wins\" or erroring out breaks many\ntests that are setup improperly. If we continue with the \"last one wins\"\nprecedence, then a warning and documentation should be added. We\ndefinitely should not swap it to \"first one wins\" -- one doesn't make sense\nthan the other, but \"last one wins\" at least has precedence. If we choose\nto error out during config parsing when duplicated submodule paths are\ndetected, then those respective tests will also need to be updated.\n\nI'm leaning towards leaving the functionality as is since a user would\nhave to manually edit the .gitmodules file to get into the state and is\nprotected from it with `git submodule add`. What do you think about\nadding a warning and possibly documentation?\n"},{"id":"472073","messageId":"CAFySSZAYNtatNKnRuG8ZNeSr+KAU04JRMUdLe+W+eeNtzW+r=Q@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqedqtbbf4.fsf@gitster.g","subject":"Re: [RFC PATCH 2/6] t4041, t4060: modernize test style","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-14T20:22:35Z","receivedAt":"2023-02-14T20:22:53Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"> > -test_create_repo sm1 &&\n> > -add_file . foo >/dev/null\n> > -\n> > -head1=$(add_file sm1 foo1 foo2)\n> > -fullhead1=$(cd sm1; git rev-parse --verify HEAD)\n> > +test_expect_success 'setup' '\n> > +     test_create_repo sm1 &&\n> > +     add_file . foo >/dev/null &&\n>\n> Now this is inside test_expect_success, redirection to /dev/null is\n> unnecessary.\n\nack.\n\n>\n> > +     head1=$(add_file sm1 foo1 foo2) &&\n> > +     fullhead1=$(cd sm1 && git rev-parse --verify HEAD)\n> > +'\n>\n> Or \"fullhead1=$(git -C sm1 rev-parse ...)\".\n>\n> Both of the above can be ignored if we are trying to be a strict\n> rewrite of the original, but moving code inside test_expect_success\n> block is a large enough change that there may not be much point in\n> avoiding such an obvious modernization \"while at it\".\n\nI agree, will fix.\n\n>\n> > -rm sm2\n> > -mv sm2-bak sm2\n> > -\n> >  test_expect_success 'setup nested submodule' '\n> > +     rm sm2 &&\n> > +     mv sm2-bak sm2 &&\n>\n> To me, this looks more like something test_when_finished in the test\n> that wanted not to have sm2 (i.e. \"deleted submodule with .git file\")\n> should have done as part of its own clean-up.\n>\n> There certainly can be two schools of thought when it comes to how to\n> arrange the precondition of subsequent tests.  More modern tests tend\n> to clean after themselves by reverting the damage they made to the\n> environment inside test_when_finished in themselves.  This one, as\n> the posted patch does, goes to the other extreme and forces the\n> subsequent test to undo the damage done by the previous ones.\n>\n> The latter approach has two major downsides.  It would not work if\n> the tester wants to skip an earlier step, or if an earlier step\n> failed to cause the expected damage this step wants to undo.  The\n> correctness of \"what we should see as sm2 here must be in sm2-bak\n> because we know an earlier step should have moved it there\" can\n> easily be broken.  It also makes it harder to update the earlier\n> step to cause different damage to the environment---the \"undoing the\n> damage done by the previous step(s)\" done as early parts of this\n> step also needs to be updated.\n>\n> Whichever approach we pick to use in each script, it would be better\n> to stick to one philosophy, and if we can make each step revert the\n> damage it caused when it is done, that would be nice.\n>\n> > -mv sm2-bak sm2\n> > +test_expect_success 'submodule cleanup' '\n> > +     mv sm2-bak sm2\n> > +'\n> >\n> >  test_done\n>\n> Likewise.\n\nack. Swapping to test_when_finished\n"},{"id":"472075","messageId":"xmqqa61g550j.fsf@gitster.g","threadId":"59235","inReplyTo":"CAFySSZBAXCGTEhTK+rpLaZz4_RhdEDV5e5QewUwN-LHgSOTe2g@mail.gmail.com","subject":"Re: [RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-14T21:08:44Z","receivedAt":"2023-02-14T21:08:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n>> Assuming that the \"last one wins\" is the sensible thing to do, the\n>> change proposed by this patch does seem reasonable way to plug the\n>> leak.\n>\n> Swapping this functionality to \"first one wins\" or erroring out breaks many\n> tests that are setup improperly. If we continue with the \"last one wins\"\n> precedence, then a warning and documentation should be added. We\n> definitely should not swap it to \"first one wins\" -- one doesn't make sense\n> than the other, but \"last one wins\" at least has precedence. If we choose\n> to error out during config parsing when duplicated submodule paths are\n> detected, then those respective tests will also need to be updated.\n\nThese tests expect the same submodule to be registered at different\npaths?  Is that a set-up that is expected to happen commonly in real\nlife?  If so, yes, the current behaviour needs to be kept (with some\ndocumentation to explain why it makes sense and how it is usefully\nused).  If not, these tests may need to be updated to test scenarios\nthat are closer to the real life, I guess, plus an additional test\nthat makes sure such a .gitmodules file is diagnosed as an error\nwith the code to do that some time in the future.\n"},{"id":"472078","messageId":"CAFySSZD9BZA9Qa5Z5KQymkowB9YtasUnNMehtA1feg43UsfwFw@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqa61g550j.fsf@gitster.g","subject":"Re: [RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-14T21:39:48Z","receivedAt":"2023-02-14T21:40:03Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Tue, Feb 14, 2023 at 1:08 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> >> Assuming that the \"last one wins\" is the sensible thing to do, the\n> >> change proposed by this patch does seem reasonable way to plug the\n> >> leak.\n> >\n> > Swapping this functionality to \"first one wins\" or erroring out breaks many\n> > tests that are setup improperly. If we continue with the \"last one wins\"\n> > precedence, then a warning and documentation should be added. We\n> > definitely should not swap it to \"first one wins\" -- one doesn't make sense\n> > than the other, but \"last one wins\" at least has precedence. If we choose\n> > to error out during config parsing when duplicated submodule paths are\n> > detected, then those respective tests will also need to be updated.\n>\n> These tests expect the same submodule to be registered at different\n> paths?  Is that a set-up that is expected to happen commonly in real\n> life?  If so, yes, the current behaviour needs to be kept (with some\n> documentation to explain why it makes sense and how it is usefully\n> used).  If not, these tests may need to be updated to test scenarios\n> that are closer to the real life, I guess, plus an additional test\n> that makes sure such a .gitmodules file is diagnosed as an error\n> with the code to do that some time in the future.\n\nIf you look at t4027-diff-submodule.sh:git diff HEAD with dirty submodule\n(work tree, refs match) [.gitmodules], it's two different submodules\npointing to the same path (or more precisely a second submodule is\nmanually added to .gitmodules with a path to the first submodule). This\nis a setup that is not expected to happen commonly in real life so\nupdating this test makes sense to me.\n"},{"id":"472082","messageId":"CAFySSZDU0NG5Bod=5soNKXfiN08y2jCKYwdVO2Feo2bDGQU2gQ@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqr0us6we1.fsf@gitster.g","subject":"Re: [RFC PATCH 6/6] add: reject nested repositories","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-14T21:45:15Z","receivedAt":"2023-02-14T21:45:30Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Tue, Feb 14, 2023 at 8:32 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Jeff King <peff@peff.net> writes:\n>\n> >> If we are keeping the escape hatch, it would make sense to actually\n> >> use that escape hatch to protect existing \"git add\" with that,\n> >> instead of turning them into \"git submodule add\" and then adjust the\n> >> tests for the consequences (i.e. \"submodule add\" does more than what\n> >> \"git add [--no-warn-embedded-repo]\" would), at least for these tests\n> >> in [3,4,5/6].\n> >\n> > Good point. I did not really look at the test modifications, but\n> > anywhere that is triggering the current warning is arguably a good spot\n> > to be using --no-warn-embedded-repo already. It is simply that the test\n> > did not bother to look at their noisy stderr. And such a modification is\n> > obviously correct, as there are no further implications for the test.\n>\n> I did not mean that no \"git add\" that create a gitlink in existing\n> tests should be made into \"git submodule add\".  The ones that\n> clearly wanted to set up tests to see what happens in a top-level\n> with a subproject may become more realistic tests by switching to\n> \"git submodule add\" and updating the expected \"git diff HEAD\" output\n> to include a newly created .gitmodules file.  But some of the tests\n> are merely to see what happens with an index with a gitlink in it,\n> and \"add --no-warn\" would be more appropriate for them.\n\nI'll take another pass into the modified tests from previous patches\nand pick out ones that are not specifically submodule related tests.\n\n> >> Also I do not think it is too late for a more natural UI, e.g.\n> >> \"--allow-embedded-repo=[yes/no/warn]\", to deprecate the\n> >> \"--[no-]warn-*\" option.\n> >\n> > True. We have to keep the existing form for backwards compatibility, but\n> > we can certainly add a new one.\n> >\n> > I kind of doubt that --allow-embedded-repo=warn is useful, though. If a\n> > caller knows what it is doing is OK, then it would say \"yes\". And\n> > otherwise, you'd want \"no\". There is no situation where a caller is\n> > unsure.\n>\n> Yeah, if the default becomes \"no\", then there isn't much point,\n> other than just for completeness, to have \"warn\" as a choice.\n\nI don't see a point for \"warn\" as well. The default \"no\" case should\ncarry over part of the deprecated warning from before.\n"},{"id":"472086","messageId":"xmqqilg352og.fsf@gitster.g","threadId":"59235","inReplyTo":"CAFySSZD9BZA9Qa5Z5KQymkowB9YtasUnNMehtA1feg43UsfwFw@mail.gmail.com","subject":"Re: [RFC PATCH 1/6] leak fix: cache_put_path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-14T21:59:11Z","receivedAt":"2023-02-14T21:59:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> If you look at t4027-diff-submodule.sh:git diff HEAD with dirty submodule\n> (work tree, refs match) [.gitmodules], it's two different submodules\n> pointing to the same path (or more precisely a second submodule is\n> manually added to .gitmodules with a path to the first submodule). This\n> is a setup that is not expected to happen commonly in real life so\n> updating this test makes sense to me.\n\nThanks for double checking.  If it is a configuration that is an\nerror, then we would want to notice it eventually (probably outside\nthe scope of this series), and before that happens, I agree that\nmodifying the test to avoid such an errnoneous scenario would be a\nvery good idea---otherwise we'd be pretending that such a scenario\nis a supported configuration somehow and misleading developers and\nusers.\n\nThanks.\n\n"},{"id":"472852","messageId":"20230228185253.2356546-1-calvinwan@google.com","threadId":"59235","inReplyTo":"20230213182134.2173280-1-calvinwan@google.com","subject":"[PATCH v2 0/6] add: block invalid submodules","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:52:53Z","receivedAt":"2023-02-28T18:53:08Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"A couple of significant changes were made since the RFC. From the\nfeedback gathered it seems like the idea of this series is worth\npursuing -- thanks Peff and Junio for the reviews!\n\nIn the initial RFC, we continued using `--no-warn-embedded-repo` to\nallow the user to add an embedded repo, but the naming of that option\nwas not ideal. This reroll adds `--allow-embedded-repo` and deprecates\n`--no-warn-embedded-repo`.\n\nWhile I initially claimed that there were incorrectly setup .gitmodules\ntests with duplicate paths, it turns out that was caused by patch 4/6 of\nthis series. I added a new patch (see 5/6) that fixes the issue.\nSubsequently, this means that the memory leak does not occur any more\n(maybe I should still include that patch -- it's an edge case that comes\nfrom a manually misconfigured .gitmodules).\n\nLastly I cleaned up the advice message and some of the tests --\nreplacing `git add` with `git submodule add` only in submodule specific\ncases and some style cleanups.\n\nCalvin Wan (1):\n  tests: remove duplicate .gitmodules path\n\nJosh Steadmon (5):\n  t4041, t4060: modernize test style\n  tests: Use `git submodule add` instead of `git add`\n  tests: use `git submodule add` and fix expected diffs\n  tests: use `git submodule add` and fix expected status\n  add: reject nested repositories\n\n Documentation/git-add.txt                    |  15 +-\n builtin/add.c                                |  37 ++-\n builtin/submodule--helper.c                  |   4 +-\n t/t0008-ignores.sh                           |   2 +-\n t/t2013-checkout-submodule.sh                |   4 +-\n t/t2103-update-index-ignore-missing.sh       |   2 +-\n t/t2107-update-index-basic.sh                |   2 +-\n t/t3040-subprojects-basic.sh                 |   5 +-\n t/t3050-subprojects-fetch.sh                 |   3 +-\n t/t3404-rebase-interactive.sh                |   3 +-\n t/t3701-add-interactive.sh                   |   5 +-\n t/t4010-diff-pathspec.sh                     |   2 +-\n t/t4020-diff-external.sh                     |   2 +-\n t/t4027-diff-submodule.sh                    |  58 ++---\n t/t4035-diff-quiet.sh                        |   2 +-\n t/t4041-diff-submodule-option.sh             | 232 +++++++++++++----\n t/t4060-diff-submodule-option-diff-format.sh | 226 ++++++++++++-----\n t/t5531-deep-submodule-push.sh               |   4 +-\n t/t6416-recursive-corner-cases.sh            |  12 +-\n t/t6430-merge-recursive.sh                   |   2 +-\n t/t6437-submodule-merge.sh                   |  12 +-\n t/t7400-submodule-basic.sh                   |   4 +-\n t/t7401-submodule-summary.sh                 |   4 +-\n t/t7402-submodule-rebase.sh                  |   2 +-\n t/t7412-submodule-absorbgitdirs.sh           |   2 +-\n t/t7414-submodule-mistakes.sh                |  29 ++-\n t/t7450-bad-git-dotfiles.sh                  |   2 +-\n t/t7506-status-submodule.sh                  |  15 +-\n t/t7508-status.sh                            | 248 ++++++++++++-------\n 29 files changed, 649 insertions(+), 291 deletions(-)\n\nRange-diff against v1:\n1:  34eacaabbd < -:  ---------- leak fix: cache_put_path\n2:  2da941fc59 ! 1:  3efc25bf0e t4041, t4060: modernize test style\n    @@ Commit message\n         easier to diagnose, because errors will caught immediately rather than\n         in later unrelated test_expect blocks.\n     \n    +    While at it, have tests clean up after themselves with\n    +    test_when_finished and fix other minor style issues.\n    +\n         Signed-off-by: Josh Steadmon <steadmon@google.com>\n         Signed-off-by: Calvin Wan <calvinwan@google.com>\n     \n    @@ t/t4041-diff-submodule-option.sh: commit_file () {\n     -fullhead1=$(cd sm1; git rev-parse --verify HEAD)\n     +test_expect_success 'setup' '\n     +\ttest_create_repo sm1 &&\n    -+\tadd_file . foo >/dev/null &&\n    ++\tadd_file . foo &&\n     +\thead1=$(add_file sm1 foo1 foo2) &&\n    -+\tfullhead1=$(cd sm1 && git rev-parse --verify HEAD)\n    ++\tfullhead1=$(git -C sm1 rev-parse --verify HEAD)\n     +'\n      \n      test_expect_success 'added submodule' '\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'modified submodule(forwar\n      \n     -fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n      test_expect_success 'modified submodule(forward) --submodule=short' '\n    -+\tfullhead2=$(cd sm1 && git rev-parse --verify HEAD) &&\n    ++\tfullhead2=$(git -C sm1 rev-parse --verify HEAD) &&\n      \tgit diff --submodule=short >actual &&\n      \tcat >expected <<-EOF &&\n      \tdiff --git a/sm1 b/sm1\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'modified submodule(backwa\n      \n      test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n      \tgit diff --submodule=log --cached >actual &&\n    +@@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n    + '\n    + \n    + test_expect_success 'typechanged submodule(submodule->blob)' '\n    ++\ttest_when_finished rm -rf sm1 &&\n    + \tgit diff --submodule=log >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tdiff --git a/sm1 b/sm1\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(submodule->blob)' '\n      \ttest_cmp expected actual\n      '\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(sub\n     -rm -rf sm1 &&\n     -git checkout-index sm1\n      test_expect_success 'typechanged submodule(submodule->blob)' '\n    -+\trm -rf sm1 &&\n    ++\ttest_when_finished rm -f sm1 &&\n     +\tgit checkout-index sm1 &&\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(sub\n     -head6=$(add_file sm1 foo6 foo7)\n     -fullhead6=$(cd sm1; git rev-parse --verify HEAD)\n      test_expect_success 'nonexistent commit' '\n    -+\trm -f sm1 &&\n     +\ttest_create_repo sm1 &&\n     +\thead6=$(add_file sm1 foo6 foo7) &&\n    -+\tfullhead6=$(cd sm1 && git rev-parse --verify HEAD) &&\n    ++\tfullhead6=$(git -C sm1 rev-parse --verify HEAD) &&\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \tcat >expected <<-EOF &&\n      \tSubmodule sm1 $head4...$head6 (commits not present)\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(blo\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \ttest_must_be_empty actual\n      '\n    +@@ t/t4041-diff-submodule-option.sh: test_expect_success 'submodule contains untracked and modified content (dirty ig\n    + '\n    + \n    + test_expect_success 'submodule contains untracked and modified content (all ignored)' '\n    ++\ttest_when_finished rm -f sm1/new-file &&\n    + \techo new > sm1/foo6 &&\n    + \tgit diff-index -p --ignore-submodules --submodule=log HEAD >actual &&\n    + \ttest_must_be_empty actual\n    + '\n    + \n    + test_expect_success 'submodule contains modified content' '\n    +-\trm -f sm1/new-file &&\n    + \tgit diff-index -p --submodule=log HEAD >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tSubmodule sm1 contains modified content\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'submodule contains modified content' '\n      \ttest_cmp expected actual\n      '\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'submodule contains modifi\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \tcat >expected <<-EOF &&\n      \tSubmodule sm1 $head6..$head8:\n    +@@ t/t4041-diff-submodule-option.sh: test_expect_success 'modified submodule contains untracked and modified content\n    + '\n    + \n    + test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '\n    ++\ttest_when_finished rm -f sm1/new-file &&\n    + \techo modification >> sm1/foo6 &&\n    + \tgit diff-index -p --ignore-submodules --submodule=log HEAD >actual &&\n    + \ttest_must_be_empty actual\n    + '\n    + \n    + test_expect_success 'modified submodule contains modified content' '\n    +-\trm -f sm1/new-file &&\n    ++\ttest_when_finished rm -rf sm1 &&\n    + \tgit diff-index -p --submodule=log HEAD >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tSubmodule sm1 contains modified content\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'modified submodule contains modified content' '\n      \ttest_cmp expected actual\n      '\n      \n     -rm -rf sm1\n      test_expect_success 'deleted submodule' '\n    -+\trm -rf sm1 &&\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    - \tSubmodule sm1 $head6...0000000 (submodule deleted)\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'path filter' '\n      \ttest_cmp expected actual\n      '\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'given commit --submodule'\n     -fullhead7=$(cd sm2; git rev-parse --verify HEAD)\n     -\n      test_expect_success 'given commit --submodule=short' '\n    -+\tfullhead7=$(cd sm2 && git rev-parse --verify HEAD) &&\n    ++\tfullhead7=$(git -C sm2 rev-parse --verify HEAD) &&\n      \tgit diff-index -p --submodule=short HEAD^ >actual &&\n      \tcat >expected <<-EOF &&\n      \tdiff --git a/sm1 b/sm1\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified subm\n      \n     -fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n      test_expect_success 'modified submodule(forward) --submodule=short' '\n    -+\tfullhead2=$(cd sm1 && git rev-parse --verify HEAD) &&\n    ++\tfullhead2=$(git -C sm1 rev-parse --verify HEAD) &&\n      \tgit diff --submodule=short >actual &&\n      \tcat >expected <<-EOF &&\n      \tdiff --git a/sm1 b/sm1\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified subm\n      test_expect_success 'modified submodule(backward)' '\n     +\tcommit_file sm1 &&\n     +\thead3=$(\n    -+\t\tcd sm1 &&\n    -+\t\tgit reset --hard HEAD~2 >/dev/null &&\n    -+\t\tgit rev-parse --short --verify HEAD\n    ++\t\tgit -C sm1 reset --hard HEAD~2 >/dev/null &&\n    ++\t\tgit -C sm1 rev-parse --short --verify HEAD\n     +\t) &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified subm\n      \n      test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n      \tgit diff --submodule=diff --cached >actual &&\n    +@@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n    + '\n    + \n    + test_expect_success 'typechanged submodule(submodule->blob)' '\n    ++\ttest_when_finished rm -rf sm1 &&\n    + \tgit diff --submodule=diff >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tdiff --git a/sm1 b/sm1\n     @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged submodule(submodule->blob)' '\n      \tdiff_cmp expected actual\n      '\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged s\n     -rm -rf sm1 &&\n     -git checkout-index sm1\n      test_expect_success 'typechanged submodule(submodule->blob)' '\n    -+\trm -rf sm1 &&\n    ++\ttest_when_finished rm -f sm1 &&\n     +\tgit checkout-index sm1 &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged s\n     -test_create_repo sm1 &&\n     -head6=$(add_file sm1 foo6 foo7)\n      test_expect_success 'nonexistent commit' '\n    -+\trm -f sm1 &&\n     +\ttest_create_repo sm1 &&\n     +\thead6=$(add_file sm1 foo6 foo7) &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged s\n      \thead7=$(git -C sm1 rev-parse --short --verify HEAD) &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \ttest_must_be_empty actual\n    +@@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'submodule contains untracked and modified content (dirty ig\n    + '\n    + \n    + test_expect_success 'submodule contains untracked and modified content (all ignored)' '\n    ++\ttest_when_finished rm -f sm1/new-file &&\n    + \techo new > sm1/foo6 &&\n    + \tgit diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&\n    + \ttest_must_be_empty actual\n    + '\n    + \n    + test_expect_success 'submodule contains modified content' '\n    +-\trm -f sm1/new-file &&\n    + \tgit diff-index -p --submodule=diff HEAD >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tSubmodule sm1 contains modified content\n     @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'submodule contains modified content' '\n      \tdiff_cmp expected actual\n      '\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'submodule con\n     -(cd sm1; git commit -mchange foo6 >/dev/null) &&\n     -head8=$(cd sm1; git rev-parse --short --verify HEAD) &&\n      test_expect_success 'submodule is modified' '\n    -+\t(cd sm1 && git commit -mchange foo6 >/dev/null) &&\n    -+\thead8=$(cd sm1 && git rev-parse --short --verify HEAD) &&\n    ++\t(git -C sm1 commit -mchange foo6 >/dev/null) &&\n    ++\thead8=$(git -C sm1 rev-parse --short --verify HEAD) &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \tcat >expected <<-EOF &&\n      \tSubmodule sm1 $head7..$head8:\n    +@@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified submodule contains untracked and modified content\n    + '\n    + \n    + test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '\n    ++\ttest_when_finished rm -f sm1/new-file &&\n    + \techo modification >> sm1/foo6 &&\n    + \tgit diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&\n    + \ttest_must_be_empty actual\n    +@@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified submodule contains untracked and modified content\n    + \n    + # NOT OK\n    + test_expect_success 'modified submodule contains modified content' '\n    +-\trm -f sm1/new-file &&\n    ++\ttest_when_finished rm -rf sm1 &&\n    + \tgit diff-index -p --submodule=diff HEAD >actual &&\n    + \tcat >expected <<-EOF &&\n    + \tSubmodule sm1 contains modified content\n     @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'modified submodule contains modified content' '\n      \tdiff_cmp expected actual\n      '\n      \n     -rm -rf sm1\n      test_expect_success 'deleted submodule' '\n    -+\trm -rf sm1 &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    - \tSubmodule sm1 $head7...0000000 (submodule deleted)\n     @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'path filter' '\n      \tdiff_cmp expected actual\n      '\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'deleted submo\n     -echo submodule-to-blob>sm2\n     -\n      test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n    ++\ttest_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n     +\techo submodule-to-blob>sm2 &&\n      \tgit diff-index -p --submodule=diff HEAD >actual &&\n      \tcat >expected <<-EOF &&\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'typechanged(s\n     -mv sm2-bak sm2\n     -\n      test_expect_success 'setup nested submodule' '\n    -+\trm sm2 &&\n    -+\tmv sm2-bak sm2 &&\n      \tgit -c protocol.file.allow=always -C sm2 submodule add ../sm2 nested &&\n      \tgit -C sm2 commit -a -m \"nested sub\" &&\n    - \thead10=$(git -C sm2 rev-parse --short --verify HEAD)\n     @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'diff --submodule=diff recurses into nested submodules' '\n      \tdiff_cmp expected actual\n      '\n    @@ t/t4060-diff-submodule-option-diff-format.sh: test_expect_success 'diff --submod\n      test_expect_success 'diff --submodule=diff recurses into deleted nested submodules' '\n     +\t(cd sm2 && commit_file nested) &&\n     +\tcommit_file sm2 &&\n    -+\thead12=$(cd sm2 && git rev-parse --short --verify HEAD) &&\n    ++\thead12=$(git -C sm2 rev-parse --short --verify HEAD) &&\n     +\tmv sm2 sm2-bak &&\n      \tcat >expected <<-EOF &&\n      \tSubmodule sm1 $head7...0000000 (submodule deleted)\n3:  e1c7c2f63e ! 2:  a438f4072d tests: Use `git submodule add` instead of `git add`\n    @@ Commit message\n         Signed-off-by: Josh Steadmon <steadmon@google.com>\n         Signed-off-by: Calvin Wan <calvinwan@google.com>\n     \n    - ## t/t0008-ignores.sh ##\n    -@@ t/t0008-ignores.sh: test_expect_success 'setup' '\n    - \t\tgit add a &&\n    - \t\tgit commit -m\"commit in submodule\"\n    - \t) &&\n    --\tgit add a/submodule &&\n    -+\tgit submodule add ./a/submodule ./a/submodule &&\n    - \tcat <<-\\EOF >.gitignore &&\n    - \t\tone\n    - \t\tignored-*\n    -\n      ## t/t2013-checkout-submodule.sh ##\n     @@ t/t2013-checkout-submodule.sh: test_expect_success 'setup' '\n      \t(cd submodule &&\n    @@ t/t2103-update-index-ignore-missing.sh: test_expect_success basics '\n      \t\tgit commit -m \"sub initial\"\n      \t) &&\n     -\tgit add xyzzy &&\n    -+\tgit submodule add ./xyzzy &&\n    ++\tgit add ./xyzzy &&\n      \n      \ttest_tick &&\n      \tgit commit -m initial &&\n    @@ t/t4020-diff-external.sh: test_expect_success 'clean up crlf leftovers' '\n      \tgit commit -m \"add submodule\" &&\n      \t( cd sub && test_commit sub2 ) &&\n     \n    - ## t/t4035-diff-quiet.sh ##\n    -@@ t/t4035-diff-quiet.sh: test_expect_success 'git diff-index --cached HEAD^' '\n    - test_expect_success 'git diff-index --cached HEAD^' '\n    - \techo text >>b &&\n    - \techo 3 >c &&\n    -+\tgit submodule add ./test-outside/repo ./test-outside/repo &&\n    - \tgit add . &&\n    - \ttest_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt &&\n    - \ttest_line_count = 0 cnt\n    -\n      ## t/t5531-deep-submodule-push.sh ##\n     @@ t/t5531-deep-submodule-push.sh: test_expect_success setup '\n      \t\t\tgit add junk &&\n    @@ t/t6416-recursive-corner-cases.sh: test_expect_success 'setup conflicting entry\n      \n      \t\tgit checkout -b C A &&\n     \n    - ## t/t6430-merge-recursive.sh ##\n    -@@ t/t6430-merge-recursive.sh: test_expect_success 'merging with triple rename across D/F conflict' '\n    - \techo content3 >sub2/file3 &&\n    - \tmkdir simple &&\n    - \techo base >simple/bar &&\n    -+\tgit -c protocol.file.allow=always submodule add ./sym &&\n    - \tgit add -A &&\n    - \ttest_tick &&\n    - \tgit commit -m base &&\n    -\n      ## t/t6437-submodule-merge.sh ##\n     @@ t/t6437-submodule-merge.sh: test_expect_success setup '\n      \t git add file &&\n4:  a7630f5a4e ! 3:  336e095b38 tests: use `git submodule add` and fix expected diffs\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'typechanged submodule(sub\n      \tdiff --git a/sm1 b/sm1\n      \tnew file mode 100644\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'nonexistent commit' '\n    - \tfullhead6=$(cd sm1 && git rev-parse --verify HEAD) &&\n    + \tfullhead6=$(git -C sm1 rev-parse --verify HEAD) &&\n      \tgit diff-index -p --submodule=log HEAD >actual &&\n      \tcat >expected <<-EOF &&\n     +\tdiff --git a/.gitmodules b/.gitmodules\n    @@ t/t4041-diff-submodule-option.sh: test_expect_success 'given commit' '\n      \tSubmodule sm2 0000000...$head7 (new submodule)\n      \tEOF\n     @@ t/t4041-diff-submodule-option.sh: test_expect_success 'given commit --submodule=short' '\n    - \tfullhead7=$(cd sm2 && git rev-parse --verify HEAD) &&\n    + \tfullhead7=$(git -C sm2 rev-parse --verify HEAD) &&\n      \tgit diff-index -p --submodule=short HEAD^ >actual &&\n      \tcat >expected <<-EOF &&\n     +\tdiff --git a/.gitmodules b/.gitmodules\n5:  7182e1fb2f = 4:  40a4647ae3 tests: use `git submodule add` and fix expected status\n-:  ---------- > 5:  caa2f228a0 tests: remove duplicate .gitmodules path\n6:  6d2ef61fb4 ! 6:  28cb291edd add: reject nested repositories\n    @@ Commit message\n     \n         Due to this experience, we believe that Git's default behavior should be\n         changed to disallow adding embedded repositories. This commit changes\n    -    the existing warning into a fatal error while preserving the\n    -    `--no-warn-embedded-repo` flag as a way to bypass this check.\n    +    the existing warning into a fatal error, rewrites the advice given, and\n    +    deprecates `--no-warn-embedded-repo` in favor of `--allow-embedded-repo`\n    +    to bypass the fatal error.\n     \n         Signed-off-by: Josh Steadmon <steadmon@google.com>\n         Signed-off-by: Calvin Wan <calvinwan@google.com>\n     \n      ## Documentation/git-add.txt ##\n     @@ Documentation/git-add.txt: for \"git add --no-all <pathspec>...\", i.e. ignored removed files.\n    + \tbe ignored, no matter if they are already present in the work\n      \ttree or not.\n      \n    - --no-warn-embedded-repo::\n    +---no-warn-embedded-repo::\n     -\tBy default, `git add` will warn when adding an embedded\n    ++--allow-embedded-repo::\n     +\tBy default, `git add` will error out when adding an embedded\n      \trepository to the index without using `git submodule add` to\n     -\tcreate an entry in `.gitmodules`. This option will suppress the\n     -\twarning (e.g., if you are manually performing operations on\n    +-\tsubmodules).\n     +\tcreate an entry in `.gitmodules`. This option will allow the\n    -+\tembedded repository to be added and suppress the error.\n    -+\t(e.g., if you are manually performing operations on\n    - \tsubmodules).\n    ++\tembedded repository to be added. (e.g., if you are manually\n    ++\tperforming operations on submodules).\n    ++\n    ++--no-warn-embedded-repo::\n    ++\tThis option is deprecated in favor of '--add-embedded-repo'.\n    ++\tPassing this option still suppresses advice but does not bypass\n    ++\tthe error.\n      \n      --renormalize::\n    + \tApply the \"clean\" process freshly to all tracked files to\n     \n      ## builtin/add.c ##\n    -@@ builtin/add.c: static const char embedded_advice[] = N_(\n    +@@ builtin/add.c: N_(\"The following paths are ignored by one of your .gitignore files:\\n\");\n    + static int verbose, show_only, ignored_too, refresh_only;\n    + static int ignore_add_errors, intent_to_add, ignore_missing;\n    + static int warn_on_embedded_repo = 1;\n    ++static int allow_embedded_repo = 0;\n    + \n    + #define ADDREMOVE_DEFAULT 1\n    + static int addremove = ADDREMOVE_DEFAULT;\n    +@@ builtin/add.c: static struct option builtin_add_options[] = {\n    + \t\t   N_(\"override the executable bit of the listed files\")),\n    + \tOPT_HIDDEN_BOOL(0, \"warn-embedded-repo\", &warn_on_embedded_repo,\n    + \t\t\tN_(\"warn when adding an embedded repository\")),\n    ++\tOPT_HIDDEN_BOOL(0, \"allow-embedded-repo\", &allow_embedded_repo,\n    ++\t\t\tN_(\"allow adding an embedded repository\")),\n    + \tOPT_PATHSPEC_FROM_FILE(&pathspec_from_file),\n    + \tOPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),\n    + \tOPT_END(),\n    +@@ builtin/add.c: static int add_config(const char *var, const char *value, void *cb)\n    + }\n    + \n    + static const char embedded_advice[] = N_(\n    +-\"You've added another git repository inside your current repository.\\n\"\n    ++\"You attempted to add another git repository inside your current repository.\\n\"\n    + \"Clones of the outer repository will not contain the contents of\\n\"\n    + \"the embedded repository and will not know how to obtain it.\\n\"\n    + \"If you meant to add a submodule, use:\\n\"\n      \"\\n\"\n    - \"\tgit rm --cached %s\\n\"\n    + \"\tgit submodule add <url> %s\\n\"\n      \"\\n\"\n    --\"See \\\"git help submodule\\\" for more information.\"\n    +-\"If you added this path by mistake, you can remove it from the\\n\"\n    +-\"index with:\\n\"\n     +\"See \\\"git help submodule\\\" for more information.\\n\"\n    -+\"\\n\"\n    + \"\\n\"\n    +-\"\tgit rm --cached %s\\n\"\n     +\"If you cannot use submodules, you may bypass this check with:\\n\"\n    -+\"\\n\"\n    -+\"\tgit add --no-warn-embedded-repo %s\\n\"\n    + \"\\n\"\n    +-\"See \\\"git help submodule\\\" for more information.\"\n    ++\"\tgit add --allow-embedded-repo %s\\n\"\n      );\n      \n     -static void check_embedded_repo(const char *path)\n    @@ builtin/add.c: static const char embedded_advice[] = N_(\n      \tstruct strbuf name = STRBUF_INIT;\n      \tstatic int adviced_on_embedded_repo = 0;\n      \n    - \tif (!warn_on_embedded_repo)\n    +-\tif (!warn_on_embedded_repo)\n     -\t\treturn;\n    ++\tif (allow_embedded_repo)\n     +\t\tgoto cleanup;\n      \tif (!ends_with(path, \"/\"))\n     -\t\treturn;\n    @@ builtin/add.c: static const char embedded_advice[] = N_(\n     -\twarning(_(\"adding embedded git repository: %s\"), name.buf);\n     +\terror(_(\"cannot add embedded git repository: %s\"), name.buf);\n      \tif (!adviced_on_embedded_repo &&\n    - \t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n    --\t\tadvise(embedded_advice, name.buf, name.buf);\n    -+\t\tadvise(embedded_advice, name.buf, name.buf, name.buf);\n    +-\t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n    ++\t\twarn_on_embedded_repo &&\n    ++\t\tadvice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n    + \t\tadvise(embedded_advice, name.buf, name.buf);\n      \t\tadviced_on_embedded_repo = 1;\n      \t}\n      \n    @@ builtin/add.c: static int add_files(struct dir_struct *dir, int flags)\n      \t\tadvise_on_updating_sparse_paths(&matched_sparse_paths);\n      \t\texit_status = 1;\n     \n    + ## builtin/submodule--helper.c ##\n    +@@ builtin/submodule--helper.c: static void configure_added_submodule(struct add_data *add_data)\n    + \n    + \tadd_submod.git_cmd = 1;\n    + \tstrvec_pushl(&add_submod.args, \"add\",\n    +-\t\t     \"--no-warn-embedded-repo\", NULL);\n    ++\t\t     \"--allow-embedded-repo\", NULL);\n    + \tif (add_data->force)\n    + \t\tstrvec_push(&add_submod.args, \"--force\");\n    + \tstrvec_pushl(&add_submod.args, \"--\", add_data->sm_path, NULL);\n    +@@ builtin/submodule--helper.c: static int module_add(int argc, const char **argv, const char *prefix)\n    + \t\tcp.git_cmd = 1;\n    + \t\tcp.no_stdout = 1;\n    + \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n    +-\t\t\t     \"--no-warn-embedded-repo\", add_data.sm_path, NULL);\n    ++\t\t\t     \"--allow-embedded-repo\", add_data.sm_path, NULL);\n    + \t\tif ((ret = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {\n    + \t\t\tstrbuf_complete_line(&sb);\n    + \t\t\tfputs(sb.buf, stderr);\n    +\n    + ## t/t0008-ignores.sh ##\n    +@@ t/t0008-ignores.sh: test_expect_success 'setup' '\n    + \t\tgit add a &&\n    + \t\tgit commit -m\"commit in submodule\"\n    + \t) &&\n    +-\tgit add a/submodule &&\n    ++\tgit add --allow-embedded-repo a/submodule &&\n    + \tcat <<-\\EOF >.gitignore &&\n    + \t\tone\n    + \t\tignored-*\n    +\n    + ## t/t2103-update-index-ignore-missing.sh ##\n    +@@ t/t2103-update-index-ignore-missing.sh: test_expect_success basics '\n    + \t\tgit add file &&\n    + \t\tgit commit -m \"sub initial\"\n    + \t) &&\n    +-\tgit add ./xyzzy &&\n    ++\tgit add --allow-embedded-repo ./xyzzy &&\n    + \n    + \ttest_tick &&\n    + \tgit commit -m initial &&\n    +\n    + ## t/t4035-diff-quiet.sh ##\n    +@@ t/t4035-diff-quiet.sh: test_expect_success 'git diff-index --cached HEAD^' '\n    + test_expect_success 'git diff-index --cached HEAD^' '\n    + \techo text >>b &&\n    + \techo 3 >c &&\n    +-\tgit add . &&\n    ++\tgit add --allow-embedded-repo . &&\n    + \ttest_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt &&\n    + \ttest_line_count = 0 cnt\n    + '\n    +\n    + ## t/t6430-merge-recursive.sh ##\n    +@@ t/t6430-merge-recursive.sh: test_expect_success 'merging with triple rename across D/F conflict' '\n    + \techo content3 >sub2/file3 &&\n    + \tmkdir simple &&\n    + \techo base >simple/bar &&\n    +-\tgit add -A &&\n    ++\tgit add -A --allow-embedded-repo &&\n    + \ttest_tick &&\n    + \tgit commit -m base &&\n    + \n    +\n      ## t/t7400-submodule-basic.sh ##\n     @@ t/t7400-submodule-basic.sh: test_expect_success 'setup - repository in init subdirectory' '\n      test_expect_success 'setup - commit with gitlink' '\n      \techo a >a &&\n      \techo z >z &&\n     -\tgit add a init z &&\n    -+\tgit add --no-warn-embedded-repo a init z &&\n    ++\tgit add --allow-embedded-repo a init z &&\n      \tgit commit -m \"super commit 1\"\n      '\n      \n    @@ t/t7400-submodule-basic.sh: test_expect_success 'set up for relative path tests'\n      \t\t\ttest_commit foo\n      \t\t) &&\n     -\t\tgit add sub &&\n    -+\t\tgit add --no-warn-embedded-repo sub &&\n    ++\t\tgit add --allow-embedded-repo sub &&\n      \t\tgit config -f .gitmodules submodule.sub.path sub &&\n      \t\tgit config -f .gitmodules submodule.sub.url ../subrepo &&\n      \t\tcp .git/config pristine-.git-config &&\n    @@ t/t7412-submodule-absorbgitdirs.sh: test_expect_success 'absorb the git dir in a\n      \tgit init sub2 &&\n      \ttest_commit -C sub2 first &&\n     -\tgit add sub2 &&\n    -+\tgit add --no-warn-embedded-repo sub2 &&\n    ++\tgit add --allow-embedded-repo sub2 &&\n      \tgit commit -m superproject\n      '\n      \n    @@ t/t7414-submodule-mistakes.sh: test_expect_success 'create embedded repository'\n      '\n      \n     -test_expect_success '--no-warn-embedded-repo suppresses warning' '\n    -+test_expect_success '--no-warn-embedded-repo suppresses error message' '\n    ++test_expect_success '--allow-embedded-repo adds embedded repository and suppresses error message' '\n      \ttest_when_finished \"git rm --cached -f embed\" &&\n    - \tgit add --no-warn-embedded-repo embed 2>stderr &&\n    +-\tgit add --no-warn-embedded-repo embed 2>stderr &&\n     -\ttest_i18ngrep ! warning stderr\n    ++\tgit add --allow-embedded-repo embed 2>stderr &&\n     +\ttest_i18ngrep ! fatal stderr\n    ++'\n    ++\n    ++test_expect_success '--no-warn-embedded-repo dies and suppresses advice' '\n    ++\ttest_must_fail git add --no-warn-embedded-repo embed 2>stderr &&\n    ++\ttest_i18ngrep ! hint stderr &&\n    ++\ttest_i18ngrep fatal stderr\n      '\n      \n     -test_expect_success 'no warning when updating entry' '\n     +test_expect_success 'no error message when updating entry' '\n      \ttest_when_finished \"git rm --cached -f embed\" &&\n     -\tgit add embed &&\n    -+\tgit add --no-warn-embedded-repo embed &&\n    ++\tgit add --allow-embedded-repo embed &&\n      \tgit -C embed commit --allow-empty -m two &&\n      \tgit add embed 2>stderr &&\n     -\ttest_i18ngrep ! warning stderr\n    @@ t/t7414-submodule-mistakes.sh: test_expect_success 'create embedded repository'\n      '\n      \n     -test_expect_success 'submodule add does not warn' '\n    -+test_expect_success 'submodule add does not issue error message' '\n    ++test_expect_success 'submodule add neither fails nor issues error message' '\n      \ttest_when_finished \"git rm -rf submodule .gitmodules\" &&\n      \tgit -c protocol.file.allow=always \\\n      \t\tsubmodule add ./embed submodule 2>stderr &&\n    @@ t/t7450-bad-git-dotfiles.sh: test_expect_success 'git dirs of sibling submodules\n      \t\tgit clone . thing1 &&\n      \t\tgit clone . thing2 &&\n     -\t\tgit add .gitmodules thing1 thing2 &&\n    -+\t\tgit add --no-warn-embedded-repo .gitmodules thing1 thing2 &&\n    ++\t\tgit add --allow-embedded-repo .gitmodules thing1 thing2 &&\n      \t\ttest_tick &&\n      \t\tgit commit -m nested\n      \t) &&\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472853","messageId":"20230228185642.2357806-1-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 1/6] t4041, t4060: modernize test style","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:37Z","receivedAt":"2023-02-28T18:56:55Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nIn preparation for later changes, move setup code into test_expect\nblocks. Smaller sections are moved into existing blocks, while larger\nsections with a standalone purpose are given their own new blocks.\n\nThis makes sure that later changes that may break the test setup are\neasier to diagnose, because errors will caught immediately rather than\nin later unrelated test_expect blocks.\n\nWhile at it, have tests clean up after themselves with\ntest_when_finished and fix other minor style issues.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t4041-diff-submodule-option.sh             |  79 ++++++++-------\n t/t4060-diff-submodule-option-diff-format.sh | 101 +++++++++----------\n 2 files changed, 89 insertions(+), 91 deletions(-)\n\ndiff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\nindex 0c1502d4b0..2aa12243bd 100755\n--- a/t/t4041-diff-submodule-option.sh\n+++ b/t/t4041-diff-submodule-option.sh\n@@ -42,11 +42,12 @@ commit_file () {\n \tgit commit \"$@\" -m \"Commit $*\" >/dev/null\n }\n \n-test_create_repo sm1 &&\n-add_file . foo >/dev/null\n-\n-head1=$(add_file sm1 foo1 foo2)\n-fullhead1=$(cd sm1; git rev-parse --verify HEAD)\n+test_expect_success 'setup' '\n+\ttest_create_repo sm1 &&\n+\tadd_file . foo &&\n+\thead1=$(add_file sm1 foo1 foo2) &&\n+\tfullhead1=$(git -C sm1 rev-parse --verify HEAD)\n+'\n \n test_expect_success 'added submodule' '\n \tgit add sm1 &&\n@@ -99,10 +100,9 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head2=$(add_file sm1 foo3)\n-\n test_expect_success 'modified submodule(forward)' '\n+\tcommit_file sm1 &&\n+\thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head1..$head2:\n@@ -129,8 +129,8 @@ test_expect_success 'modified submodule(forward) --submodule' '\n \ttest_cmp expected actual\n '\n \n-fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'modified submodule(forward) --submodule=short' '\n+\tfullhead2=$(git -C sm1 rev-parse --verify HEAD) &&\n \tgit diff --submodule=short >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -144,14 +144,14 @@ test_expect_success 'modified submodule(forward) --submodule=short' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head3=$(\n-\tcd sm1 &&\n-\tgit reset --hard HEAD~2 >/dev/null &&\n-\tgit rev-parse --short --verify HEAD\n-)\n \n test_expect_success 'modified submodule(backward)' '\n+\tcommit_file sm1 &&\n+\thead3=$(\n+\t\tcd sm1 &&\n+\t\tgit reset --hard HEAD~2 >/dev/null &&\n+\t\tgit rev-parse --short --verify HEAD\n+\t) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2..$head3 (rewind):\n@@ -161,8 +161,8 @@ test_expect_success 'modified submodule(backward)' '\n \ttest_cmp expected actual\n '\n \n-head4=$(add_file sm1 foo4 foo5)\n test_expect_success 'modified submodule(backward and forward)' '\n+\thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2...$head4:\n@@ -174,13 +174,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n-mv sm1 sm1-bak &&\n-echo sm1 >sm1 &&\n-head5=$(git hash-object sm1 | cut -c1-7) &&\n-git add sm1 &&\n-rm -f sm1 &&\n-mv sm1-bak sm1\n+test_expect_success 'setup - change sm1 to a blob' '\n+\tcommit_file sm1 &&\n+\tmv sm1 sm1-bak &&\n+\techo sm1 >sm1 &&\n+\thead5=$(git hash-object sm1 | cut -c1-7) &&\n+\tgit add sm1 &&\n+\trm -f sm1 &&\n+\tmv sm1-bak sm1\n+'\n \n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=log --cached >actual &&\n@@ -198,6 +200,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n '\n \n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\ttest_when_finished rm -rf sm1 &&\n \tgit diff --submodule=log >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -212,9 +215,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \ttest_cmp expected actual\n '\n \n-rm -rf sm1 &&\n-git checkout-index sm1\n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\ttest_when_finished rm -f sm1 &&\n+\tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n@@ -229,11 +232,10 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \ttest_cmp expected actual\n '\n \n-rm -f sm1 &&\n-test_create_repo sm1 &&\n-head6=$(add_file sm1 foo6 foo7)\n-fullhead6=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'nonexistent commit' '\n+\ttest_create_repo sm1 &&\n+\thead6=$(add_file sm1 foo6 foo7) &&\n+\tfullhead6=$(git -C sm1 rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...$head6 (commits not present)\n@@ -241,8 +243,8 @@ test_expect_success 'nonexistent commit' '\n \ttest_cmp expected actual\n '\n \n-commit_file\n test_expect_success 'typechanged submodule(blob->submodule)' '\n+\tcommit_file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -257,8 +259,8 @@ test_expect_success 'typechanged submodule(blob->submodule)' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm1 &&\n test_expect_success 'submodule is up to date' '\n+\tcommit_file sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \ttest_must_be_empty actual\n '\n@@ -313,13 +315,13 @@ test_expect_success 'submodule contains untracked and modified content (dirty ig\n '\n \n test_expect_success 'submodule contains untracked and modified content (all ignored)' '\n+\ttest_when_finished rm -f sm1/new-file &&\n \techo new > sm1/foo6 &&\n \tgit diff-index -p --ignore-submodules --submodule=log HEAD >actual &&\n \ttest_must_be_empty actual\n '\n \n test_expect_success 'submodule contains modified content' '\n-\trm -f sm1/new-file &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 contains modified content\n@@ -327,9 +329,9 @@ test_expect_success 'submodule contains modified content' '\n \ttest_cmp expected actual\n '\n \n-(cd sm1; git commit -mchange foo6 >/dev/null) &&\n-head8=$(cd sm1; git rev-parse --short --verify HEAD) &&\n test_expect_success 'submodule is modified' '\n+\t(cd sm1 && git commit -mchange foo6 >/dev/null) &&\n+\thead8=$(cd sm1 && git rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head6..$head8:\n@@ -406,13 +408,14 @@ test_expect_success 'modified submodule contains untracked and modified content\n '\n \n test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '\n+\ttest_when_finished rm -f sm1/new-file &&\n \techo modification >> sm1/foo6 &&\n \tgit diff-index -p --ignore-submodules --submodule=log HEAD >actual &&\n \ttest_must_be_empty actual\n '\n \n test_expect_success 'modified submodule contains modified content' '\n-\trm -f sm1/new-file &&\n+\ttest_when_finished rm -rf sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 contains modified content\n@@ -422,7 +425,6 @@ test_expect_success 'modified submodule contains modified content' '\n \ttest_cmp expected actual\n '\n \n-rm -rf sm1\n test_expect_success 'deleted submodule' '\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n@@ -454,8 +456,8 @@ test_expect_success 'path filter' '\n \ttest_cmp expected actual\n '\n \n-commit_file sm2\n test_expect_success 'given commit' '\n+\tcommit_file sm2 &&\n \tgit diff-index -p --submodule=log HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n@@ -473,9 +475,8 @@ test_expect_success 'given commit --submodule' '\n \ttest_cmp expected actual\n '\n \n-fullhead7=$(cd sm2; git rev-parse --verify HEAD)\n-\n test_expect_success 'given commit --submodule=short' '\n+\tfullhead7=$(git -C sm2 rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=short HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\ndiff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh\nindex 97c6424cd5..a760ed5eb6 100755\n--- a/t/t4060-diff-submodule-option-diff-format.sh\n+++ b/t/t4060-diff-submodule-option-diff-format.sh\n@@ -138,10 +138,9 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head2=$(add_file sm1 foo3)\n-\n test_expect_success 'modified submodule(forward)' '\n+\tcommit_file sm1 &&\n+\thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head1..$head2:\n@@ -180,8 +179,8 @@ test_expect_success 'modified submodule(forward) --submodule' '\n \tdiff_cmp expected actual\n '\n \n-fullhead2=$(cd sm1; git rev-parse --verify HEAD)\n test_expect_success 'modified submodule(forward) --submodule=short' '\n+\tfullhead2=$(git -C sm1 rev-parse --verify HEAD) &&\n \tgit diff --submodule=short >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -195,14 +194,12 @@ test_expect_success 'modified submodule(forward) --submodule=short' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-head3=$(\n-\tcd sm1 &&\n-\tgit reset --hard HEAD~2 >/dev/null &&\n-\tgit rev-parse --short --verify HEAD\n-)\n-\n test_expect_success 'modified submodule(backward)' '\n+\tcommit_file sm1 &&\n+\thead3=$(\n+\t\tgit -C sm1 reset --hard HEAD~2 >/dev/null &&\n+\t\tgit -C sm1 rev-parse --short --verify HEAD\n+\t) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2..$head3 (rewind):\n@@ -224,8 +221,8 @@ test_expect_success 'modified submodule(backward)' '\n \tdiff_cmp expected actual\n '\n \n-head4=$(add_file sm1 foo4 foo5)\n test_expect_success 'modified submodule(backward and forward)' '\n+\thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head2...$head4:\n@@ -261,13 +258,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n-mv sm1 sm1-bak &&\n-echo sm1 >sm1 &&\n-head5=$(git hash-object sm1 | cut -c1-7) &&\n-git add sm1 &&\n-rm -f sm1 &&\n-mv sm1-bak sm1\n+test_expect_success 'setup - change sm1 to a blob' '\n+\tcommit_file sm1 &&\n+\tmv sm1 sm1-bak &&\n+\techo sm1 >sm1 &&\n+\thead5=$(git hash-object sm1 | cut -c1-7) &&\n+\tgit add sm1 &&\n+\trm -f sm1 &&\n+\tmv sm1-bak sm1\n+'\n \n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=diff --cached >actual &&\n@@ -306,6 +305,7 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n '\n \n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\ttest_when_finished rm -rf sm1 &&\n \tgit diff --submodule=diff >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -341,9 +341,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tdiff_cmp expected actual\n '\n \n-rm -rf sm1 &&\n-git checkout-index sm1\n test_expect_success 'typechanged submodule(submodule->blob)' '\n+\ttest_when_finished rm -f sm1 &&\n+\tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n@@ -358,10 +358,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tdiff_cmp expected actual\n '\n \n-rm -f sm1 &&\n-test_create_repo sm1 &&\n-head6=$(add_file sm1 foo6 foo7)\n test_expect_success 'nonexistent commit' '\n+\ttest_create_repo sm1 &&\n+\thead6=$(add_file sm1 foo6 foo7) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head4...$head6 (commits not present)\n@@ -369,8 +368,8 @@ test_expect_success 'nonexistent commit' '\n \tdiff_cmp expected actual\n '\n \n-commit_file\n test_expect_success 'typechanged submodule(blob->submodule)' '\n+\tcommit_file &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/sm1 b/sm1\n@@ -399,8 +398,8 @@ test_expect_success 'typechanged submodule(blob->submodule)' '\n \tdiff_cmp expected actual\n '\n \n-commit_file sm1 &&\n test_expect_success 'submodule is up to date' '\n+\tcommit_file sm1 &&\n \thead7=$(git -C sm1 rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \ttest_must_be_empty actual\n@@ -471,13 +470,13 @@ test_expect_success 'submodule contains untracked and modified content (dirty ig\n '\n \n test_expect_success 'submodule contains untracked and modified content (all ignored)' '\n+\ttest_when_finished rm -f sm1/new-file &&\n \techo new > sm1/foo6 &&\n \tgit diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&\n \ttest_must_be_empty actual\n '\n \n test_expect_success 'submodule contains modified content' '\n-\trm -f sm1/new-file &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 contains modified content\n@@ -492,9 +491,9 @@ test_expect_success 'submodule contains modified content' '\n \tdiff_cmp expected actual\n '\n \n-(cd sm1; git commit -mchange foo6 >/dev/null) &&\n-head8=$(cd sm1; git rev-parse --short --verify HEAD) &&\n test_expect_success 'submodule is modified' '\n+\t(git -C sm1 commit -mchange foo6 >/dev/null) &&\n+\thead8=$(git -C sm1 rev-parse --short --verify HEAD) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7..$head8:\n@@ -616,6 +615,7 @@ test_expect_success 'modified submodule contains untracked and modified content\n '\n \n test_expect_success 'modified submodule contains untracked and modified content (all ignored)' '\n+\ttest_when_finished rm -f sm1/new-file &&\n \techo modification >> sm1/foo6 &&\n \tgit diff-index -p --ignore-submodules --submodule=diff HEAD >actual &&\n \ttest_must_be_empty actual\n@@ -623,7 +623,7 @@ test_expect_success 'modified submodule contains untracked and modified content\n \n # NOT OK\n test_expect_success 'modified submodule contains modified content' '\n-\trm -f sm1/new-file &&\n+\ttest_when_finished rm -rf sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 contains modified content\n@@ -643,7 +643,6 @@ test_expect_success 'modified submodule contains modified content' '\n \tdiff_cmp expected actual\n '\n \n-rm -rf sm1\n test_expect_success 'deleted submodule' '\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n@@ -703,13 +702,15 @@ test_expect_success 'path filter' '\n \tdiff_cmp expected actual\n '\n \n-cat >.gitmodules <<-EOF\n-[submodule \"sm2\"]\n-\tpath = sm2\n-\turl = bogus_url\n-EOF\n-git add .gitmodules\n-commit_file sm2 .gitmodules\n+test_expect_success 'setup - construct .gitmodules' '\n+\tcat >.gitmodules <<-EOF &&\n+\t[submodule \"sm2\"]\n+\t\tpath = sm2\n+\t\turl = bogus_url\n+\tEOF\n+\tgit add .gitmodules &&\n+\tcommit_file sm2 .gitmodules\n+'\n \n test_expect_success 'given commit' '\n \tgit diff-index -p --submodule=diff HEAD^ >actual &&\n@@ -779,9 +780,8 @@ test_expect_success 'diff --submodule=diff with .git file' '\n \tdiff_cmp expected actual\n '\n \n-mv sm2 sm2-bak\n-\n test_expect_success 'deleted submodule with .git file' '\n+\tmv sm2 sm2-bak &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n@@ -804,9 +804,9 @@ test_expect_success 'deleted submodule with .git file' '\n \tdiff_cmp expected actual\n '\n \n-echo submodule-to-blob>sm2\n-\n test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n+\ttest_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n+\techo submodule-to-blob>sm2 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n@@ -836,9 +836,6 @@ test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n \tdiff_cmp expected actual\n '\n \n-rm sm2\n-mv sm2-bak sm2\n-\n test_expect_success 'setup nested submodule' '\n \tgit -c protocol.file.allow=always -C sm2 submodule add ../sm2 nested &&\n \tgit -C sm2 commit -a -m \"nested sub\" &&\n@@ -910,13 +907,11 @@ test_expect_success 'diff --submodule=diff recurses into nested submodules' '\n \tdiff_cmp expected actual\n '\n \n-(cd sm2; commit_file nested)\n-commit_file sm2\n-head12=$(cd sm2; git rev-parse --short --verify HEAD)\n-\n-mv sm2 sm2-bak\n-\n test_expect_success 'diff --submodule=diff recurses into deleted nested submodules' '\n+\t(cd sm2 && commit_file nested) &&\n+\tcommit_file sm2 &&\n+\thead12=$(git -C sm2 rev-parse --short --verify HEAD) &&\n+\tmv sm2 sm2-bak &&\n \tcat >expected <<-EOF &&\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n \tSubmodule sm2 $head12...0000000 (submodule deleted)\n@@ -971,6 +966,8 @@ test_expect_success 'diff --submodule=diff recurses into deleted nested submodul\n \tdiff_cmp expected actual\n '\n \n-mv sm2-bak sm2\n+test_expect_success 'submodule cleanup' '\n+\tmv sm2-bak sm2\n+'\n \n test_done\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472854","messageId":"20230228185642.2357806-2-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 2/6] tests: Use `git submodule add` instead of `git add`","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:38Z","receivedAt":"2023-02-28T18:56:57Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nSince 532139940c (add: warn when adding an embedded repository,\n2017-06-14), we have recognized that adding embedded repositories is a\nsubpar user experience compared to submodules. Embedded repositories\nlack a .gitmodules entry, which means clones of the top-level repo will\nbe unable to obtain the nested repo. We issue advice about this\nsituation in the case where a user adds an embedded repository.\n\nHowever, many tests predate this advice, and directly add embedded\nrepositories instead of using submodules. This commit cleans up such\ntest cases where minimal other changes are required (e.g., committing\nlater changes to .gitmodules or changing the counts of committed files\nin the worktree). Future commits will handle tests requiring more\ncomplicated adjustments.\n\nThese changes will enable us to switch the default behavior of git-add\nfrom warning about embedded repositories to rejecting them outright. See\nlater commits for a further discussion of that topic.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t2013-checkout-submodule.sh          |  4 +++-\n t/t2103-update-index-ignore-missing.sh |  2 +-\n t/t2107-update-index-basic.sh          |  2 +-\n t/t3040-subprojects-basic.sh           |  2 +-\n t/t3050-subprojects-fetch.sh           |  3 ++-\n t/t3404-rebase-interactive.sh          |  3 ++-\n t/t3701-add-interactive.sh             |  5 +++--\n t/t4010-diff-pathspec.sh               |  2 +-\n t/t4020-diff-external.sh               |  2 +-\n t/t5531-deep-submodule-push.sh         |  4 ++--\n t/t6416-recursive-corner-cases.sh      | 12 ++++++------\n t/t6437-submodule-merge.sh             | 12 ++++++------\n t/t7401-submodule-summary.sh           |  4 ++--\n t/t7402-submodule-rebase.sh            |  2 +-\n 14 files changed, 32 insertions(+), 27 deletions(-)\n\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex b2bdd1fcb4..dd2858648b 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -10,7 +10,7 @@ test_expect_success 'setup' '\n \t(cd submodule &&\n \t git init &&\n \t test_commit first) &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \ttest_tick &&\n \tgit commit -m superproject &&\n \t(cd submodule &&\n@@ -51,6 +51,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .gitm\n \tgit config diff.ignoreSubmodules none &&\n \tgit config -f .gitmodules submodule.submodule.path submodule &&\n \tgit config -f .gitmodules submodule.submodule.ignore untracked &&\n+\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n \tgit checkout HEAD >actual 2>&1 &&\n \ttest_must_be_empty actual\n '\n@@ -59,6 +60,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n \tgit config -f .gitmodules submodule.submodule.ignore none &&\n \tgit config submodule.submodule.path submodule &&\n \tgit config submodule.submodule.ignore all &&\n+\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n \tgit checkout HEAD >actual 2>&1 &&\n \ttest_must_be_empty actual\n '\ndiff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\nindex e9451cd567..11bc136f6e 100755\n--- a/t/t2103-update-index-ignore-missing.sh\n+++ b/t/t2103-update-index-ignore-missing.sh\n@@ -36,7 +36,7 @@ test_expect_success basics '\n \t\tgit add file &&\n \t\tgit commit -m \"sub initial\"\n \t) &&\n-\tgit add xyzzy &&\n+\tgit add ./xyzzy &&\n \n \ttest_tick &&\n \tgit commit -m initial &&\ndiff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh\nindex 07e6de84e6..465b41ccdc 100755\n--- a/t/t2107-update-index-basic.sh\n+++ b/t/t2107-update-index-basic.sh\n@@ -49,7 +49,7 @@ test_expect_success '--cacheinfo does not accept blob null sha1' '\n test_expect_success '--cacheinfo does not accept gitlink null sha1' '\n \tgit init submodule &&\n \t(cd submodule && test_commit foo) &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \tgit rev-parse :submodule >expect &&\n \ttest_must_fail git update-index --cacheinfo 160000 $ZERO_OID submodule &&\n \tgit rev-parse :submodule >actual &&\ndiff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh\nindex bd65dfcffc..61da7e3b94 100755\n--- a/t/t3040-subprojects-basic.sh\n+++ b/t/t3040-subprojects-basic.sh\n@@ -69,7 +69,7 @@ test_expect_success 'check if clone works' '\n test_expect_success 'removing and adding subproject' '\n \tgit update-index --force-remove -- sub2 &&\n \tmv sub2 sub3 &&\n-\tgit add sub3 &&\n+\tgit submodule add ./sub3 &&\n \tgit commit -q -m \"renaming a subproject\" &&\n \ttest_expect_code 1 git diff -M --name-status --exit-code HEAD^ HEAD\n '\ndiff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh\nindex f1f09abdd9..9a692274b9 100755\n--- a/t/t3050-subprojects-fetch.sh\n+++ b/t/t3050-subprojects-fetch.sh\n@@ -14,7 +14,8 @@ test_expect_success setup '\n \t\tgit commit -m \"subproject commit #1\"\n \t) &&\n \t>mainfile &&\n-\tgit add sub mainfile &&\n+\tgit add mainfile &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"superproject commit #1\"\n '\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 462cefd25d..1d0574216b 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -675,7 +675,8 @@ test_expect_success 'submodule rebase setup' '\n \t\tgit add elif && git commit -m \"submodule initial\"\n \t) &&\n \techo 1 >file1 &&\n-\tgit add file1 sub &&\n+\tgit add file1 &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"One\" &&\n \techo 2 >file1 &&\ndiff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh\nindex 5841f280fb..715c4fcc62 100755\n--- a/t/t3701-add-interactive.sh\n+++ b/t/t3701-add-interactive.sh\n@@ -913,8 +913,9 @@ test_expect_success 'setup different kinds of dirty submodules' '\n \t\t) &&\n \t\tcp -R dirty-head dirty-otherwise &&\n \t\tcp -R dirty-head dirty-both-ways &&\n-\t\tgit add dirty-head &&\n-\t\tgit add dirty-otherwise dirty-both-ways &&\n+\t\tgit submodule add ./dirty-head &&\n+\t\tgit submodule add ./dirty-otherwise &&\n+\t\tgit submodule add ./dirty-both-ways &&\n \t\tgit commit -m initial &&\n \n \t\tcd dirty-head &&\ndiff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh\nindex 9d9650eba7..844258c418 100755\n--- a/t/t4010-diff-pathspec.sh\n+++ b/t/t4010-diff-pathspec.sh\n@@ -117,7 +117,7 @@ test_expect_success 'setup submodules' '\n \ttest_tick &&\n \tgit init submod &&\n \t( cd submod && test_commit first ) &&\n-\tgit add submod &&\n+\tgit submodule add ./submod &&\n \tgit commit -m first &&\n \t( cd submod && test_commit second ) &&\n \tgit add submod &&\ndiff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh\nindex c1ac09ecc7..ca2a23a78f 100755\n--- a/t/t4020-diff-external.sh\n+++ b/t/t4020-diff-external.sh\n@@ -253,7 +253,7 @@ test_expect_success 'clean up crlf leftovers' '\n test_expect_success 'submodule diff' '\n \tgit init sub &&\n \t( cd sub && test_commit sub1 ) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m \"add submodule\" &&\n \t( cd sub && test_commit sub2 ) &&\ndiff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\nindex 302e4cbdba..f8ef70b5a2 100755\n--- a/t/t5531-deep-submodule-push.sh\n+++ b/t/t5531-deep-submodule-push.sh\n@@ -28,7 +28,7 @@ test_expect_success setup '\n \t\t\tgit add junk &&\n \t\t\tgit commit -m \"Initial junk\"\n \t\t) &&\n-\t\tgit add gar/bage &&\n+\t\tgit submodule add ./gar/bage ./gar/bage &&\n \t\tgit commit -m \"Initial superproject\"\n \t)\n '\n@@ -367,7 +367,7 @@ test_expect_success 'push succeeds if submodule has no remote and is on the firs\n \t\t\tgit add junk &&\n \t\t\tgit commit -m \"initial\"\n \t\t) &&\n-\t\tgit add b &&\n+\t\tgit submodule add ./b &&\n \t\tgit commit -m \"added submodule\" &&\n \t\tgit push --recurse-submodules=check origin main\n \t)\ndiff --git a/t/t6416-recursive-corner-cases.sh b/t/t6416-recursive-corner-cases.sh\nindex 17b54d625d..b366dd77e5 100755\n--- a/t/t6416-recursive-corner-cases.sh\n+++ b/t/t6416-recursive-corner-cases.sh\n@@ -1270,7 +1270,7 @@ test_expect_success 'setup submodule modify/modify' '\n \t\t) &&\n \n \t\tgit -C submod reset --hard A &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m A &&\n \t\tgit tag A &&\n \n@@ -1303,7 +1303,7 @@ test_expect_merge_algorithm failure success 'check submodule modify/modify' '\n \t\ttest_must_fail git merge -s recursive E^0 &&\n \n \t\tgit ls-files -s >out &&\n-\t\ttest_line_count = 3 out &&\n+\t\ttest_line_count = 4 out &&\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 3 out &&\n \t\tgit ls-files -o >out &&\n@@ -1364,12 +1364,12 @@ test_expect_success 'setup submodule add/add' '\n \n \t\tgit checkout -b B A &&\n \t\tgit -C submod reset --hard B &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m B &&\n \n \t\tgit checkout -b C A &&\n \t\tgit -C submod reset --hard C &&\n-\t\tgit add submod &&\n+\t\tgit submodule add ./submod &&\n \t\tgit commit -m C &&\n \n \t\tgit checkout -q B^0 &&\n@@ -1391,7 +1391,7 @@ test_expect_merge_algorithm failure success 'check submodule add/add' '\n \t\ttest_must_fail git merge -s recursive E^0 &&\n \n \t\tgit ls-files -s >out &&\n-\t\ttest_line_count = 3 out &&\n+\t\ttest_line_count = 4 out &&\n \t\tgit ls-files -u >out &&\n \t\ttest_line_count = 2 out &&\n \t\tgit ls-files -o >out &&\n@@ -1439,7 +1439,7 @@ test_expect_success 'setup conflicting entry types (submodule vs symlink)' '\n \n \t\tgit checkout -b B A &&\n \t\tgit -C path reset --hard B &&\n-\t\tgit add path &&\n+\t\tgit submodule add ./path &&\n \t\tgit commit -m B &&\n \n \t\tgit checkout -b C A &&\ndiff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\nindex c9a86f2e94..7f6e89f541 100755\n--- a/t/t6437-submodule-merge.sh\n+++ b/t/t6437-submodule-merge.sh\n@@ -30,7 +30,7 @@ test_expect_success setup '\n \t git add file &&\n \t test_tick &&\n \t git commit -m sub-root) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \ttest_tick &&\n \tgit commit -m root &&\n \n@@ -85,7 +85,7 @@ test_expect_success 'setup for merge search' '\n \t git branch sub-a) &&\n \tgit commit --allow-empty -m init &&\n \tgit branch init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"a\" &&\n \tgit branch a &&\n \n@@ -132,7 +132,7 @@ test_expect_success 'finish setup for merge-search' '\n \tgit checkout -b g init &&\n \t(cd sub &&\n \t git checkout -b sub-g sub-c) &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -a -m \"g\")\n '\n \n@@ -296,7 +296,7 @@ test_expect_success 'setup for recursive merge with submodule' '\n \t  git checkout -b sub-cb sub-c &&\n \t  git merge sub-b &&\n \t  git checkout main) &&\n-\t git add sub &&\n+\t git submodule add ./sub &&\n \t git commit -m a &&\n \t git checkout -b top-b main &&\n \t (cd sub && git checkout sub-b) &&\n@@ -520,7 +520,7 @@ test_expect_success 'setup for null merge base' '\n \tgit commit --allow-empty -m init &&\n \tgit branch init &&\n \tgit checkout -b a init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"a\" &&\n \tgit switch main &&\n \t(cd sub &&\n@@ -532,7 +532,7 @@ test_expect_success 'setup for null merge base' '\n test_expect_success 'merging should fail with no merge base' '\n \t(cd no-merge-base &&\n \tgit checkout -b b init &&\n-\tgit add sub &&\n+\tgit submodule add ./sub &&\n \tgit commit -m \"b\" &&\n \ttest_must_fail git merge a >actual &&\n \tif test \"$GIT_TEST_MERGE_ALGORITHM\" = ort\ndiff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh\nindex 542b3331a7..73fd09edb6 100755\n--- a/t/t7401-submodule-summary.sh\n+++ b/t/t7401-submodule-summary.sh\n@@ -45,7 +45,7 @@ add_file . foo >/dev/null\n head1=$(add_file sm1 foo1 foo2)\n \n test_expect_success 'added submodule' \"\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n \tgit submodule summary >actual &&\n \tcat >expected <<-EOF &&\n \t* sm1 0000000...$head1 (2):\n@@ -253,7 +253,7 @@ test_expect_success 'deleted submodule' \"\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead7=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2\n '\n \n test_expect_success 'multiple submodules' \"\ndiff --git a/t/t7402-submodule-rebase.sh b/t/t7402-submodule-rebase.sh\nindex ebeca12a71..abc2092741 100755\n--- a/t/t7402-submodule-rebase.sh\n+++ b/t/t7402-submodule-rebase.sh\n@@ -14,7 +14,7 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m initial &&\n \tgit clone . submodule &&\n-\tgit add submodule &&\n+\tgit submodule add ./submodule &&\n \ttest_tick &&\n \tgit commit -m submodule &&\n \techo second line >> file &&\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472855","messageId":"20230228185642.2357806-3-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 3/6] tests: use `git submodule add` and fix expected diffs","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:39Z","receivedAt":"2023-02-28T18:57:03Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nThis commit continues the previous work of updating the test suite to\nuse `git submodule add` to create submodules instead of using `git add`\nto include embedded repositories. Specifically, in this commit we update\ntest cases where expected diffs must change due to the presence of a\n.gitmodules file.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t3040-subprojects-basic.sh                 |   3 +-\n t/t4041-diff-submodule-option.sh             | 153 ++++++++++++++++++-\n t/t4060-diff-submodule-option-diff-format.sh | 125 +++++++++++++--\n t/t7506-status-submodule.sh                  |  15 +-\n 4 files changed, 278 insertions(+), 18 deletions(-)\n\ndiff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh\nindex 61da7e3b94..a0f14db3d2 100755\n--- a/t/t3040-subprojects-basic.sh\n+++ b/t/t3040-subprojects-basic.sh\n@@ -19,11 +19,12 @@ test_expect_success 'setup: create subprojects' '\n \t( cd sub2 && git init && : >Makefile && git add * &&\n \tgit commit -q -m \"subproject 2\" ) &&\n \tgit update-index --add sub1 &&\n-\tgit add sub2 &&\n+\tgit submodule add ./sub2 &&\n \tgit commit -q -m \"subprojects added\" &&\n \tGIT_PRINT_SHA1_ELLIPSIS=\"yes\" git diff-tree --abbrev=5 HEAD^ HEAD |cut -d\" \" -f-3,5- >current &&\n \tgit branch save HEAD &&\n \tcat >expected <<-\\EOF &&\n+\t:000000 100644 00000... A\t.gitmodules\n \t:000000 160000 00000... A\tsub1\n \t:000000 160000 00000... A\tsub2\n \tEOF\ndiff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\nindex 2aa12243bd..f5074071a4 100755\n--- a/t/t4041-diff-submodule-option.sh\n+++ b/t/t4041-diff-submodule-option.sh\n@@ -50,9 +50,19 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'added submodule' '\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n+\tgitmodules_hash1=$(git rev-parse --short $(git hash-object .gitmodules)) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tEOF\n \ttest_cmp expected actual\n@@ -63,6 +73,15 @@ test_expect_success 'added submodule, set diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tEOF\n \tgit config --unset diff.submodule &&\n@@ -74,6 +93,15 @@ test_expect_success '--submodule=short overrides diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --submodule=short --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -89,6 +117,15 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_config diff.submodule log &&\n \tgit diff-index -p HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -105,6 +142,15 @@ test_expect_success 'modified submodule(forward)' '\n \thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head1..$head2:\n \t  > Add foo3 ($added foo3)\n \tEOF\n@@ -154,6 +200,15 @@ test_expect_success 'modified submodule(backward)' '\n \t) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2..$head3 (rewind):\n \t  < Add foo3 ($added foo3)\n \t  < Add foo2 ($added foo2)\n@@ -165,6 +220,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2...$head4:\n \t  > Add foo5 ($added foo5)\n \t  > Add foo4 ($added foo4)\n@@ -187,6 +251,15 @@ test_expect_success 'setup - change sm1 to a blob' '\n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=log --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -220,6 +293,15 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -238,6 +320,15 @@ test_expect_success 'nonexistent commit' '\n \tfullhead6=$(git -C sm1 rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..$gitmodules_hash1\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...$head6 (commits not present)\n \tEOF\n \ttest_cmp expected actual\n@@ -436,12 +527,24 @@ test_expect_success 'deleted submodule' '\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead7=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2 &&\n+\tgitmodules_hash2=$(git rev-parse --short $(git hash-object .gitmodules))\n '\n \n test_expect_success 'multiple submodules' '\n \tgit diff-index -p --submodule=log HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -460,6 +563,17 @@ test_expect_success 'given commit' '\n \tcommit_file sm2 &&\n \tgit diff-index -p --submodule=log HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -469,6 +583,17 @@ test_expect_success 'given commit' '\n test_expect_success 'given commit --submodule' '\n \tgit diff-index -p --submodule HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -479,6 +604,17 @@ test_expect_success 'given commit --submodule=short' '\n \tfullhead7=$(git -C sm2 rev-parse --verify HEAD) &&\n \tgit diff-index -p --submodule=short HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tdiff --git a/sm1 b/sm1\n \tdeleted file mode 160000\n \tindex $head6..0000000\n@@ -507,6 +643,17 @@ test_expect_success 'setup .git file for sm2' '\n test_expect_success 'diff --submodule with .git file' '\n \tgit diff --submodule HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex $gitmodules_hash1..$gitmodules_hash2 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head6...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head7 (new submodule)\n \tEOF\n@@ -525,7 +672,7 @@ test_expect_success 'diff --submodule with objects referenced by alternates' '\n \t(cd super &&\n \t\tgit clone -s ../sub_alt sub &&\n \t\tgit init &&\n-\t\tgit add sub &&\n+\t\tgit submodule add ./sub &&\n \t\tgit commit -m \"sub a\"\n \t) &&\n \t(cd sub_alt &&\ndiff --git a/t/t4060-diff-submodule-option-diff-format.sh b/t/t4060-diff-submodule-option-diff-format.sh\nindex a760ed5eb6..89c5641c6b 100755\n--- a/t/t4060-diff-submodule-option-diff-format.sh\n+++ b/t/t4060-diff-submodule-option-diff-format.sh\n@@ -61,9 +61,18 @@ test_expect_success 'setup repository' '\n '\n \n test_expect_success 'added submodule' '\n-\tgit add sm1 &&\n+\tgit submodule add ./sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tnew file mode 100644\n@@ -88,6 +97,15 @@ test_expect_success 'added submodule, set diff.submodule' '\n \tgit add sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 0000000...$head1 (new submodule)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tnew file mode 100644\n@@ -112,6 +130,15 @@ test_expect_success '--submodule=short overrides diff.submodule' '\n \tgit add sm1 &&\n \tgit diff --submodule=short --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -127,6 +154,15 @@ test_expect_success 'diff.submodule does not affect plumbing' '\n \ttest_config diff.submodule log &&\n \tgit diff-index -p HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 1234567..89abcde\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 160000\n \tindex 0000000..$head1\n@@ -143,6 +179,15 @@ test_expect_success 'modified submodule(forward)' '\n \thead2=$(add_file sm1 foo3) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head1..$head2:\n \tdiff --git a/sm1/foo3 b/sm1/foo3\n \tnew file mode 100644\n@@ -202,6 +247,15 @@ test_expect_success 'modified submodule(backward)' '\n \t) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2..$head3 (rewind):\n \tdiff --git a/sm1/foo2 b/sm1/foo2\n \tdeleted file mode 100644\n@@ -225,6 +279,15 @@ test_expect_success 'modified submodule(backward and forward)' '\n \thead4=$(add_file sm1 foo4 foo5) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head2...$head4:\n \tdiff --git a/sm1/foo2 b/sm1/foo2\n \tdeleted file mode 100644\n@@ -271,6 +334,15 @@ test_expect_success 'setup - change sm1 to a blob' '\n test_expect_success 'typechanged submodule(submodule->blob), --cached' '\n \tgit diff --submodule=diff --cached >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1/foo1 b/sm1/foo1\n \tdeleted file mode 100644\n@@ -346,6 +418,15 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n \tgit checkout-index sm1 &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...0000000 (submodule deleted)\n \tdiff --git a/sm1 b/sm1\n \tnew file mode 100644\n@@ -363,6 +444,15 @@ test_expect_success 'nonexistent commit' '\n \thead6=$(add_file sm1 foo6 foo7) &&\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tnew file mode 100644\n+\tindex 0000000..2334463\n+\t--- /dev/null\n+\t+++ b/.gitmodules\n+\t@@ -0,0 +1,3 @@\n+\t+[submodule \"sm1\"]\n+\t+\tpath = sm1\n+\t+\turl = ./sm1\n \tSubmodule sm1 $head4...$head6 (commits not present)\n \tEOF\n \tdiff_cmp expected actual\n@@ -654,12 +744,23 @@ test_expect_success 'deleted submodule' '\n test_expect_success 'create second submodule' '\n \ttest_create_repo sm2 &&\n \thead9=$(add_file sm2 foo8 foo9) &&\n-\tgit add sm2\n+\tgit submodule add ./sm2\n '\n \n test_expect_success 'multiple submodules' '\n \tgit diff-index -p --submodule=diff HEAD >actual &&\n \tcat >expected <<-EOF &&\n+\tdiff --git a/.gitmodules b/.gitmodules\n+\tindex 2334463..8809a9f 100644\n+\t--- a/.gitmodules\n+\t+++ b/.gitmodules\n+\t@@ -1,3 +1,6 @@\n+\t [submodule \"sm1\"]\n+\t \tpath = sm1\n+\t \turl = ./sm1\n+\t+[submodule \"sm2\"]\n+\t+\tpath = sm2\n+\t+\turl = ./sm2\n \tSubmodule sm1 $head7...0000000 (submodule deleted)\n \tSubmodule sm2 0000000...$head9 (new submodule)\n \tdiff --git a/sm2/foo8 b/sm2/foo8\n@@ -716,11 +817,13 @@ test_expect_success 'given commit' '\n \tgit diff-index -p --submodule=diff HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/.gitmodules b/.gitmodules\n-\tnew file mode 100644\n-\tindex 1234567..89abcde\n-\t--- /dev/null\n+\tindex 1234567..89abcde 100644\n+\t--- a/.gitmodules\n \t+++ b/.gitmodules\n-\t@@ -0,0 +1,3 @@\n+\t@@ -1,3 +1,3 @@\n+\t-[submodule \"sm1\"]\n+\t-\tpath = sm1\n+\t-\turl = ./sm1\n \t+[submodule \"sm2\"]\n \t+path = sm2\n \t+url = bogus_url\n@@ -752,11 +855,13 @@ test_expect_success 'diff --submodule=diff with .git file' '\n \tgit diff --submodule=diff HEAD^ >actual &&\n \tcat >expected <<-EOF &&\n \tdiff --git a/.gitmodules b/.gitmodules\n-\tnew file mode 100644\n-\tindex 1234567..89abcde\n-\t--- /dev/null\n+\tindex 1234567..89abcde 100644\n+\t--- a/.gitmodules\n \t+++ b/.gitmodules\n-\t@@ -0,0 +1,3 @@\n+\t@@ -1,3 +1,3 @@\n+\t-[submodule \"sm1\"]\n+\t-\tpath = sm1\n+\t-\turl = ./sm1\n \t+[submodule \"sm2\"]\n \t+path = sm2\n \t+url = bogus_url\ndiff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh\nindex d050091345..9dbd9ff266 100755\n--- a/t/t7506-status-submodule.sh\n+++ b/t/t7506-status-submodule.sh\n@@ -31,7 +31,8 @@ sanitize_diff () {\n test_expect_success 'setup' '\n \ttest_create_repo_with_commit sub &&\n \techo output > .gitignore &&\n-\tgit add sub .gitignore &&\n+\tgit submodule add ./sub &&\n+\tgit add .gitignore &&\n \tgit commit -m \"Add submodule sub\"\n '\n \n@@ -243,7 +244,7 @@ test_expect_success 'status -a clean (empty submodule dir)' '\n '\n \n cat >status_expect <<\\EOF\n-AA .gitmodules\n+UU .gitmodules\n A  sub1\n EOF\n \n@@ -277,7 +278,10 @@ cat >diff_expect <<\\EOF\n diff --cc .gitmodules\n --- a/.gitmodules\n +++ b/.gitmodules\n-@@@ -1,3 -1,3 +1,9 @@@\n+@@@ -1,6 -1,6 +1,12 @@@\n+  [submodule \"sub\"]\n+  \tpath = sub\n+  \turl = ./sub\n ++<<<<<<< HEAD\n  +[submodule \"sub2\"]\n  +\tpath = sub2\n@@ -293,7 +297,10 @@ cat >diff_submodule_expect <<\\EOF\n diff --cc .gitmodules\n --- a/.gitmodules\n +++ b/.gitmodules\n-@@@ -1,3 -1,3 +1,9 @@@\n+@@@ -1,6 -1,6 +1,12 @@@\n+  [submodule \"sub\"]\n+  \tpath = sub\n+  \turl = ./sub\n ++<<<<<<< HEAD\n  +[submodule \"sub2\"]\n  +\tpath = sub2\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472856","messageId":"20230228185642.2357806-4-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 4/6] tests: use `git submodule add` and fix expected status","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:40Z","receivedAt":"2023-02-28T18:57:04Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nThis commit continues the previous work of updating the test suite to\nuse `git submodule add` to create submodules instead of using `git add`\nto include embedded repositories.\n\nIn this commit, we update test cases where the expected status output\nmust change due to the presence of a .gitmodules file. We use the\npre-existing expected output as a template for cases where .gitmodules\nhas been modified but not committed.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t4027-diff-submodule.sh |  17 +++--\n t/t7508-status.sh         | 134 ++++++++++++++++++++++++++++++++------\n 2 files changed, 128 insertions(+), 23 deletions(-)\n\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 40164ae07d..2ee9f18b38 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -18,7 +18,8 @@ test_expect_success setup '\n \n \ttest_tick &&\n \techo frotz >nitfol &&\n-\tgit add nitfol sub &&\n+\tgit add nitfol &&\n+\tgit submodule add ./sub &&\n \tgit commit -m superproject &&\n \n \t(\n@@ -122,25 +123,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n '\n \n test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n+\tgit branch pristine-gitmodules &&\n \tgit config diff.ignoreSubmodules dirty &&\n \tgit diff HEAD >actual &&\n \ttest_must_be_empty actual &&\n \tgit config --add -f .gitmodules submodule.subname.ignore none &&\n \tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n \tgit config -f .gitmodules submodule.subname.ignore all &&\n \tgit config -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual3.body &&\n \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n \tgit config submodule.subname.ignore none &&\n@@ -152,7 +158,7 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n \tgit config --unset diff.ignoreSubmodules &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' '\n@@ -190,12 +196,15 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n \tgit config --add -f .gitmodules submodule.subname.ignore all &&\n \tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \ttest_must_be_empty actual3 &&\n \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n \tgit config submodule.subname.ignore none &&\n@@ -206,7 +215,7 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)\n \ttest_cmp expect.body actual.body &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff between submodule commits' '\n@@ -243,7 +252,7 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' '\n \texpect_from_to >expect.body $subtip $subprev &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname &&\n-\trm .gitmodules\n+\tgit reset --hard pristine-gitmodules\n '\n \n test_expect_success 'git diff (empty submodule dir)' '\ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 2b7ef6c41a..5808339997 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -892,7 +892,7 @@ test_expect_success 'setup status submodule summary' '\n \t\tgit add foo &&\n \t\tgit commit -m \"Add foo\"\n \t) &&\n-\tgit add sm\n+\tgit submodule add ./sm\n '\n \n test_expect_success 'status submodule summary is disabled by default' '\n@@ -904,6 +904,7 @@ and have 1 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -931,6 +932,7 @@ test_expect_success 'status --untracked-files=all does not show submodule' '\n '\n \n cat >expect <<EOF\n+A  .gitmodules\n  M dir1/modified\n A  dir2/added\n A  sm\n@@ -961,6 +963,7 @@ and have 1 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -998,6 +1001,7 @@ test_expect_success 'commit with submodule summary ignores status.displayComment\n '\n \n cat >expect <<EOF\n+A  .gitmodules\n  M dir1/modified\n A  dir2/added\n A  sm\n@@ -1068,6 +1072,7 @@ and have 2 and 2 different commits each, respectively.\n \n Changes to be committed:\n   (use \"git restore --source=HEAD^1 --staged <file>...\" to unstage)\n+\tnew file:   .gitmodules\n \tnew file:   dir2/added\n \tnew file:   sm\n \n@@ -1134,7 +1139,6 @@ Submodule changes to be committed:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1152,8 +1156,37 @@ test_expect_success '.gitmodules ignore=untracked suppresses submodules with unt\n \ttest_cmp expect output &&\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1163,7 +1196,7 @@ test_expect_success '.git/config ignore=untracked suppresses submodules with unt\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config --remove-section -f .gitmodules submodule.subname\n '\n@@ -1180,7 +1213,7 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with untrack\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1190,7 +1223,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with untrack\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1205,7 +1238,7 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with modifie\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1215,7 +1248,7 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1245,7 +1278,6 @@ Submodule changes to be committed:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1259,8 +1291,39 @@ EOF\n test_expect_success \".gitmodules ignore=untracked doesn't suppress submodules with modified content\" '\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+  (commit or discard the untracked or modified content in submodules)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\tmodified:   sm (modified content)\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1270,7 +1333,7 @@ test_expect_success \".git/config ignore=untracked doesn't suppress submodules wi\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1306,7 +1369,6 @@ Submodules changed but not updated:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1318,10 +1380,45 @@ EOF\n '\n \n test_expect_success \".gitmodules ignore=untracked doesn't suppress submodule summary\" '\n+\tcat > expect-modified-gitmodules << EOF &&\n+On branch main\n+Your branch and '\\''upstream'\\'' have diverged,\n+and have 2 and 2 different commits each, respectively.\n+  (use \"git pull\" to merge the remote branch into yours)\n+\n+Changes to be committed:\n+  (use \"git restore --staged <file>...\" to unstage)\n+\tmodified:   sm\n+\n+Changes not staged for commit:\n+  (use \"git add <file>...\" to update what will be committed)\n+  (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n+\tmodified:   dir1/modified\n+\tmodified:   sm (new commits)\n+\n+Submodule changes to be committed:\n+\n+* sm $head...$new_head (1):\n+  > Add bar\n+\n+Submodules changed but not updated:\n+\n+* sm $new_head...$head2 (1):\n+  > 2nd commit\n+\n+Untracked files:\n+  (use \"git add <file>...\" to include in what will be committed)\n+\tdir1/untracked\n+\tdir2/modified\n+\tdir2/untracked\n+\tuntracked\n+\n+EOF\n \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1331,7 +1428,7 @@ test_expect_success \".git/config ignore=untracked doesn't suppress submodule sum\n \tgit config --add submodule.subname.ignore untracked &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1344,7 +1441,7 @@ test_expect_success \".gitmodules ignore=dirty doesn't suppress submodule summary\n \tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n \tgit config --add -f .gitmodules submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n \n@@ -1354,7 +1451,7 @@ test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\n \tgit config --add submodule.subname.ignore dirty &&\n \tgit config --add submodule.subname.path sm &&\n \tgit status >output &&\n-\ttest_cmp expect output &&\n+\ttest_cmp expect-modified-gitmodules output &&\n \tgit config --remove-section submodule.subname &&\n \tgit config -f .gitmodules  --remove-section submodule.subname\n '\n@@ -1387,7 +1484,6 @@ cat > expect << EOF\n ;\n ; Untracked files:\n ;   (use \"git add <file>...\" to include in what will be committed)\n-;\t.gitmodules\n ;\tdir1/untracked\n ;\tdir2/modified\n ;\tdir2/untracked\n@@ -1420,7 +1516,6 @@ Changes not staged for commit:\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1446,11 +1541,11 @@ Changes to be committed:\n Changes not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n \tmodified:   dir1/modified\n \n Untracked files:\n   (use \"git add <file>...\" to include in what will be committed)\n-\t.gitmodules\n \tdir1/untracked\n \tdir2/modified\n \tdir2/untracked\n@@ -1566,6 +1661,7 @@ Changes to be committed:\n Changes not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n+\tmodified:   .gitmodules\n \tmodified:   dir1/modified\n \n Untracked files not listed (use -u option to show untracked files)\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472857","messageId":"20230228185642.2357806-5-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 5/6] tests: remove duplicate .gitmodules path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:41Z","receivedAt":"2023-02-28T18:57:07Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Swapping `git add <submodule>` to `git submodule add <submodule>`\nin a previous patch created a .gitmodules file with multiple\nsubmodules pointing to the same path in certain tests. Fix tests\nso that they are run on the original added submodule rather than\na separate manually configured submodule.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n t/t4027-diff-submodule.sh |  41 ++++++--------\n t/t7508-status.sh         | 114 +++++++++++++++-----------------------\n 2 files changed, 62 insertions(+), 93 deletions(-)\n\ndiff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh\nindex 2ee9f18b38..ce335534b9 100755\n--- a/t/t4027-diff-submodule.sh\n+++ b/t/t4027-diff-submodule.sh\n@@ -127,36 +127,33 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n \tgit config diff.ignoreSubmodules dirty &&\n \tgit diff HEAD >actual &&\n \ttest_must_be_empty actual &&\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit config --add -f .gitmodules submodule.sub.ignore none &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config -f .gitmodules submodule.subname.ignore all &&\n-\tgit config -f .gitmodules submodule.subname.path sub &&\n+\tgit config -f .gitmodules submodule.sub.ignore all &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n-\tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit config -f .gitmodules submodule.sub.ignore untracked &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual3.body &&\n-\tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config -f .gitmodules submodule.sub.ignore dirty &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n-\tgit config submodule.subname.ignore none &&\n-\tgit config submodule.subname.path sub &&\n+\tgit config submodule.sub.ignore none &&\n+\tgit config submodule.sub.path sub &&\n \tgit diff HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\tgit config --unset submodule.sub.ignore &&\n \tgit config --unset diff.ignoreSubmodules &&\n \tgit reset --hard pristine-gitmodules\n '\n@@ -194,27 +191,24 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n '\n \n test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n-\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit config --add -f .gitmodules submodule.sub.ignore all &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual2 &&\n \ttest_must_be_empty actual2 &&\n-\tgit config -f .gitmodules submodule.subname.ignore untracked &&\n+\tgit config -f .gitmodules submodule.sub.ignore untracked &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual3 &&\n \ttest_must_be_empty actual3 &&\n-\tgit config -f .gitmodules submodule.subname.ignore dirty &&\n+\tgit config -f .gitmodules submodule.sub.ignore dirty &&\n \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n \tgit diff HEAD >actual4 &&\n \ttest_must_be_empty actual4 &&\n-\tgit config submodule.subname.ignore none &&\n-\tgit config submodule.subname.path sub &&\n+\tgit config submodule.sub.ignore none &&\n \tgit diff HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subprev $subprev-dirty &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\tgit config --unset submodule.sub.ignore &&\n \tgit reset --hard pristine-gitmodules\n '\n \n@@ -236,22 +230,19 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' '\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subtip $subprev &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n-\tgit config --add -f .gitmodules submodule.subname.path sub &&\n+\tgit config --add -f .gitmodules submodule.sub.ignore dirty &&\n \tgit diff HEAD^..HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subtip $subprev &&\n \ttest_cmp expect.body actual.body &&\n-\tgit config -f .gitmodules submodule.subname.ignore all &&\n+\tgit config -f .gitmodules submodule.sub.ignore all &&\n \tgit diff HEAD^..HEAD >actual &&\n \ttest_must_be_empty actual &&\n-\tgit config submodule.subname.ignore dirty &&\n-\tgit config submodule.subname.path sub &&\n+\tgit config submodule.sub.ignore dirty &&\n \tgit diff  HEAD^..HEAD >actual &&\n \tsed -e \"1,/^@@/d\" actual >actual.body &&\n \texpect_from_to >expect.body $subtip $subprev &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config --remove-section -f .gitmodules submodule.subname &&\n+\tgit config --unset submodule.sub.ignore &&\n \tgit reset --hard pristine-gitmodules\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex 5808339997..3d934bfb86 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -1154,8 +1154,7 @@ test_expect_success '.gitmodules ignore=untracked suppresses submodules with unt\n \ttest_config diff.ignoreSubmodules dirty &&\n \tgit status >output &&\n \ttest_cmp expect output &&\n-\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n \tcat > expect-modified-gitmodules << EOF &&\n On branch main\n Your branch and '\\''upstream'\\'' have diverged,\n@@ -1187,18 +1186,16 @@ Untracked files:\n EOF\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '.git/config ignore=untracked suppresses submodules with untracked content' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore untracked &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore untracked &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config --remove-section -f .gitmodules submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '--ignore-submodules=dirty suppresses submodules with untracked content' '\n@@ -1210,22 +1207,19 @@ test_expect_success '.gitmodules ignore=dirty suppresses submodules with untrack\n \ttest_config diff.ignoreSubmodules dirty &&\n \tgit status >output &&\n \t! test -s actual &&\n-\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '.git/config ignore=dirty suppresses submodules with untracked content' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore dirty &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '--ignore-submodules=dirty suppresses submodules with modified content' '\n@@ -1235,22 +1229,19 @@ test_expect_success '--ignore-submodules=dirty suppresses submodules with modifi\n '\n \n test_expect_success '.gitmodules ignore=dirty suppresses submodules with modified content' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '.git/config ignore=dirty suppresses submodules with modified content' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore dirty &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success \"--ignore-submodules=untracked doesn't suppress submodules with modified content\" '\n@@ -1289,8 +1280,7 @@ EOF\n '\n \n test_expect_success \".gitmodules ignore=untracked doesn't suppress submodules with modified content\" '\n-\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n \tcat > expect-modified-gitmodules << EOF &&\n On branch main\n Your branch and '\\''upstream'\\'' have diverged,\n@@ -1324,18 +1314,16 @@ Untracked files:\n EOF\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success \".git/config ignore=untracked doesn't suppress submodules with modified content\" '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore untracked &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore untracked &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n head2=$(cd sm && git commit -q -m \"2nd commit\" foo && git rev-parse --short=7 --verify HEAD)\n@@ -1415,22 +1403,19 @@ Untracked files:\n \tuntracked\n \n EOF\n-\tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore untracked &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success \".git/config ignore=untracked doesn't suppress submodule summary\" '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore untracked &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore untracked &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summary\" '\n@@ -1438,22 +1423,19 @@ test_expect_success \"--ignore-submodules=dirty doesn't suppress submodule summar\n \ttest_cmp expect output\n '\n test_expect_success \".gitmodules ignore=dirty doesn't suppress submodule summary\" '\n-\tgit config --add -f .gitmodules submodule.subname.ignore dirty &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success \".git/config ignore=dirty doesn't suppress submodule summary\" '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore dirty &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore dirty &&\n \tgit status >output &&\n \ttest_cmp expect-modified-gitmodules output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n cat > expect << EOF\n@@ -1552,22 +1534,19 @@ Untracked files:\n \tuntracked\n \n EOF\n-\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore all &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success '.git/config ignore=all suppresses unstaged submodule summary' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore none &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore all &&\n-\tgit config --add submodule.subname.path sm &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore none &&\n+\tgit config --add submodule.sm.ignore all &&\n \tgit status > output &&\n \ttest_cmp expect output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success 'setup of test environment' '\n@@ -1633,9 +1612,8 @@ test_expect_success 'Restore default test environment' '\n '\n \n test_expect_success 'git commit will commit a staged but ignored submodule' '\n-\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n-\tgit config --add -f .gitmodules submodule.subname.path sm &&\n-\tgit config --add submodule.subname.ignore all &&\n+\tgit config --add -f .gitmodules submodule.sm.ignore all &&\n+\tgit config --add submodule.sm.ignore all &&\n \tgit status -s --ignore-submodules=dirty >output &&\n \ttest_i18ngrep \"^M. sm\" output &&\n \tGIT_EDITOR=\"echo hello >>\\\"\\$1\\\"\" &&\n@@ -1676,8 +1654,8 @@ test_expect_success 'git commit -m will commit a staged but ignored submodule' '\n \tgit commit -uno -m message &&\n \tgit status -s --ignore-submodules=dirty >output &&\n \ttest_i18ngrep ! \"^M. sm\" output &&\n-\tgit config --remove-section submodule.subname &&\n-\tgit config -f .gitmodules  --remove-section submodule.subname\n+\tgit config --unset submodule.sm.ignore &&\n+\tgit config -f .gitmodules --unset submodule.sm.ignore\n '\n \n test_expect_success 'show stash info with \"--show-stash\"' '\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472858","messageId":"20230228185642.2357806-6-calvinwan@google.com","threadId":"59235","inReplyTo":"20230228185253.2356546-1-calvinwan@google.com","subject":"[PATCH v2 6/6] add: reject nested repositories","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-02-28T18:56:42Z","receivedAt":"2023-02-28T18:57:15Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"From: Josh Steadmon <steadmon@google.com>\n\nAs noted in 532139940c (add: warn when adding an embedded repository,\n2017-06-14), adding embedded repositories results in subpar experience\ncompared to submodules, due to the lack of a corresponding .gitmodules\nentry, which means later clones of the top-level repository cannot\nlocate the embedded repo. We expect that this situation is usually\nunintentional, which is why 532139940c added a warning message and\nadvice when users attempt to add an embedded repo.\n\nAt $dayjob, we have found that even this advice is insufficient to stop\nusers from committing unclonable embedded repos in shared projects.\nThis causes toil for the owners of the top-level project repository as\nthey must clean up the resulting gitlinks. Additionally, these mistakes\nare often made by partners outside of $dayjob, which means that a simple\norganization-wide change to the default Git config would be insufficient\nto prevent these mistakes.\n\nDue to this experience, we believe that Git's default behavior should be\nchanged to disallow adding embedded repositories. This commit changes\nthe existing warning into a fatal error, rewrites the advice given, and\ndeprecates `--no-warn-embedded-repo` in favor of `--allow-embedded-repo`\nto bypass the fatal error.\n\nSigned-off-by: Josh Steadmon <steadmon@google.com>\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n Documentation/git-add.txt              | 15 +++++++----\n builtin/add.c                          | 37 +++++++++++++++++---------\n builtin/submodule--helper.c            |  4 +--\n t/t0008-ignores.sh                     |  2 +-\n t/t2103-update-index-ignore-missing.sh |  2 +-\n t/t4035-diff-quiet.sh                  |  2 +-\n t/t6430-merge-recursive.sh             |  2 +-\n t/t7400-submodule-basic.sh             |  4 +--\n t/t7412-submodule-absorbgitdirs.sh     |  2 +-\n t/t7414-submodule-mistakes.sh          | 29 +++++++++++---------\n t/t7450-bad-git-dotfiles.sh            |  2 +-\n 11 files changed, 61 insertions(+), 40 deletions(-)\n\ndiff --git a/Documentation/git-add.txt b/Documentation/git-add.txt\nindex a030d33c6e..b90e305110 100644\n--- a/Documentation/git-add.txt\n+++ b/Documentation/git-add.txt\n@@ -176,12 +176,17 @@ for \"git add --no-all <pathspec>...\", i.e. ignored removed files.\n \tbe ignored, no matter if they are already present in the work\n \ttree or not.\n \n---no-warn-embedded-repo::\n-\tBy default, `git add` will warn when adding an embedded\n+--allow-embedded-repo::\n+\tBy default, `git add` will error out when adding an embedded\n \trepository to the index without using `git submodule add` to\n-\tcreate an entry in `.gitmodules`. This option will suppress the\n-\twarning (e.g., if you are manually performing operations on\n-\tsubmodules).\n+\tcreate an entry in `.gitmodules`. This option will allow the\n+\tembedded repository to be added. (e.g., if you are manually\n+\tperforming operations on submodules).\n+\n+--no-warn-embedded-repo::\n+\tThis option is deprecated in favor of '--add-embedded-repo'.\n+\tPassing this option still suppresses advice but does not bypass\n+\tthe error.\n \n --renormalize::\n \tApply the \"clean\" process freshly to all tracked files to\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 76277df326..c1590129bb 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -354,6 +354,7 @@ N_(\"The following paths are ignored by one of your .gitignore files:\\n\");\n static int verbose, show_only, ignored_too, refresh_only;\n static int ignore_add_errors, intent_to_add, ignore_missing;\n static int warn_on_embedded_repo = 1;\n+static int allow_embedded_repo = 0;\n \n #define ADDREMOVE_DEFAULT 1\n static int addremove = ADDREMOVE_DEFAULT;\n@@ -392,6 +393,8 @@ static struct option builtin_add_options[] = {\n \t\t   N_(\"override the executable bit of the listed files\")),\n \tOPT_HIDDEN_BOOL(0, \"warn-embedded-repo\", &warn_on_embedded_repo,\n \t\t\tN_(\"warn when adding an embedded repository\")),\n+\tOPT_HIDDEN_BOOL(0, \"allow-embedded-repo\", &allow_embedded_repo,\n+\t\t\tN_(\"allow adding an embedded repository\")),\n \tOPT_PATHSPEC_FROM_FILE(&pathspec_from_file),\n \tOPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),\n \tOPT_END(),\n@@ -409,48 +412,53 @@ static int add_config(const char *var, const char *value, void *cb)\n }\n \n static const char embedded_advice[] = N_(\n-\"You've added another git repository inside your current repository.\\n\"\n+\"You attempted to add another git repository inside your current repository.\\n\"\n \"Clones of the outer repository will not contain the contents of\\n\"\n \"the embedded repository and will not know how to obtain it.\\n\"\n \"If you meant to add a submodule, use:\\n\"\n \"\\n\"\n \"\tgit submodule add <url> %s\\n\"\n \"\\n\"\n-\"If you added this path by mistake, you can remove it from the\\n\"\n-\"index with:\\n\"\n+\"See \\\"git help submodule\\\" for more information.\\n\"\n \"\\n\"\n-\"\tgit rm --cached %s\\n\"\n+\"If you cannot use submodules, you may bypass this check with:\\n\"\n \"\\n\"\n-\"See \\\"git help submodule\\\" for more information.\"\n+\"\tgit add --allow-embedded-repo %s\\n\"\n );\n \n-static void check_embedded_repo(const char *path)\n+static int check_embedded_repo(const char *path)\n {\n+\tint ret = 0;\n \tstruct strbuf name = STRBUF_INIT;\n \tstatic int adviced_on_embedded_repo = 0;\n \n-\tif (!warn_on_embedded_repo)\n-\t\treturn;\n+\tif (allow_embedded_repo)\n+\t\tgoto cleanup;\n \tif (!ends_with(path, \"/\"))\n-\t\treturn;\n+\t\tgoto cleanup;\n+\n+\tret = 1;\n \n \t/* Drop trailing slash for aesthetics */\n \tstrbuf_addstr(&name, path);\n \tstrbuf_strip_suffix(&name, \"/\");\n \n-\twarning(_(\"adding embedded git repository: %s\"), name.buf);\n+\terror(_(\"cannot add embedded git repository: %s\"), name.buf);\n \tif (!adviced_on_embedded_repo &&\n-\t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n+\t\twarn_on_embedded_repo &&\n+\t\tadvice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n \t\tadvise(embedded_advice, name.buf, name.buf);\n \t\tadviced_on_embedded_repo = 1;\n \t}\n \n+cleanup:\n \tstrbuf_release(&name);\n+\treturn ret;\n }\n \n static int add_files(struct dir_struct *dir, int flags)\n {\n-\tint i, exit_status = 0;\n+\tint i, exit_status = 0, embedded_repo = 0;\n \tstruct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;\n \n \tif (dir->ignored_nr) {\n@@ -476,10 +484,13 @@ static int add_files(struct dir_struct *dir, int flags)\n \t\t\t\tdie(_(\"adding files failed\"));\n \t\t\texit_status = 1;\n \t\t} else {\n-\t\t\tcheck_embedded_repo(dir->entries[i]->name);\n+\t\t\tembedded_repo |= check_embedded_repo(dir->entries[i]->name);\n \t\t}\n \t}\n \n+\tif (embedded_repo)\n+\t\tdie(_(\"refusing to add embedded git repositories\"));\n+\n \tif (matched_sparse_paths.nr) {\n \t\tadvise_on_updating_sparse_paths(&matched_sparse_paths);\n \t\texit_status = 1;\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 05f2c9bc98..534ed22c9e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -3129,7 +3129,7 @@ static void configure_added_submodule(struct add_data *add_data)\n \n \tadd_submod.git_cmd = 1;\n \tstrvec_pushl(&add_submod.args, \"add\",\n-\t\t     \"--no-warn-embedded-repo\", NULL);\n+\t\t     \"--allow-embedded-repo\", NULL);\n \tif (add_data->force)\n \t\tstrvec_push(&add_submod.args, \"--force\");\n \tstrvec_pushl(&add_submod.args, \"--\", add_data->sm_path, NULL);\n@@ -3318,7 +3318,7 @@ static int module_add(int argc, const char **argv, const char *prefix)\n \t\tcp.git_cmd = 1;\n \t\tcp.no_stdout = 1;\n \t\tstrvec_pushl(&cp.args, \"add\", \"--dry-run\", \"--ignore-missing\",\n-\t\t\t     \"--no-warn-embedded-repo\", add_data.sm_path, NULL);\n+\t\t\t     \"--allow-embedded-repo\", add_data.sm_path, NULL);\n \t\tif ((ret = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {\n \t\t\tstrbuf_complete_line(&sb);\n \t\t\tfputs(sb.buf, stderr);\ndiff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\nindex c70d11bc91..a53dac5931 100755\n--- a/t/t0008-ignores.sh\n+++ b/t/t0008-ignores.sh\n@@ -191,7 +191,7 @@ test_expect_success 'setup' '\n \t\tgit add a &&\n \t\tgit commit -m\"commit in submodule\"\n \t) &&\n-\tgit add a/submodule &&\n+\tgit add --allow-embedded-repo a/submodule &&\n \tcat <<-\\EOF >.gitignore &&\n \t\tone\n \t\tignored-*\ndiff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\nindex 11bc136f6e..1ce4fc49fa 100755\n--- a/t/t2103-update-index-ignore-missing.sh\n+++ b/t/t2103-update-index-ignore-missing.sh\n@@ -36,7 +36,7 @@ test_expect_success basics '\n \t\tgit add file &&\n \t\tgit commit -m \"sub initial\"\n \t) &&\n-\tgit add ./xyzzy &&\n+\tgit add --allow-embedded-repo ./xyzzy &&\n \n \ttest_tick &&\n \tgit commit -m initial &&\ndiff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh\nindex 76f8034c60..bfd87891f4 100755\n--- a/t/t4035-diff-quiet.sh\n+++ b/t/t4035-diff-quiet.sh\n@@ -66,7 +66,7 @@ test_expect_success 'git diff-index --cached HEAD^' '\n test_expect_success 'git diff-index --cached HEAD^' '\n \techo text >>b &&\n \techo 3 >c &&\n-\tgit add . &&\n+\tgit add --allow-embedded-repo . &&\n \ttest_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt &&\n \ttest_line_count = 0 cnt\n '\ndiff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\nindex 07067bb347..ae435fa492 100755\n--- a/t/t6430-merge-recursive.sh\n+++ b/t/t6430-merge-recursive.sh\n@@ -677,7 +677,7 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n \techo content3 >sub2/file3 &&\n \tmkdir simple &&\n \techo base >simple/bar &&\n-\tgit add -A &&\n+\tgit add -A --allow-embedded-repo &&\n \ttest_tick &&\n \tgit commit -m base &&\n \ndiff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\nindex eae6a46ef3..18ef9141b7 100755\n--- a/t/t7400-submodule-basic.sh\n+++ b/t/t7400-submodule-basic.sh\n@@ -118,7 +118,7 @@ test_expect_success 'setup - repository in init subdirectory' '\n test_expect_success 'setup - commit with gitlink' '\n \techo a >a &&\n \techo z >z &&\n-\tgit add a init z &&\n+\tgit add --allow-embedded-repo a init z &&\n \tgit commit -m \"super commit 1\"\n '\n \n@@ -771,7 +771,7 @@ test_expect_success 'set up for relative path tests' '\n \t\t\tgit init &&\n \t\t\ttest_commit foo\n \t\t) &&\n-\t\tgit add sub &&\n+\t\tgit add --allow-embedded-repo sub &&\n \t\tgit config -f .gitmodules submodule.sub.path sub &&\n \t\tgit config -f .gitmodules submodule.sub.url ../subrepo &&\n \t\tcp .git/config pristine-.git-config &&\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex 2859695c6d..d1662aa23c 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -100,7 +100,7 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n \tgit init sub2 &&\n \ttest_commit -C sub2 first &&\n-\tgit add sub2 &&\n+\tgit add --allow-embedded-repo sub2 &&\n \tgit commit -m superproject\n '\n \ndiff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh\nindex 101afff30f..d38cf34dff 100755\n--- a/t/t7414-submodule-mistakes.sh\n+++ b/t/t7414-submodule-mistakes.sh\n@@ -10,31 +10,36 @@ test_expect_success 'create embedded repository' '\n \ttest_commit -C embed one\n '\n \n-test_expect_success 'git-add on embedded repository warns' '\n-\ttest_when_finished \"git rm --cached -f embed\" &&\n-\tgit add embed 2>stderr &&\n-\ttest_i18ngrep warning stderr\n+test_expect_success 'git-add on embedded repository dies' '\n+\ttest_must_fail git add embed 2>stderr &&\n+\ttest_i18ngrep fatal stderr\n '\n \n-test_expect_success '--no-warn-embedded-repo suppresses warning' '\n+test_expect_success '--allow-embedded-repo adds embedded repository and suppresses error message' '\n \ttest_when_finished \"git rm --cached -f embed\" &&\n-\tgit add --no-warn-embedded-repo embed 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\tgit add --allow-embedded-repo embed 2>stderr &&\n+\ttest_i18ngrep ! fatal stderr\n+'\n+\n+test_expect_success '--no-warn-embedded-repo dies and suppresses advice' '\n+\ttest_must_fail git add --no-warn-embedded-repo embed 2>stderr &&\n+\ttest_i18ngrep ! hint stderr &&\n+\ttest_i18ngrep fatal stderr\n '\n \n-test_expect_success 'no warning when updating entry' '\n+test_expect_success 'no error message when updating entry' '\n \ttest_when_finished \"git rm --cached -f embed\" &&\n-\tgit add embed &&\n+\tgit add --allow-embedded-repo embed &&\n \tgit -C embed commit --allow-empty -m two &&\n \tgit add embed 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\ttest_i18ngrep ! fatal stderr\n '\n \n-test_expect_success 'submodule add does not warn' '\n+test_expect_success 'submodule add neither fails nor issues error message' '\n \ttest_when_finished \"git rm -rf submodule .gitmodules\" &&\n \tgit -c protocol.file.allow=always \\\n \t\tsubmodule add ./embed submodule 2>stderr &&\n-\ttest_i18ngrep ! warning stderr\n+\ttest_i18ngrep ! fatal stderr\n '\n \n test_done\ndiff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\nindex ba1f569bcb..4b3010c9e2 100755\n--- a/t/t7450-bad-git-dotfiles.sh\n+++ b/t/t7450-bad-git-dotfiles.sh\n@@ -307,7 +307,7 @@ test_expect_success 'git dirs of sibling submodules must not be nested' '\n \t\tEOF\n \t\tgit clone . thing1 &&\n \t\tgit clone . thing2 &&\n-\t\tgit add .gitmodules thing1 thing2 &&\n+\t\tgit add --allow-embedded-repo .gitmodules thing1 thing2 &&\n \t\ttest_tick &&\n \t\tgit commit -m nested\n \t) &&\n-- \n2.39.2.722.g9855ee24e9-goog\n\n"},{"id":"472862","messageId":"xmqqttz5pduy.fsf@gitster.g","threadId":"59235","inReplyTo":"20230228185642.2357806-2-calvinwan@google.com","subject":"Re: [PATCH v2 2/6] tests: Use `git submodule add` instead of `git add`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-28T23:30:29Z","receivedAt":"2023-02-28T23:30:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n> index b2bdd1fcb4..dd2858648b 100755\n> --- a/t/t2013-checkout-submodule.sh\n> +++ b/t/t2013-checkout-submodule.sh\n> @@ -10,7 +10,7 @@ test_expect_success 'setup' '\n>  \t(cd submodule &&\n>  \t git init &&\n>  \t test_commit first) &&\n> -\tgit add submodule &&\n> +\tgit submodule add ./submodule &&\n\nThe change from \"submodule\" to \"./submodule\" was not explained in\nthe proposed log message.  I think this is necessary for \"git\nsubmodule add\" to function as expected, but if that is why we are\nmaking this change, perhaps we should mention it?\n\n> @@ -51,6 +51,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .gitm\n>  \tgit config diff.ignoreSubmodules none &&\n>  \tgit config -f .gitmodules submodule.submodule.path submodule &&\n>  \tgit config -f .gitmodules submodule.submodule.ignore untracked &&\n> +\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n\nWhat does \"patterns\" refer here (another one in the next hunk)?\n\n> diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\n> index e9451cd567..11bc136f6e 100755\n> --- a/t/t2103-update-index-ignore-missing.sh\n> +++ b/t/t2103-update-index-ignore-missing.sh\n> @@ -36,7 +36,7 @@ test_expect_success basics '\n>  \t\tgit add file &&\n>  \t\tgit commit -m \"sub initial\"\n>  \t) &&\n> -\tgit add xyzzy &&\n> +\tgit add ./xyzzy &&\n\nIs this supposed to have become \"git submodule add ./xyzzy\"?  Or\n\"git add xyzzy\" will trigger \"don't add gitlink\" warning but you can\nwrite \"git add ./xyzzy\" as a way to work around the warning?\n\nOr is this an incomplete change that wasn't spotted during\nproofreading?\n\n> diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\n> index 302e4cbdba..f8ef70b5a2 100755\n> --- a/t/t5531-deep-submodule-push.sh\n> +++ b/t/t5531-deep-submodule-push.sh\n> @@ -28,7 +28,7 @@ test_expect_success setup '\n>  \t\t\tgit add junk &&\n>  \t\t\tgit commit -m \"Initial junk\"\n>  \t\t) &&\n> -\t\tgit add gar/bage &&\n> +\t\tgit submodule add ./gar/bage ./gar/bage &&\n\nWhy does this one (and only this one) look different?  Everybody\nelse changed \"git add A\" to \"git submodule add ./A\", it seems?\n\n> diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\n> ...\n\nI think I saw a code section that was touched in the previous patch\nthat hand-crafted .gitmodules file to make the gitlink it adds into\na submodule.  It is unexpected and puzzling that there is no removal\nof that \"cat >.gitmodules\" from t4060.\n\n"},{"id":"472863","messageId":"xmqqpm9tpdmw.fsf@gitster.g","threadId":"59235","inReplyTo":"20230228185642.2357806-5-calvinwan@google.com","subject":"Re: [PATCH v2 5/6] tests: remove duplicate .gitmodules path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-02-28T23:35:19Z","receivedAt":"2023-02-28T23:35:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Swapping `git add <submodule>` to `git submodule add <submodule>`\n> in a previous patch created a .gitmodules file with multiple\n> submodules pointing to the same path in certain tests. Fix tests\n> so that they are run on the original added submodule rather than\n> a separate manually configured submodule.\n\nDoesn't \"git submodule add\" have a way to give a specific name other\nthan the default taken from the path?  If \"git add sub\" is converted\nto \"git submodule add --name subname ./sub\", wouldn't these changes\nbecome unnecessary?\n\n"},{"id":"472943","messageId":"CAFySSZBqN+a-mP=+epz4rELYH_aLnrTC+VRFFTvib0W0nUBQ2Q@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqpm9tpdmw.fsf@gitster.g","subject":"Re: [PATCH v2 5/6] tests: remove duplicate .gitmodules path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-03-02T23:09:54Z","receivedAt":"2023-03-02T23:10:09Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Tue, Feb 28, 2023 at 3:35 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > Swapping `git add <submodule>` to `git submodule add <submodule>`\n> > in a previous patch created a .gitmodules file with multiple\n> > submodules pointing to the same path in certain tests. Fix tests\n> > so that they are run on the original added submodule rather than\n> > a separate manually configured submodule.\n>\n> Doesn't \"git submodule add\" have a way to give a specific name other\n> than the default taken from the path?  If \"git add sub\" is converted\n> to \"git submodule add --name subname ./sub\", wouldn't these changes\n> become unnecessary?\n>\n\nIf we converted to \"git submodule add --name subname ./sub\", we would\ninstead have a different set of problems. For example, instances of\ngit config --add -f .gitmodules submodule.subname.path sub\ngit config -f .gitmodules submodule.subname.path sub\nand other similar lines would still need to be removed to prevent duplicate\npaths. That, however, seems like a better alternative than my current\npatch which replaces those removals with different ones.\n"},{"id":"472946","messageId":"CAFySSZDeZ-HHPsh9noX1xqGfdzkRALwH0DRzcG3XPUKp57P-rg@mail.gmail.com","threadId":"59235","inReplyTo":"xmqqttz5pduy.fsf@gitster.g","subject":"Re: [PATCH v2 2/6] tests: Use `git submodule add` instead of `git add`","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-03-03T00:16:24Z","receivedAt":"2023-03-03T00:16:39Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Tue, Feb 28, 2023 at 3:30 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n> > index b2bdd1fcb4..dd2858648b 100755\n> > --- a/t/t2013-checkout-submodule.sh\n> > +++ b/t/t2013-checkout-submodule.sh\n> > @@ -10,7 +10,7 @@ test_expect_success 'setup' '\n> >       (cd submodule &&\n> >        git init &&\n> >        test_commit first) &&\n> > -     git add submodule &&\n> > +     git submodule add ./submodule &&\n>\n> The change from \"submodule\" to \"./submodule\" was not explained in\n> the proposed log message.  I think this is necessary for \"git\n> submodule add\" to function as expected, but if that is why we are\n> making this change, perhaps we should mention it?\n\nack.\n\n>\n> > @@ -51,6 +51,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .gitm\n> >       git config diff.ignoreSubmodules none &&\n> >       git config -f .gitmodules submodule.submodule.path submodule &&\n> >       git config -f .gitmodules submodule.submodule.ignore untracked &&\n> > +     git commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n>\n> What does \"patterns\" refer here (another one in the next hunk)?\n\n\"patterns\" seems unnecessary here. \"Update .gitmodules\" is more than\nsufficient.\n\n>\n> > diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\n> > index e9451cd567..11bc136f6e 100755\n> > --- a/t/t2103-update-index-ignore-missing.sh\n> > +++ b/t/t2103-update-index-ignore-missing.sh\n> > @@ -36,7 +36,7 @@ test_expect_success basics '\n> >               git add file &&\n> >               git commit -m \"sub initial\"\n> >       ) &&\n> > -     git add xyzzy &&\n> > +     git add ./xyzzy &&\n>\n> Is this supposed to have become \"git submodule add ./xyzzy\"?  Or\n> \"git add xyzzy\" will trigger \"don't add gitlink\" warning but you can\n> write \"git add ./xyzzy\" as a way to work around the warning?\n>\n> Or is this an incomplete change that wasn't spotted during\n> proofreading?\n\nThe latter. Missed this one when I was reverting the change from v1.\n\n>\n> > diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh\n> > index 302e4cbdba..f8ef70b5a2 100755\n> > --- a/t/t5531-deep-submodule-push.sh\n> > +++ b/t/t5531-deep-submodule-push.sh\n> > @@ -28,7 +28,7 @@ test_expect_success setup '\n> >                       git add junk &&\n> >                       git commit -m \"Initial junk\"\n> >               ) &&\n> > -             git add gar/bage &&\n> > +             git submodule add ./gar/bage ./gar/bage &&\n>\n> Why does this one (and only this one) look different?  Everybody\n> else changed \"git add A\" to \"git submodule add ./A\", it seems?\n\nThe second ./gar/bage is to define the submodule path. Without it,\nsubmodule add attempts to add it to ./bage instead of ./gar/bage.\nThis is unique only to this test since the submodule is 2 folders deep.\n\n>\n> > diff --git a/t/t6437-submodule-merge.sh b/t/t6437-submodule-merge.sh\n> > ...\n>\n> I think I saw a code section that was touched in the previous patch\n> that hand-crafted .gitmodules file to make the gitlink it adds into\n> a submodule.  It is unexpected and puzzling that there is no removal\n> of that \"cat >.gitmodules\" from t4060.\n>\n\nI have gone ahead and removed the \"cat >.gitmodules\" from t4060, and\nfixed the subsequent tests that were affected by that\n"},{"id":"473079","messageId":"kl6l8rg9ekvz.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-1-calvinwan@google.com","subject":"Re: [PATCH v2 1/6] t4041, t4060: modernize test style","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-06T19:32:16Z","receivedAt":"2023-03-06T19:32:22Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> In preparation for later changes, move setup code into test_expect\n> blocks. Smaller sections are moved into existing blocks, while larger\n> sections with a standalone purpose are given their own new blocks.\n\nThe changes where we moved lines outside of blocks into blocks without\nchanging them look good to me.\n\n> While at it, have tests clean up after themselves with\n> test_when_finished\n\nI believe this came about as part of the discussion in\n\n  https://lore.kernel.org/git/xmqqedqtbbf4.fsf@gitster.g\n\nI think it's good to have tests clean up after themselves, but I'm not\nsure if that's what we're doing in all of these cases, see below.\n\nI'm leaving the diff header in place, since the two files have very\nconfusingly similar tests.\n\n> diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\n>  test_expect_success 'typechanged submodule(submodule->blob)' '\n> +\ttest_when_finished rm -rf sm1 &&\n>  \tgit diff --submodule=log >actual &&\n>  \tcat >expected <<-EOF &&\n>  \tdiff --git a/sm1 b/sm1\n\nThis hunk and the next...\n\n> @@ -212,9 +215,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n>  \ttest_cmp expected actual\n>  '\n>  \n> -rm -rf sm1 &&\n> -git checkout-index sm1\n>  test_expect_success 'typechanged submodule(submodule->blob)' '\n> +\ttest_when_finished rm -f sm1 &&\n> +\tgit checkout-index sm1 &&\n>  \tgit diff-index -p --submodule=log HEAD >actual &&\n>  \tcat >expected <<-EOF &&\n>  \tSubmodule sm1 $head4...0000000 (submodule deleted)\n\nwere changed so that the \"rm -rf\" happens in the clean up phase of the\nearlier test (test 14) instead of set up phase of the later test (test\n15). But, the \"rm -rf\" actually results in a _different_ state from\nbefore 14, so it isn't actually cleaning up, it really is preparation\nfor 15's git checkout-index.\n\nYou can observe this by running\n\n  ./t4041-diff-submodule-option.sh --run=1-13,15\n\nwhich fails as expected. On the other hand, it passes if we move the \"rm\n-rf\" into test 15.\n\nNearly all of the other test_when_finished here have the same problem,\nwhere they 'clean up' state that wasn't changed in the same test body. I\nbelieve they will show similar dependency issues, though I didn't go\nthrough and test them all.\n\n> @@ -643,7 +643,6 @@ test_expect_success 'modified submodule contains modified content' '\n>  \tdiff_cmp expected actual\n>  '\n>  \n> -rm -rf sm1\n>  test_expect_success 'deleted submodule' '\n>  \tgit diff-index -p --submodule=diff HEAD >actual &&\n>  \tcat >expected <<-EOF &&\n\nThis one is fairly obvious, since the test says 'deleted submodule', but\nwe no longer delete the submodule in the setup.\n\n> @@ -779,9 +780,8 @@ test_expect_success 'diff --submodule=diff with .git file' '\n>  \tdiff_cmp expected actual\n>  '\n>  \n> -mv sm2 sm2-bak\n> -\n>  test_expect_success 'deleted submodule with .git file' '\n> +\tmv sm2 sm2-bak &&\n>  \tgit diff-index -p --submodule=diff HEAD >actual &&\n>  \tcat >expected <<-EOF &&\n>  \tSubmodule sm1 $head7...0000000 (submodule deleted)\n> @@ -804,9 +804,9 @@ test_expect_success 'deleted submodule with .git file' '\n>  \tdiff_cmp expected actual\n>  '\n>  \n> -echo submodule-to-blob>sm2\n> -\n>  test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n> +\ttest_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n> +\techo submodule-to-blob>sm2 &&\n>  \tgit diff-index -p --submodule=diff HEAD >actual &&\n>  \tcat >expected <<-EOF &&\n>  \tSubmodule sm1 $head7...0000000 (submodule deleted)\n> @@ -836,9 +836,6 @@ test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n>  \tdiff_cmp expected actual\n>  '\n>  \n> -rm sm2\n> -mv sm2-bak sm2\n\nThis is the original case that Junio flagged, which I think is an almost\ncorrect use of test_when_finished, since we do get back to an earlier\nstate before this string of tests, but not to the state before the\nactual test with the test_when_finished.\n\nIf we want to use test_when_finished here (which I think we do), we\nshould add another test_when_finished to remove the dependency between\nthe two tests. like so:\n\n  test_expect_success 'deleted submodule with .git file' '\n  +\ttest_when_finished \"mv sm2-bak sm2\" &&\n  \tmv sm2 sm2-bak &&\n    git diff-index -p --submodule=diff HEAD >actual &&\n\n...\n\n test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n\ttest_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n+ mv sm2 sm2-bak &&\n\nCurrently, they're still dependent because one creates sm2-bak and the\nother moves it back, but if we have each test restore sm2, there will be\nno more dependency.\n\n"},{"id":"473083","messageId":"CAFySSZDF5V6nV2uyg0NSvVGgG_ybSpeqGPi7CPSvsyZ10KfYwA@mail.gmail.com","threadId":"59235","inReplyTo":"kl6l8rg9ekvz.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 1/6] t4041, t4060: modernize test style","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-03-06T20:40:43Z","receivedAt":"2023-03-06T20:40:59Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Mon, Mar 6, 2023 at 11:32 AM Glen Choo <chooglen@google.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > In preparation for later changes, move setup code into test_expect\n> > blocks. Smaller sections are moved into existing blocks, while larger\n> > sections with a standalone purpose are given their own new blocks.\n>\n> The changes where we moved lines outside of blocks into blocks without\n> changing them look good to me.\n>\n> > While at it, have tests clean up after themselves with\n> > test_when_finished\n>\n> I believe this came about as part of the discussion in\n>\n>   https://lore.kernel.org/git/xmqqedqtbbf4.fsf@gitster.g\n>\n> I think it's good to have tests clean up after themselves, but I'm not\n> sure if that's what we're doing in all of these cases, see below.\n>\n> I'm leaving the diff header in place, since the two files have very\n> confusingly similar tests.\n>\n> > diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\n> >  test_expect_success 'typechanged submodule(submodule->blob)' '\n> > +     test_when_finished rm -rf sm1 &&\n> >       git diff --submodule=log >actual &&\n> >       cat >expected <<-EOF &&\n> >       diff --git a/sm1 b/sm1\n>\n> This hunk and the next...\n>\n> > @@ -212,9 +215,9 @@ test_expect_success 'typechanged submodule(submodule->blob)' '\n> >       test_cmp expected actual\n> >  '\n> >\n> > -rm -rf sm1 &&\n> > -git checkout-index sm1\n> >  test_expect_success 'typechanged submodule(submodule->blob)' '\n> > +     test_when_finished rm -f sm1 &&\n> > +     git checkout-index sm1 &&\n> >       git diff-index -p --submodule=log HEAD >actual &&\n> >       cat >expected <<-EOF &&\n> >       Submodule sm1 $head4...0000000 (submodule deleted)\n>\n> were changed so that the \"rm -rf\" happens in the clean up phase of the\n> earlier test (test 14) instead of set up phase of the later test (test\n> 15). But, the \"rm -rf\" actually results in a _different_ state from\n> before 14, so it isn't actually cleaning up, it really is preparation\n> for 15's git checkout-index.\n>\n> You can observe this by running\n>\n>   ./t4041-diff-submodule-option.sh --run=1-13,15\n>\n> which fails as expected. On the other hand, it passes if we move the \"rm\n> -rf\" into test 15.\n>\n> Nearly all of the other test_when_finished here have the same problem,\n> where they 'clean up' state that wasn't changed in the same test body. I\n> believe they will show similar dependency issues, though I didn't go\n> through and test them all.\n\nGood catch. I'll go thru the rest of them and remove the dependency\nissues.\n\n>\n> > @@ -643,7 +643,6 @@ test_expect_success 'modified submodule contains modified content' '\n> >       diff_cmp expected actual\n> >  '\n> >\n> > -rm -rf sm1\n> >  test_expect_success 'deleted submodule' '\n> >       git diff-index -p --submodule=diff HEAD >actual &&\n> >       cat >expected <<-EOF &&\n>\n> This one is fairly obvious, since the test says 'deleted submodule', but\n> we no longer delete the submodule in the setup.\n>\n> > @@ -779,9 +780,8 @@ test_expect_success 'diff --submodule=diff with .git file' '\n> >       diff_cmp expected actual\n> >  '\n> >\n> > -mv sm2 sm2-bak\n> > -\n> >  test_expect_success 'deleted submodule with .git file' '\n> > +     mv sm2 sm2-bak &&\n> >       git diff-index -p --submodule=diff HEAD >actual &&\n> >       cat >expected <<-EOF &&\n> >       Submodule sm1 $head7...0000000 (submodule deleted)\n> > @@ -804,9 +804,9 @@ test_expect_success 'deleted submodule with .git file' '\n> >       diff_cmp expected actual\n> >  '\n> >\n> > -echo submodule-to-blob>sm2\n> > -\n> >  test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n> > +     test_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n> > +     echo submodule-to-blob>sm2 &&\n> >       git diff-index -p --submodule=diff HEAD >actual &&\n> >       cat >expected <<-EOF &&\n> >       Submodule sm1 $head7...0000000 (submodule deleted)\n> > @@ -836,9 +836,6 @@ test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n> >       diff_cmp expected actual\n> >  '\n> >\n> > -rm sm2\n> > -mv sm2-bak sm2\n>\n> This is the original case that Junio flagged, which I think is an almost\n> correct use of test_when_finished, since we do get back to an earlier\n> state before this string of tests, but not to the state before the\n> actual test with the test_when_finished.\n>\n> If we want to use test_when_finished here (which I think we do), we\n> should add another test_when_finished to remove the dependency between\n> the two tests. like so:\n>\n>   test_expect_success 'deleted submodule with .git file' '\n>   +     test_when_finished \"mv sm2-bak sm2\" &&\n>         mv sm2 sm2-bak &&\n>     git diff-index -p --submodule=diff HEAD >actual &&\n>\n> ...\n>\n>  test_expect_success 'typechanged(submodule->blob) submodule with .git file' '\n>         test_when_finished \"rm sm2 && mv sm2-bak sm2\" &&\n> + mv sm2 sm2-bak &&\n>\n> Currently, they're still dependent because one creates sm2-bak and the\n> other moves it back, but if we have each test restore sm2, there will be\n> no more dependency.\n>\n\nThat all makes sense. Thanks for the recommendations\n"},{"id":"473085","messageId":"kl6l5ybdeflj.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-2-calvinwan@google.com","subject":"Re: [PATCH v2 2/6] tests: Use `git submodule add` instead of `git add`","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-06T21:26:32Z","receivedAt":"2023-03-06T21:26:43Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n>                                           This commit cleans up such\n> test cases where minimal other changes are required (e.g., committing\n> later changes to .gitmodules or changing the counts of committed files\n> in the worktree).\n\nOkay, though perhaps not detailed enough to explain why these changes\nwere needed in some circumstances. It might be helpful to explain the\nexact differences that you are adjusting for, i.e.:\n\n- 'git submodule add' requires a './'-prefixed path\n- 'git submodule add' changes and tracks .gitmodules\n\n> diff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\n> index b2bdd1fcb4..dd2858648b 100755\n> --- a/t/t2013-checkout-submodule.sh\n> +++ b/t/t2013-checkout-submodule.sh\n> @@ -10,7 +10,7 @@ test_expect_success 'setup' '\n>  \t(cd submodule &&\n>  \t git init &&\n>  \t test_commit first) &&\n> -\tgit add submodule &&\n> +\tgit submodule add ./submodule &&\n>  \ttest_tick &&\n>  \tgit commit -m superproject &&\n>  \t(cd submodule &&\n\nJunio mentioned that the change from submodule to ./submodule was\nsurprising, but this seemed quite clear to me. Maybe that's just a sign\nthat I've worked on submodules for too long.\n\n> @@ -51,6 +51,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .gitm\n>  \tgit config diff.ignoreSubmodules none &&\n>  \tgit config -f .gitmodules submodule.submodule.path submodule &&\n>  \tgit config -f .gitmodules submodule.submodule.ignore untracked &&\n> +\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n>  \tgit checkout HEAD >actual 2>&1 &&\n>  \ttest_must_be_empty actual\n>  '\n> @@ -59,6 +60,7 @@ test_expect_success '\"checkout <submodule>\" honors submodule.*.ignore from .git/\n>  \tgit config -f .gitmodules submodule.submodule.ignore none &&\n>  \tgit config submodule.submodule.path submodule &&\n>  \tgit config submodule.submodule.ignore all &&\n> +\tgit commit -m \"Update patterns in .gitmodules\" .gitmodules &&\n>  \tgit checkout HEAD >actual 2>&1 &&\n>  \ttest_must_be_empty actual\n\nI puzzled a lot over why these changes were necessary. The answer is\nthat .gitmodules was formerly untracked, so it didn't show up in the\nlist of files during checkout. But, now that we use 'git submodule add',\nwe do track .gitmodules, so we instead 'fix' the test by committing the\n.gitmodules. This one is unobvious enough that I think it's worth\ncalling out specifically in the commit message.\n"},{"id":"473094","messageId":"kl6lsfehihdv.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-3-calvinwan@google.com","subject":"Re: [PATCH v2 3/6] tests: use `git submodule add` and fix expected diffs","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-06T23:34:20Z","receivedAt":"2023-03-06T23:34:26Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> This commit continues the previous work of updating the test suite to\n> use `git submodule add` to create submodules instead of using `git add`\n> to include embedded repositories. Specifically, in this commit we update\n> test cases where expected diffs must change due to the presence of a\n> .gitmodules file.\n\nAdjusting the diff makes sense when the .gitmodules file is relevant to\nthe diff being tested.\n\n> diff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh\n> index 61da7e3b94..a0f14db3d2 100755\n> --- a/t/t3040-subprojects-basic.sh\n> +++ b/t/t3040-subprojects-basic.sh\n> @@ -19,11 +19,12 @@ test_expect_success 'setup: create subprojects' '\n>  \t( cd sub2 && git init && : >Makefile && git add * &&\n>  \tgit commit -q -m \"subproject 2\" ) &&\n>  \tgit update-index --add sub1 &&\n> -\tgit add sub2 &&\n> +\tgit submodule add ./sub2 &&\n>  \tgit commit -q -m \"subprojects added\" &&\n>  \tGIT_PRINT_SHA1_ELLIPSIS=\"yes\" git diff-tree --abbrev=5 HEAD^ HEAD |cut -d\" \" -f-3,5- >current &&\n>  \tgit branch save HEAD &&\n>  \tcat >expected <<-\\EOF &&\n> +\t:000000 100644 00000... A\t.gitmodules\n>  \t:000000 160000 00000... A\tsub1\n>  \t:000000 160000 00000... A\tsub2\n>  \tEOF\n\ne.g. this change makes sense\n\n> diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh\n> index 2aa12243bd..f5074071a4 100755\n> --- a/t/t4041-diff-submodule-option.sh\n> +++ b/t/t4041-diff-submodule-option.sh\n> @@ -50,9 +50,19 @@ test_expect_success 'setup' '\n>  '\n>  \n>  test_expect_success 'added submodule' '\n> -\tgit add sm1 &&\n> +\tgit submodule add ./sm1 &&\n> +\tgitmodules_hash1=$(git rev-parse --short $(git hash-object .gitmodules)) &&\n>  \tgit diff-index -p --submodule=log HEAD >actual &&\n>  \tcat >expected <<-EOF &&\n> +\tdiff --git a/.gitmodules b/.gitmodules\n> +\tnew file mode 100644\n> +\tindex 0000000..$gitmodules_hash1\n> +\t--- /dev/null\n> +\t+++ b/.gitmodules\n> +\t@@ -0,0 +1,3 @@\n> +\t+[submodule \"sm1\"]\n> +\t+\tpath = sm1\n> +\t+\turl = ./sm1\n>  \tSubmodule sm1 0000000...$head1 (new submodule)\n>  \tEOF\n>  \ttest_cmp expected actual\n\nBut in this file and the next (t4041 and t4060), we are checking\nsubmodule diffing behavior, so wouldn't it make sense to ignore\nnon-submodule changes in the diff?\n\nE.g. we could have ignored .gitmodules during the diff like so\n\n  test_expect_success 'added submodule' '\n          git submodule add ./sm1 &&\n          gitmodules_hash1=$(git rev-parse --short $(git hash-object .gitmodules)) &&\n  -       git diff-index -p --submodule=log HEAD >actual &&\n  +       git diff-index -p --submodule=log HEAD -- :!.gitmodules >actual &&\n\nand then we wouldn't have to adjust the diff. That would be my preferred\napproach, since it keeps the irrelevant details out of the test.\n\nTo play devil's advocate, there's a small integration test-style benefit\nto testing both a regular file diff and a submodule diff together. I\nhaven't checked if these are the only files that are testing this, but\neven if not, checking .gitmodules repeatedly seems like a suboptimal way\nto do this.\n\n> @@ -243,7 +244,7 @@ test_expect_success 'status -a clean (empty submodule dir)' '\n>  '\n>  \n>  cat >status_expect <<\\EOF\n> -AA .gitmodules\n> +UU .gitmodules\n>  A  sub1\n>  EOF\n\n_Maybe_ this is worth modernizing too as a 'while we're at it' kind of\nchange, though it's far less important than the earlier patch (where the\nsetup actually touches the Git repo and submodules). Idk.\n"},{"id":"473095","messageId":"xmqqlek977se.fsf@gitster.g","threadId":"59235","inReplyTo":"kl6lsfehihdv.fsf@chooglen-macbookpro.roam.corp.google.com","subject":"Re: [PATCH v2 3/6] tests: use `git submodule add` and fix expected diffs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-03-06T23:57:05Z","receivedAt":"2023-03-06T23:57:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Glen Choo <chooglen@google.com> writes:\n\n> E.g. we could have ignored .gitmodules during the diff like so\n>\n>   test_expect_success 'added submodule' '\n>           git submodule add ./sm1 &&\n>           gitmodules_hash1=$(git rev-parse --short $(git hash-object .gitmodules)) &&\n>   -       git diff-index -p --submodule=log HEAD >actual &&\n>   +       git diff-index -p --submodule=log HEAD -- :!.gitmodules >actual &&\n>\n> and then we wouldn't have to adjust the diff. That would be my preferred\n> approach, since it keeps the irrelevant details out of the test.\n\nYes, it certainly does make the diff simpler to read, but the\nreasoning cuts both ways.\n\nThe end-goal of the topic is to propose that updating .gitmodules is\nan integral part of \"adding a submodule\" and to make it impossible\nto just add gitlink without a command line option using \"git add\",\nso from that point of view, readers would expect that the diff after\n\"adding a submodule\" to have both new gitlink and also a modified\n(or if this were the first submodule, added) \".gitmodules\" file.\n"},{"id":"473096","messageId":"kl6lpm9lifhz.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-4-calvinwan@google.com","subject":"Re: [PATCH v2 4/6] tests: use `git submodule add` and fix expected status","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-07T00:15:04Z","receivedAt":"2023-03-07T00:15:10Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> @@ -122,25 +123,30 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)'\n>  '\n>  \n>  test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match) [.gitmodules]' '\n> +\tgit branch pristine-gitmodules &&\n>  \tgit config diff.ignoreSubmodules dirty &&\n>  \tgit diff HEAD >actual &&\n>  \ttest_must_be_empty actual &&\n>  \tgit config --add -f .gitmodules submodule.subname.ignore none &&\n>  \tgit config --add -f .gitmodules submodule.subname.path sub &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual &&\n>  \tsed -e \"1,/^@@/d\" actual >actual.body &&\n>  \texpect_from_to >expect.body $subprev $subprev-dirty &&\n>  \ttest_cmp expect.body actual.body &&\n>  \tgit config -f .gitmodules submodule.subname.ignore all &&\n>  \tgit config -f .gitmodules submodule.subname.path sub &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual2 &&\n>  \ttest_must_be_empty actual2 &&\n>  \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual3 &&\n>  \tsed -e \"1,/^@@/d\" actual3 >actual3.body &&\n>  \texpect_from_to >expect.body $subprev $subprev-dirty &&\n>  \ttest_cmp expect.body actual3.body &&\n>  \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual4 &&\n>  \ttest_must_be_empty actual4 &&\n>  \tgit config submodule.subname.ignore none &&\n> @@ -152,7 +158,7 @@ test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)\n>  \tgit config --remove-section submodule.subname &&\n>  \tgit config --remove-section -f .gitmodules submodule.subname &&\n>  \tgit config --unset diff.ignoreSubmodules &&\n> -\trm .gitmodules\n> +\tgit reset --hard pristine-gitmodules\n>  '\n\nThis looks like the perfect use case for test_when_finished :)\n\n> @@ -190,12 +196,15 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n>  test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n>  \tgit config --add -f .gitmodules submodule.subname.ignore all &&\n>  \tgit config --add -f .gitmodules submodule.subname.path sub &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual2 &&\n>  \ttest_must_be_empty actual2 &&\n>  \tgit config -f .gitmodules submodule.subname.ignore untracked &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual3 &&\n>  \ttest_must_be_empty actual3 &&\n>  \tgit config -f .gitmodules submodule.subname.ignore dirty &&\n> +\tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual4 &&\n>  \ttest_must_be_empty actual4 &&\n>  \tgit config submodule.subname.ignore none &&\n\nLike the previous patch, I wonder a little whether we should be diffing\nwith :!.gitmodules, but at least here we are focused on diffing with\nsubmodules in general (and not the specific \"git diff --submodule=\"\nbehavior), so I thnk this is okay to keep.\n\n> @@ -206,7 +215,7 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)\n>  \ttest_cmp expect.body actual.body &&\n>  \tgit config --remove-section submodule.subname &&\n>  \tgit config --remove-section -f .gitmodules submodule.subname &&\n> -\trm .gitmodules\n> +\tgit reset --hard pristine-gitmodules\n\nDitto about test_when_finished.\n\n>  '\n>  \n>  test_expect_success 'git diff between submodule commits' '\n> @@ -243,7 +252,7 @@ test_expect_success 'git diff between submodule commits [.gitmodules]' '\n>  \texpect_from_to >expect.body $subtip $subprev &&\n>  \tgit config --remove-section submodule.subname &&\n>  \tgit config --remove-section -f .gitmodules submodule.subname &&\n> -\trm .gitmodules\n> +\tgit reset --hard pristine-gitmodules\n>  '\n>  \n\nDitto\n\n> @@ -1152,8 +1156,37 @@ test_expect_success '.gitmodules ignore=untracked suppresses submodules with unt\n>  \ttest_cmp expect output &&\n>  \tgit config --add -f .gitmodules submodule.subname.ignore untracked &&\n>  \tgit config --add -f .gitmodules submodule.subname.path sm &&\n> +\tcat > expect-modified-gitmodules << EOF &&\n> +On branch main\n> +Your branch and '\\''upstream'\\'' have diverged,\n> +and have 2 and 2 different commits each, respectively.\n> +  (use \"git pull\" to merge the remote branch into yours)\n> +\n> +Changes to be committed:\n> +  (use \"git restore --staged <file>...\" to unstage)\n> +\tmodified:   sm\n> +\n> +Changes not staged for commit:\n> +  (use \"git add <file>...\" to update what will be committed)\n> +  (use \"git restore <file>...\" to discard changes in working directory)\n> +\tmodified:   .gitmodules\n> +\tmodified:   dir1/modified\n> +\n> +Submodule changes to be committed:\n> +\n> +* sm $head...$new_head (1):\n> +  > Add bar\n> +\n> +Untracked files:\n> +  (use \"git add <file>...\" to include in what will be committed)\n> +\tdir1/untracked\n> +\tdir2/modified\n> +\tdir2/untracked\n> +\tuntracked\n> +\n> +EOF\n>  \tgit status >output &&\n> -\ttest_cmp expect output &&\n> +\ttest_cmp expect-modified-gitmodules output &&\n>  \tgit config -f .gitmodules  --remove-section submodule.subname\n>  '\n\nThat another giant snapshot makes me a bit wary, since it's harder to\ntell whether the \"modifed .gitmodules\" and \"unmodified .gitmodules\" are\nreally checking the same things, but there might not be a way around it.\nThe following tests check various combinations of values (dirty,\nuntracked, etc) and sources \"--ignore-submodules\", \".git/config ignore=\"\nand \".gitmodules ignore=\". For the .gitmodules tests, we really do have\nto modify .gitmodules to test that it gives us the behavior we want.\n\nAs a hack, we could preemptively modify .gitmodules, so that it's\nmodified in all of the snapshots we're diffing. That feels too hacky to\nme, but maybe others think it's fine.\n\n(Side note: I recall a previous conversation with Junio about how we\nshouldn't be changing behavior based on .gitmodules. If we had that, we\nwouldn't need to worry about this right now.)\n\n"},{"id":"473104","messageId":"kl6llek9idt8.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-5-calvinwan@google.com","subject":"Re: [PATCH v2 5/6] tests: remove duplicate .gitmodules path","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-07T00:51:31Z","receivedAt":"2023-03-07T00:51:36Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Swapping `git add <submodule>` to `git submodule add <submodule>`\n> in a previous patch created a .gitmodules file with multiple\n> submodules pointing to the same path in certain tests. Fix tests\n> so that they are run on the original added submodule rather than\n> a separate manually configured submodule.\n\nWithout reading the diff, I thought that having multiple configured\nsubmodules was a bug that needed to be fixed (I also wasn't sure which\nprevious patch was being referenced). But after reading the diff, this\nseems much more like a test simplification.\n\nI think this is might be better squashed with the previous patch (the\ncombined diff of both patches looks ok to me) with some extra\nclarification, e.g.:\n\n  In some of the tests, we modify .gitmodules to check whether the\n  value of \"submodule.subname.ignore\" is respected. When we were using\n  \"git add\", we also had to temporarily turn the gitlink into a\n  submodule by setting \"submodule.subname.path\", but since \"git\n  submodule add\" handles that for us, let's use the real submodule\n  instead.\n\n> @@ -194,27 +191,24 @@ test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)'\n>  '\n>  \n>  test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match) [.gitmodules]' '\n> -\tgit config --add -f .gitmodules submodule.subname.ignore all &&\n> -\tgit config --add -f .gitmodules submodule.subname.path sub &&\n> +\tgit config --add -f .gitmodules submodule.sub.ignore all &&\n>  \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual2 &&\n>  \ttest_must_be_empty actual2 &&\n> -\tgit config -f .gitmodules submodule.subname.ignore untracked &&\n> +\tgit config -f .gitmodules submodule.sub.ignore untracked &&\n>  \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual3 &&\n>  \ttest_must_be_empty actual3 &&\n> -\tgit config -f .gitmodules submodule.subname.ignore dirty &&\n> +\tgit config -f .gitmodules submodule.sub.ignore dirty &&\n>  \tgit commit -m \"Update .gitmodules\" .gitmodules &&\n>  \tgit diff HEAD >actual4 &&\n>  \ttest_must_be_empty actual4 &&\n> -\tgit config submodule.subname.ignore none &&\n> -\tgit config submodule.subname.path sub &&\n> +\tgit config submodule.sub.ignore none &&\n>  \tgit diff HEAD >actual &&\n>  \tsed -e \"1,/^@@/d\" actual >actual.body &&\n>  \texpect_from_to >expect.body $subprev $subprev-dirty &&\n>  \ttest_cmp expect.body actual.body &&\n> -\tgit config --remove-section submodule.subname &&\n> -\tgit config --remove-section -f .gitmodules submodule.subname &&\n> +\tgit config --unset submodule.sub.ignore &&\n>  \tgit reset --hard pristine-gitmodules\n>  '\n\nNot the fault of this patch, but I think that this diff would have been\neasier to read if the latter part were moved into \"test_when_finished\",\nand it would be clear that we are just undoing what we are setting up a\nfew lines earlier (instead of a whole test block earlier).\n"},{"id":"473106","messageId":"kl6lilfdiag7.fsf@chooglen-macbookpro.roam.corp.google.com","threadId":"59235","inReplyTo":"20230228185642.2357806-6-calvinwan@google.com","subject":"Re: [PATCH v2 6/6] add: reject nested repositories","fromName":"Glen Choo","fromEmail":"chooglen@google.com","sentAt":"2023-03-07T02:04:08Z","receivedAt":"2023-03-07T02:04:24Z","isPatch":true,"sender":{"key":"glencbz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58092771?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> At $dayjob, we have found that even this advice is insufficient to stop\n> users from committing unclonable embedded repos in shared projects.\n> This causes toil for the owners of the top-level project repository as\n> they must clean up the resulting gitlinks. Additionally, these mistakes\n> are often made by partners outside of $dayjob, which means that a simple\n> organization-wide change to the default Git config would be insufficient\n> to prevent these mistakes.\n>\n> Due to this experience, we believe that Git's default behavior should be\n> changed to disallow adding embedded repositories. This commit changes\n> the existing warning into a fatal error, rewrites the advice given, and\n> deprecates `--no-warn-embedded-repo` in favor of `--allow-embedded-repo`\n> to bypass the fatal error.\n\nSounds good, thanks.\n\n> ---no-warn-embedded-repo::\n> -\tBy default, `git add` will warn when adding an embedded\n> +--allow-embedded-repo::\n> +\tBy default, `git add` will error out when adding an embedded\n>  \trepository to the index without using `git submodule add` to\n> -\tcreate an entry in `.gitmodules`. This option will suppress the\n> -\twarning (e.g., if you are manually performing operations on\n> -\tsubmodules).\n> +\tcreate an entry in `.gitmodules`. This option will allow the\n> +\tembedded repository to be added. (e.g., if you are manually\n> +\tperforming operations on submodules).\n\nOkay.\n\n> +--no-warn-embedded-repo::\n> +\tThis option is deprecated in favor of '--add-embedded-repo'.\n> +\tPassing this option still suppresses advice but does not bypass\n> +\tthe error.\n\nHm, why would a user want to suppress the warning but still have \"git\nadd\" fail?\n\nIf this is for backwards compatibility, i.e. users get the same behavior\nif they pass \"--no-warn-embedded-repo\" before and after this patch, then\nshouldn't this also allow the embedded repo to be added (i.e. it is an\nalias of --allow-embedded-repo)?\n\n> @@ -409,48 +412,53 @@ static int add_config(const char *var, const char *value, void *cb)\n>  }\n>  \n>  static const char embedded_advice[] = N_(\n> -\"You've added another git repository inside your current repository.\\n\"\n> +\"You attempted to add another git repository inside your current repository.\\n\"\n>  \"Clones of the outer repository will not contain the contents of\\n\"\n>  \"the embedded repository and will not know how to obtain it.\\n\"\n>  \"If you meant to add a submodule, use:\\n\"\n>  \"\\n\"\n>  \"\tgit submodule add <url> %s\\n\"\n>  \"\\n\"\n> -\"If you added this path by mistake, you can remove it from the\\n\"\n> -\"index with:\\n\"\n> +\"See \\\"git help submodule\\\" for more information.\\n\"\n>  \"\\n\"\n> -\"\tgit rm --cached %s\\n\"\n> +\"If you cannot use submodules, you may bypass this check with:\\n\"\n>  \"\\n\"\n> -\"See \\\"git help submodule\\\" for more information.\"\n> +\"\tgit add --allow-embedded-repo %s\\n\"\n>  );\n\nIs there a particular reason you reordered the\n\n  \"See \\\"git help submodule\\\" for more information.\\n\"\n\nline? I personally like it at the end, and if a user is already used to\nlooking for it at the end, they can keep looking there.\n\n> -static void check_embedded_repo(const char *path)\n> +static int check_embedded_repo(const char *path)\n>  {\n> +\tint ret = 0;\n>  \tstruct strbuf name = STRBUF_INIT;\n>  \tstatic int adviced_on_embedded_repo = 0;\n>  \n> -\tif (!warn_on_embedded_repo)\n> -\t\treturn;\n> +\tif (allow_embedded_repo)\n> +\t\tgoto cleanup;\n>  \tif (!ends_with(path, \"/\"))\n> -\t\treturn;\n> +\t\tgoto cleanup;\n> +\n> +\tret = 1;\n>  \n>  \t/* Drop trailing slash for aesthetics */\n>  \tstrbuf_addstr(&name, path);\n>  \tstrbuf_strip_suffix(&name, \"/\");\n>  \n> -\twarning(_(\"adding embedded git repository: %s\"), name.buf);\n> +\terror(_(\"cannot add embedded git repository: %s\"), name.buf);\n>  \tif (!adviced_on_embedded_repo &&\n> -\t    advice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n> +\t\twarn_on_embedded_repo &&\n> +\t\tadvice_enabled(ADVICE_ADD_EMBEDDED_REPO)) {\n>  \t\tadvise(embedded_advice, name.buf, name.buf);\n>  \t\tadviced_on_embedded_repo = 1;\n>  \t}\n>  \n> +cleanup:\n>  \tstrbuf_release(&name);\n> +\treturn ret;\n>  }\n\nSo we give an error message when we first encounter the embedded repo,\nokay...\n\n>  static int add_files(struct dir_struct *dir, int flags)\n>  {\n> -\tint i, exit_status = 0;\n> +\tint i, exit_status = 0, embedded_repo = 0;\n>  \tstruct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;\n>  \n>  \tif (dir->ignored_nr) {\n> @@ -476,10 +484,13 @@ static int add_files(struct dir_struct *dir, int flags)\n>  \t\t\t\tdie(_(\"adding files failed\"));\n>  \t\t\texit_status = 1;\n>  \t\t} else {\n> -\t\t\tcheck_embedded_repo(dir->entries[i]->name);\n> +\t\t\tembedded_repo |= check_embedded_repo(dir->entries[i]->name);\n>  \t\t}\n>  \t}\n>  \n> +\tif (embedded_repo)\n> +\t\tdie(_(\"refusing to add embedded git repositories\"));\n> +\n\nAnd then we die(), giving a similar message again. That feels like\noverkill, but I'm not sure if it's unidiomatic.\n\nIs there a reason why we shouldn't just die() the first time we\nencounter the embedded repo? The difference is that in this patch, we\nactually add all of the non-submodule files before die()-ing, but I'm\nnot sure if that's what users would expect. Personally at least, I'd\nexpect \"git add\" to abort the moment it encountered something wrong.\n\n> diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh\n> index c70d11bc91..a53dac5931 100755\n> --- a/t/t0008-ignores.sh\n> +++ b/t/t0008-ignores.sh\n> @@ -191,7 +191,7 @@ test_expect_success 'setup' '\n>  \t\tgit add a &&\n>  \t\tgit commit -m\"commit in submodule\"\n>  \t) &&\n> -\tgit add a/submodule &&\n> +\tgit add --allow-embedded-repo a/submodule &&\n>  \tcat <<-\\EOF >.gitignore &&\n>  \t\tone\n>  \t\tignored-*\n\nGiven that --allow-embedded-repo is meant to be an escape hatch, and\nwe've already adjusted so many tests to avoid using it, I'd imagine that\nany uses of it in the test suite have to be quite well-justified. It\nwould have been helpful to see such a justification in the comments on\neach of the changes or some general principles in the commit message.\n\nI've tried testing most of these with \"git submodule add\". This one\nworks around a test failure in test 346 \"submodule\", which checks that\nignores should fail if the path is in the submodule, like\n\n\ttest_check_ignore \"a/submodule/one\" 128 &&\n\ttest_stderr \"fatal: Pathspec '\\''a/submodule/one'\\'' is in submodule '\\''a/submodule'\\''\"\n\nI don't understand why git-check-ignore should succeed on submodules but\nnot an embedded repo. I'll investigate more later.\n\n> diff --git a/t/t2103-update-index-ignore-missing.sh b/t/t2103-update-index-ignore-missing.sh\n> index 11bc136f6e..1ce4fc49fa 100755\n> --- a/t/t2103-update-index-ignore-missing.sh\n> +++ b/t/t2103-update-index-ignore-missing.sh\n> @@ -36,7 +36,7 @@ test_expect_success basics '\n>  \t\tgit add file &&\n>  \t\tgit commit -m \"sub initial\"\n>  \t) &&\n> -\tgit add ./xyzzy &&\n> +\tgit add --allow-embedded-repo ./xyzzy &&\n>  \n>  \ttest_tick &&\n>  \tgit commit -m initial &&\n\nThis seems to pass with \"git submodule add\", but maybe we don't want to\nintroduce .gitmodules into a low level test.\n\n> diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh\n> index 76f8034c60..bfd87891f4 100755\n> --- a/t/t4035-diff-quiet.sh\n> +++ b/t/t4035-diff-quiet.sh\n> @@ -66,7 +66,7 @@ test_expect_success 'git diff-index --cached HEAD^' '\n>  test_expect_success 'git diff-index --cached HEAD^' '\n>  \techo text >>b &&\n>  \techo 3 >c &&\n> -\tgit add . &&\n> +\tgit add --allow-embedded-repo . &&\n>  \ttest_expect_code 1 git diff-index --quiet --cached HEAD^ >cnt &&\n>  \ttest_line_count = 0 cnt\n>  '\n\nThis is also a low-level test for gitlinks in the index, so eliminating\nnoise from .gitmodules also seems okay I think.\n\n> diff --git a/t/t6430-merge-recursive.sh b/t/t6430-merge-recursive.sh\n> index 07067bb347..ae435fa492 100755\n> --- a/t/t6430-merge-recursive.sh\n> +++ b/t/t6430-merge-recursive.sh\n> @@ -677,7 +677,7 @@ test_expect_success 'merging with triple rename across D/F conflict' '\n>  \techo content3 >sub2/file3 &&\n>  \tmkdir simple &&\n>  \techo base >simple/bar &&\n> -\tgit add -A &&\n> +\tgit add -A --allow-embedded-repo &&\n>  \ttest_tick &&\n>  \tgit commit -m base &&\n>  \n\nSimilarly, this tests low-level gitlink merging, so eliminating\n.gitmodules sounds okay.\n\n> diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh\n> index eae6a46ef3..18ef9141b7 100755\n> --- a/t/t7400-submodule-basic.sh\n> +++ b/t/t7400-submodule-basic.sh\n> @@ -118,7 +118,7 @@ test_expect_success 'setup - repository in init subdirectory' '\n>  test_expect_success 'setup - commit with gitlink' '\n>  \techo a >a &&\n>  \techo z >z &&\n> -\tgit add a init z &&\n> +\tgit add --allow-embedded-repo a init z &&\n>  \tgit commit -m \"super commit 1\"\n>  '\n>  \n\nThis is needed because test 38\n\n  test_expect_success 'status should fail for unmapped paths' '\n    test_must_fail git submodule status\n  '\n\npresumably requires the submodule to not be in .gitmodules. This needs a\ncomment, I think.\n\n> @@ -771,7 +771,7 @@ test_expect_success 'set up for relative path tests' '\n>  \t\t\tgit init &&\n>  \t\t\ttest_commit foo\n>  \t\t) &&\n> -\t\tgit add sub &&\n> +\t\tgit add --allow-embedded-repo sub &&\n>  \t\tgit config -f .gitmodules submodule.sub.path sub &&\n>  \t\tgit config -f .gitmodules submodule.sub.url ../subrepo &&\n>  \t\tcp .git/config pristine-.git-config &&\n\nIn the next test, we're checking that \"git submodule init\" fixes a\ngitlink without .gitmodules. Okay. Might benefit from a comment.\n\n> diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\n> index 2859695c6d..d1662aa23c 100755\n> --- a/t/t7412-submodule-absorbgitdirs.sh\n> +++ b/t/t7412-submodule-absorbgitdirs.sh\n> @@ -100,7 +100,7 @@ test_expect_success 'absorb the git dir in a nested submodule' '\n>  test_expect_success 'setup a gitlink with missing .gitmodules entry' '\n>  \tgit init sub2 &&\n>  \ttest_commit -C sub2 first &&\n> -\tgit add sub2 &&\n> +\tgit add --allow-embedded-repo sub2 &&\n>  \tgit commit -m superproject\n>  '\n\nThe test is literally called 'setup a gitlink with missing .gitmodules\nentry', so okay.\n\n> diff --git a/t/t7450-bad-git-dotfiles.sh b/t/t7450-bad-git-dotfiles.sh\n> index ba1f569bcb..4b3010c9e2 100755\n> --- a/t/t7450-bad-git-dotfiles.sh\n> +++ b/t/t7450-bad-git-dotfiles.sh\n> @@ -307,7 +307,7 @@ test_expect_success 'git dirs of sibling submodules must not be nested' '\n>  \t\tEOF\n>  \t\tgit clone . thing1 &&\n>  \t\tgit clone . thing2 &&\n> -\t\tgit add .gitmodules thing1 thing2 &&\n> +\t\tgit add --allow-embedded-repo .gitmodules thing1 thing2 &&\n>  \t\ttest_tick &&\n>  \t\tgit commit -m nested\n>  \t) &&\n\nThis one can be adjusted. The important thing is that .gitmodules is bad\n_after_ we have \"git submodule add\"-ed the submodules, so this works:\n\n\tgit init nested &&\n\ttest_commit -C nested nested &&\n\t(\n\t\tcd nested &&\n\t\tgit clone . thing1 &&\n\t\tgit clone . thing2 &&\n\t\tgit submodule add ./thing1 &&\n\t\tgit submodule add ./thing2 &&\n\t\tcat >.gitmodules <<-EOF &&\n\t\t[submodule \"hippo\"]\n\t\t\turl = .\n\t\t\tpath = thing1\n\t\t[submodule \"hippo/hooks\"]\n\t\t\turl = .\n\t\t\tpath = thing2\n\t\tEOF\n\t\tgit add .gitmodules &&\n\t\ttest_tick &&\n\t\tgit commit -m nested\n\t) &&\n\ttest_must_fail git clone --recurse-submodules nested clone 2>err &&\n\ttest_i18ngrep \"is inside git dir\" err\n\n> -- \n> 2.39.2.722.g9855ee24e9-goog\n"}]}