{"thread":{"id":"63436","subject":"[PATCH 0/9] make stash apply with --index by default","startedAt":"2025-05-10T18:34:13Z","lastAt":"2025-10-14T02:19:03Z","messageCount":38,"participants":["D. Ben Knoble","Junio C Hamano","Phillip Wood","Kristoffer Haugsbakk","Ben Knoble"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"517745","messageId":"20250510183358.36806-1-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":null,"subject":"[PATCH 0/9] make stash apply with --index by default","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:35Z","receivedAt":"2025-05-10T18:34:13Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Since git-stash's inception, it has defaulted to stashing the index but not\nrestoring it. This has caused some confusion: change the default as part of Git\n3.0 to unstash the index, too.\n\nI ran into this myself a while back and did some digging; it appears that other\nhave been bit, too (see references in patch 3). Moreover, when git-stash was\noriginally written, defaulting with --index was suggested but not implemented\nbefore the script merged. So this RFC should bring us back towards \"less\nconfusing,\" hopefully.\n\nThe series is structured as follows:\n\nPatches 1-2: unrelated prep/style commits noticed while working on tests.\nPatch 3: update Documentation/BreakingChanges.adoc. This seems like a natural\n    place to discuss the proposal, so it contains no other changes.\nPatch 4: make it so in builtin/stash.c.\nPatches 5-9: update the impacted tests. Separated out for ease of review. I used\n    a style more like \"split the test into 2: one with, one without breaking\n    changes.\" In retrospect, the diff might be smaller (and the 2 versions of\n    the test easier to compare) if I used \"test_has_prereq\" in the tests… but at\n    the cost of making the tests harder to follow. Thoughts?\n\nD. Ben Knoble (9):\n  t3903: reduce dependencies on previous tests\n  t3905: remove unneeded blank line\n  BreakingChanges: announce stash {apply,pop} will imply --index\n  stash: restore the index by default when breaking changes are enabled\n  t0450: mark stash documentation as a known discrepancy\n  t3903: adjust stash test to account for --[no-]index with breaking\n    changes\n  t3904: adjust stash -p test to account for index states with breaking\n    changes\n  t3905: adjust stash -u tests for breaking changes\n  t3906: adjust stash submodule tests to account for breaking changes\n\n Documentation/BreakingChanges.adoc |  11 ++\n Documentation/git-stash.adoc       |   6 ++\n builtin/stash.c                    |  38 +++++++\n t/lib-submodule-update.sh          |  24 ++++-\n t/t0450/adoc-help-mismatches       |   1 +\n t/t3903-stash.sh                   | 161 +++++++++++++++++++++++++++--\n t/t3904-stash-patch.sh             |  14 ++-\n t/t3905-stash-include-untracked.sh |  40 ++++++-\n 8 files changed, 276 insertions(+), 19 deletions(-)\n\n\nbase-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n-- \n2.48.1\n\n"},{"id":"517746","messageId":"20250510183358.36806-2-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 1/9] t3903: reduce dependencies on previous tests","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:36Z","receivedAt":"2025-05-10T18:34:17Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Skipping previous tests to work through only failing tests with\narguments like --run=4,122- causes some tests to fail because subdir\ndoesn't exist yet (it is created by a previous test; typically\n\"unstashing in a subdirectory\"). Create it on demand for tests that need\nit, but don't fail (-p) if the directory already exists.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3903-stash.sh | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 74666ff3e4..b8936a653b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -895,6 +895,7 @@ setup_stash()\n \n test_expect_success 'apply: show same status as git status (relative to ./)' '\n \tgit stash clear &&\n+\tmkdir -p subdir &&\n \techo 1 >subdir/subfile1 &&\n \techo 2 >subdir/subfile2 &&\n \tgit add subdir/subfile1 &&\n@@ -1327,6 +1328,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> leaves untracked files in subdir intact' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked1 &&\n \t>subdir/tracked2 &&\n@@ -1343,6 +1345,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> works with binary files' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked &&\n \tcp \"$TEST_DIRECTORY\"/test-binary-1.png subdir/tracked-binary &&\n-- \n2.48.1\n\n"},{"id":"517747","messageId":"20250510183358.36806-3-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 2/9] t3905: remove unneeded blank line","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:37Z","receivedAt":"2025-05-10T18:34:23Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"This is leftover from 787513027a (stash: Add --include-untracked option\nto stash and remove all untracked files, 2011-06-24) when it was\nconverted in bbaa45c3aa (t3905: move all commands into test cases,\n2021-02-08).\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3905-stash-include-untracked.sh | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 1289ae3e07..7704709054 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -87,7 +87,6 @@\n \n test_expect_success 'clean up untracked/untracked file to prepare for next tests' '\n \tgit clean --force --quiet\n-\n '\n \n test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '\n-- \n2.48.1\n\n"},{"id":"517748","messageId":"20250510183358.36806-4-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 3/9] BreakingChanges: announce stash {apply,pop} will imply --index","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:38Z","receivedAt":"2025-05-10T18:34:28Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Some uses may now require --no-index, but remove a footgun that has bit\nusers over the years where stash {apply,pop} are not the opposite of\nstash push because they drop the (saved) index.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n\nNotes:\n    Dscho/Junio suggested it in the original thread [1], but it wasn't\n    considered for the release I believe [2].\n\n    [1]: https://lore.kernel.org/git/Pine.LNX.4.64.0707021213350.4438@racer.site/\n    [2]: https://lore.kernel.org/git/7vzm20q1l7.fsf_-_@assigned-by-dhcp.cox.net/\n\n Documentation/BreakingChanges.adoc | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc\nindex 61bdd586b9..798e742267 100644\n--- a/Documentation/BreakingChanges.adoc\n+++ b/Documentation/BreakingChanges.adoc\n@@ -118,6 +118,17 @@ Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>,\n <20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,\n <CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.\n \n+* The git-stash(1) command now tries to reinstate the index by default in\n+  the \"apply\" and \"pop\" modes. Not doing so creates a common trap: \"git stash\n+  apply\" is not the reverse of \"git stash push\" because carefully staged indices\n+  are lost and have to be manually recreated.\n++\n+Now git-stash(1) will behave like \"--index\" was given in the \"apply\" and \"pop\"\n+modes. Use \"--no-index\" to disable this behavior.\n++\n+Cf. <CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com>,\n+<c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com>.\n+\n === Removals\n \n * Support for grafting commits has long been superseded by git-replace(1).\n-- \n2.48.1\n\n"},{"id":"517749","messageId":"20250510183358.36806-5-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 4/9] stash: restore the index by default when breaking changes are enabled","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:39Z","receivedAt":"2025-05-10T18:34:35Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"This footgun is described in the previous commit to\nDocumentation/BreakingChanges.adoc; without --index, stash apply and\nstash pop confusingly drop stashed index changes.\n\nWhen compiling with breaking changes, instead restore the index unless\nasked not to. Adjust both argument parsing and handling, as well as help\nsynopses. Don't forget to adjust the error message when application\nfails to point to --no-index instead.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n\nNotes:\n    Tests will follow in separate patches, as some changes are rather complicated.\n\n Documentation/git-stash.adoc |  6 ++++++\n builtin/stash.c              | 38 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 44 insertions(+)\n\ndiff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc\nindex 1a5177f498..3b01f494a3 100644\n--- a/Documentation/git-stash.adoc\n+++ b/Documentation/git-stash.adoc\n@@ -11,8 +11,14 @@ SYNOPSIS\n 'git stash' list [<log-options>]\n 'git stash' show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]\n 'git stash' drop [-q | --quiet] [<stash>]\n+ifndef::with-breaking-changes[]\n 'git stash' pop [--index] [-q | --quiet] [<stash>]\n 'git stash' apply [--index] [-q | --quiet] [<stash>]\n+endif::with-breaking-changes[]\n+ifdef::with-breaking-changes[]\n+'git stash' pop [--no-index] [-q | --quiet] [<stash>]\n+'git stash' apply [--no-index] [-q | --quiet] [<stash>]\n+endif::with-breaking-changes[]\n 'git stash' branch <branchname> [<stash>]\n 'git stash' [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n \t     [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex cfbd92852a..4ffa586d07 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -38,10 +38,17 @@\n \tN_(\"git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]\")\n #define BUILTIN_STASH_DROP_USAGE \\\n \tN_(\"git stash drop [-q | --quiet] [<stash>]\")\n+#ifdef WITH_BREAKING_CHANGES\n+#define BUILTIN_STASH_POP_USAGE \\\n+\tN_(\"git stash pop [--no-index] [-q | --quiet] [<stash>]\")\n+#define BUILTIN_STASH_APPLY_USAGE \\\n+\tN_(\"git stash apply [--no-index] [-q | --quiet] [<stash>]\")\n+#else\n #define BUILTIN_STASH_POP_USAGE \\\n \tN_(\"git stash pop [--index] [-q | --quiet] [<stash>]\")\n #define BUILTIN_STASH_APPLY_USAGE \\\n \tN_(\"git stash apply [--index] [-q | --quiet] [<stash>]\")\n+#endif /* WITH_BREAKING_CHANGES */\n #define BUILTIN_STASH_BRANCH_USAGE \\\n \tN_(\"git stash branch <branchname> [<stash>]\")\n #define BUILTIN_STASH_STORE_USAGE \\\n@@ -562,8 +569,13 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,\n \t\t\tret = apply_cached(&out);\n \t\t\tstrbuf_release(&out);\n \t\t\tif (ret)\n+#ifdef WITH_BREAKING_CHANGES\n+\t\t\t\treturn error(_(\"conflicts in index. \"\n+\t\t\t\t\t       \"Try with --no-index.\"));\n+#else\n \t\t\t\treturn error(_(\"conflicts in index. \"\n \t\t\t\t\t       \"Try without --index.\"));\n+#endif /* WITH_BREAKING_CHANGES */\n \n \t\t\tdiscard_index(the_repository->index);\n \t\t\trepo_read_index(the_repository);\n@@ -658,12 +670,21 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n {\n \tint ret = -1;\n \tint quiet = 0;\n+#ifdef WITH_BREAKING_CHANGES\n+\tint no_index = 0;\n+#else\n \tint index = 0;\n+#endif /* WITH_BREAKING_CHANGES */\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+#ifdef WITH_BREAKING_CHANGES\n+\t\tOPT_BOOL(0, \"no-index\", &no_index,\n+\t\t\t N_(\"do not attempt to recreate the index\")),\n+#else\n \t\tOPT_BOOL(0, \"index\", &index,\n \t\t\t N_(\"attempt to recreate the index\")),\n+#endif /* WITH_BREAKING_CHANGES */\n \t\tOPT_END()\n \t};\n \n@@ -673,7 +694,11 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n \tif (get_stash_info(&info, argc, argv))\n \t\tgoto cleanup;\n \n+#ifdef WITH_BREAKING_CHANGES\n+\tret = do_apply_stash(prefix, &info, !no_index, quiet);\n+#else\n \tret = do_apply_stash(prefix, &info, index, quiet);\n+#endif /* WITH_BREAKING_CHANGES */\n cleanup:\n \tfree_stash_info(&info);\n \treturn ret;\n@@ -755,13 +780,22 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n \t\t     struct repository *repo UNUSED)\n {\n \tint ret = -1;\n+#ifdef WITH_BREAKING_CHANGES\n+\tint no_index = 0;\n+#else\n \tint index = 0;\n+#endif /* WITH_BREAKING_CHANGES */\n \tint quiet = 0;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+#ifdef WITH_BREAKING_CHANGES\n+\t\tOPT_BOOL(0, \"no-index\", &no_index,\n+\t\t\t N_(\"do not attempt to recreate the index\")),\n+#else\n \t\tOPT_BOOL(0, \"index\", &index,\n \t\t\t N_(\"attempt to recreate the index\")),\n+#endif /* WITH_BREAKING_CHANGES */\n \t\tOPT_END()\n \t};\n \n@@ -771,7 +805,11 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n \tif (get_stash_info_assert(&info, argc, argv))\n \t\tgoto cleanup;\n \n+#ifdef WITH_BREAKING_CHANGES\n+\tif ((ret = do_apply_stash(prefix, &info, !no_index, quiet)))\n+#else\n \tif ((ret = do_apply_stash(prefix, &info, index, quiet)))\n+#endif /* WITH_BREAKING_CHANGES */\n \t\tprintf_ln(_(\"The stash entry is kept in case \"\n \t\t\t    \"you need it again.\"));\n \telse\n-- \n2.48.1\n\n"},{"id":"517750","messageId":"20250510183358.36806-6-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 5/9] t0450: mark stash documentation as a known discrepancy","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:40Z","receivedAt":"2025-05-10T18:34:40Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"The stash documentation now differs when built with breaking changes,\nand t0450 is not smart enough to understand the results. Expect failure\nby adding to the known list of mismatches.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t0450/adoc-help-mismatches | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/t/t0450/adoc-help-mismatches b/t/t0450/adoc-help-mismatches\nindex c4a15fd0cb..379da30191 100644\n--- a/t/t0450/adoc-help-mismatches\n+++ b/t/t0450/adoc-help-mismatches\n@@ -50,6 +50,7 @@ restore\n rev-parse\n show\n stage\n+stash\n switch\n update-index\n update-ref\n-- \n2.48.1\n\n"},{"id":"517751","messageId":"20250510183358.36806-7-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 6/9] t3903: adjust stash test to account for --[no-]index with breaking changes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:41Z","receivedAt":"2025-05-10T18:34:41Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"A few tests check the results of the index after applying a stash; with\nbreaking changes from previous commits that automatically restore the\nstashed index, the expected values are wrong.\n\nA few of the relevant tests check the restoration of <pathspec>s; with\nthe aforementioned breaking changes, things get more interesting. In\nparticular, if we \"git stash push -- foo\" but have \"bar\" in the index,\nthen when applying the stash we get a conflict: \"bar\" was not removed\nfrom the index by the stash, but it was included in the recorded index\nin the stash. In those cases, apply the stash with \"--no-index\" (which\nwould be the required user behavior).\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n\nNotes:\n    It looks like the pathspec filtering is not applied to the stashed\n    index; should it be?\n\n t/t3903-stash.sh | 158 +++++++++++++++++++++++++++++++++++++++++++----\n 1 file changed, 147 insertions(+), 11 deletions(-)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex b8936a653b..36e1d3ec08 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -99,7 +99,7 @@ setup_stash()\n \ttest_cmp expect file\n '\n \n-test_expect_success 'apply stashed changes' '\n+test_expect_success !WITH_BREAKING_CHANGES 'apply stashed changes' '\n \tgit reset --hard &&\n \techo 5 >other-file &&\n \tgit add other-file &&\n@@ -111,6 +111,18 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'apply stashed changes' '\n+\tgit reset --hard &&\n+\techo 5 >other-file &&\n+\tgit add other-file &&\n+\ttest_tick &&\n+\tgit commit -m other-file &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n test_expect_success 'apply stashed changes (including index)' '\n \tgit reset --hard HEAD^ &&\n \techo 6 >other-file &&\n@@ -136,7 +148,7 @@ setup_stash()\n \ttest_must_fail git stash drop --foo\n '\n \n-test_expect_success 'drop top stash' '\n+test_expect_success !WITH_BREAKING_CHANGES 'drop top stash' '\n \tgit reset --hard &&\n \tgit stash list >expected &&\n \techo 7 >file &&\n@@ -150,7 +162,21 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n-test_expect_success 'drop middle stash' '\n+test_expect_success WITH_BREAKING_CHANGES 'drop top stash' '\n+\tgit reset --hard &&\n+\tgit stash list >expected &&\n+\techo 7 >file &&\n+\tgit stash &&\n+\tgit stash drop &&\n+\tgit stash list >actual &&\n+\ttest_cmp expected actual &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash' '\n \tgit reset --hard &&\n \techo 8 >file &&\n \tgit stash &&\n@@ -170,7 +196,27 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n-test_expect_success 'drop middle stash by index' '\n+test_expect_success WITH_BREAKING_CHANGES 'drop middle stash' '\n+\tgit reset --hard &&\n+\techo 8 >file &&\n+\tgit stash &&\n+\techo 9 >file &&\n+\tgit stash &&\n+\tgit stash drop stash@{1} &&\n+\ttest 2 = $(git stash list | wc -l) &&\n+\tgit stash apply &&\n+\ttest 9 = $(cat file) &&\n+\ttest 1 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file) &&\n+\tgit reset --hard &&\n+\tgit stash drop &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash by index' '\n \tgit reset --hard &&\n \techo 8 >file &&\n \tgit stash &&\n@@ -227,7 +273,7 @@ setup_stash()\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'stash pop' '\n+test_expect_success !WITH_BREAKING_CHANGES 'stash pop' '\n \tgit reset --hard &&\n \tgit stash pop &&\n \ttest 3 = $(cat file) &&\n@@ -236,6 +282,15 @@ setup_stash()\n \ttest 0 = $(git stash list | wc -l)\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'stash pop' '\n+\tgit reset --hard &&\n+\tgit stash pop &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file) &&\n+\ttest 0 = $(git stash list | wc -l)\n+'\n+\n cat >expect <<EOF\n diff --git a/file2 b/file2\n new file mode 100644\n@@ -320,7 +375,7 @@ setup_stash()\n \ttest_must_be_empty output.out\n '\n \n-test_expect_success 'pop -q works and is quiet' '\n+test_expect_success !WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n \tgit stash pop -q >output.out 2>&1 &&\n \techo bar >expect &&\n \tgit show :file >actual &&\n@@ -328,6 +383,14 @@ setup_stash()\n \ttest_must_be_empty output.out\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n+\tgit stash pop -q >output.out 2>&1 &&\n+\techo test >expect &&\n+\tgit show :file >actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty output.out\n+'\n+\n test_expect_success 'pop -q --index works and is quiet' '\n \techo foo >file &&\n \tgit add file &&\n@@ -1166,7 +1229,7 @@ setup_stash()\n \ttest_cmp expect actual\n '\n \n-test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n \t>foo &&\n \t>bar &&\n \tgit add foo bar &&\n@@ -1178,7 +1241,19 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n-test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n \tmkdir sub &&\n \t>foo &&\n \t>bar &&\n@@ -1194,7 +1269,23 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n-test_expect_success 'stash with multiple pathspec arguments' '\n+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n+\tmkdir sub &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\t(\n+\t\tcd sub &&\n+\t\tgit stash push -- ../foo\n+\t) &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n+test_expect_success !WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n \t>foo &&\n \t>bar &&\n \t>extra &&\n@@ -1209,7 +1300,22 @@ setup_stash()\n \ttest_path_is_file extra\n '\n \n-test_expect_success 'stash with file including $IFS character' '\n+test_expect_success WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n+test_expect_success !WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n \t>\"foo bar\" &&\n \t>foo &&\n \t>bar &&\n@@ -1224,6 +1330,21 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash with pathspec matching multiple paths' '\n \techo original >file &&\n \techo original >other-file &&\n@@ -1297,7 +1418,7 @@ setup_stash()\n \ttest_path_is_file untracked\n '\n \n-test_expect_success 'stash without verb with pathspec' '\n+test_expect_success !WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n \t>\"foo bar\" &&\n \t>foo &&\n \t>bar &&\n@@ -1312,6 +1433,21 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n \tgit reset &&\n \t>foo &&\n-- \n2.48.1\n\n"},{"id":"517752","messageId":"20250510183358.36806-8-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 7/9] t3904: adjust stash -p test to account for index states with breaking changes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:42Z","receivedAt":"2025-05-10T18:34:42Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3904-stash-patch.sh | 14 +++++++++++++-\n 1 file changed, 13 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh\nindex ae313e3c70..90f6b6bc90 100755\n--- a/t/t3904-stash-patch.sh\n+++ b/t/t3904-stash-patch.sh\n@@ -30,7 +30,7 @@\n \tverify_state dir/foo work index\n '\n \n-test_expect_success 'git stash -p' '\n+test_expect_success !WITH_BREAKING_CHANGES 'git stash -p' '\n \ttest_write_lines y n y | git stash save -p &&\n \tverify_state HEAD committed HEADfile_index &&\n \tverify_saved_state bar &&\n@@ -42,6 +42,18 @@\n \tverify_state dir/foo work head\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'git stash -p' '\n+\ttest_write_lines y n y | git stash save -p &&\n+\tverify_state HEAD committed HEADfile_index &&\n+\tverify_saved_state bar &&\n+\tverify_state dir/foo head index &&\n+\tgit reset --hard &&\n+\tgit stash apply &&\n+\tverify_state HEAD HEADfile_work HEADfile_index &&\n+\tverify_state bar dummy bar_index &&\n+\tverify_state dir/foo work index\n+'\n+\n test_expect_success 'git stash -p --no-keep-index' '\n \tset_state HEAD HEADfile_work HEADfile_index &&\n \tset_state bar bar_work bar_index &&\n-- \n2.48.1\n\n"},{"id":"517753","messageId":"20250510183358.36806-9-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 8/9] t3905: adjust stash -u tests for breaking changes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:43Z","receivedAt":"2025-05-10T18:34:43Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Like previous commits, adjust the expected results of application of\nstashes with --no-index as needed, with <pathspec> tests typically\nrequiring --no-index.\n\nOne test (stash pop after save --include-untracked leaves files\nuntracked again) requires an extra cleanup step: subsequent tests\n(\"stash save -u dirty index\" and company) are not expecting \"file\" to be\ndirty in the index, but after \"stash pop\" it will be. Clean up after\nourselves rather than adjusting later tests.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3905-stash-include-untracked.sh | 39 ++++++++++++++++++++++++++++--\n 1 file changed, 37 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 7704709054..ee6cea49c8 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -89,7 +89,7 @@\n \tgit clean --force --quiet\n '\n \n-test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '\n+test_expect_success !WITH_BREAKING_CHANGES 'stash pop after save --include-untracked leaves files untracked again' '\n \tcat >expect <<-EOF &&\n \t M file\n \t?? HEAD\n@@ -108,6 +108,26 @@\n \ttest_cmp untracked_expect untracked/untracked\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'stash pop after save --include-untracked leaves files untracked again' '\n+\tcat >expect <<-EOF &&\n+\tMM file\n+\t?? HEAD\n+\t?? actual\n+\t?? expect\n+\t?? file2\n+\t?? untracked/\n+\tEOF\n+\n+\tgit stash pop &&\n+\ttest_when_finished \"git restore --staged file\" &&\n+\tgit status --porcelain >actual &&\n+\ttest_cmp expect actual &&\n+\techo 1 >expect_file2 &&\n+\ttest_cmp expect_file2 file2 &&\n+\techo untracked >untracked_expect &&\n+\ttest_cmp untracked_expect untracked/untracked\n+'\n+\n test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n \tgit clean --force --quiet -d\n '\n@@ -206,7 +226,7 @@\n \ttest_path_is_file foo\n '\n \n-test_expect_success 'stash push with $IFS character' '\n+test_expect_success !WITH_BREAKING_CHANGES 'stash push with $IFS character' '\n \t>\"foo bar\" &&\n \t>foo &&\n \t>bar &&\n@@ -221,6 +241,21 @@\n \ttest_path_is_file bar\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'stash push with $IFS character' '\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash previously ignored file' '\n \tcat >.gitignore <<-EOF &&\n \tignored\n-- \n2.48.1\n\n"},{"id":"517754","messageId":"20250510183358.36806-10-ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH 9/9] t3906: adjust stash submodule tests to account for breaking changes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-10T18:33:44Z","receivedAt":"2025-05-10T18:34:44Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"I cannot explain _why_ this occurs, but it seems that automatically\nunstashing the index from previous commits resolves some known failures\nin t3906 (which are captured by t/lib-submodule-updates.sh).\n\nIn particular:\n- 'replace tracked file with submodule creates empty directory' succeeds\n  with breaking changes;\n- all KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR tests\n  succeed with breaking changes;\n- all KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES suceed with\n  breaking changes.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/lib-submodule-update.sh | 24 ++++++++++++++++++++----\n 1 file changed, 20 insertions(+), 4 deletions(-)\n\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex 36f767cb74..4ae909c432 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -353,7 +353,21 @@ test_submodule_switch_common ()\n \t'\n \t# Replacing a tracked file with a submodule produces an empty\n \t# directory ...\n-\ttest_expect_$RESULT \"$command: replace tracked file with submodule creates empty directory\" '\n+\ttest_expect_$RESULT !WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n+\t\tprolog &&\n+\t\treset_work_tree_to replace_sub1_with_file &&\n+\t\t(\n+\t\t\tcd submodule_update &&\n+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n+\t\t\t$command replace_file_with_sub1 &&\n+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n+\t\t\ttest_dir_is_empty sub1 &&\n+\t\t\tgit submodule update --init --recursive &&\n+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n+\t\t)\n+\t'\n+\t# (unless we automatically unstash the index!)\n+\ttest_expect_success WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n \t\tprolog &&\n \t\treset_work_tree_to replace_sub1_with_file &&\n \t\t(\n@@ -368,7 +382,8 @@ test_submodule_switch_common ()\n \t'\n \t# ... as does removing a directory with tracked files with a\n \t# submodule.\n-\tif test \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n+\t\ttest \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n \tthen\n \t\t# Non fast-forward merges fail with \"Directory sub1 doesn't\n \t\t# exist. sub1\" because the empty submodule directory is not\n@@ -392,8 +407,9 @@ test_submodule_switch_common ()\n \t'\n \n \t######################## Disappearing submodule #######################\n-\t# Removing a submodule doesn't remove its work tree ...\n-\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n+\t# Removing a submodule doesn't remove its work tree (unless stash applies the index!) ...\n+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n+\t\ttest \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n \tthen\n \t\tRESULT=\"failure\"\n \telse\n-- \n2.48.1\n\n"},{"id":"517836","messageId":"xmqqzffivvnr.fsf@gitster.g","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"Re: [PATCH 0/9] make stash apply with --index by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-05-12T12:52:08Z","receivedAt":"2025-05-12T12:52:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"D. Ben Knoble\" <ben.knoble+github@gmail.com> writes:\n\n> Since git-stash's inception, it has defaulted to stashing the index but not\n> restoring it. This has caused some confusion: change the default as part of Git\n> 3.0 to unstash the index, too.\n\nI am very tempted to veto this, as I very much recall trying to see\nhow I liked it and used in my workflow (by using an alias to do the\n\"pop\" always used with \"--index\"), got quite frustrated seeing that\na lot of times the command would have worked perfectly well if the\n\"--index\" option weren't given, and gave up after a few weeks even\nthough I tried very hard to like it as the default.\n\nAs \"--index\" is a Boolean option, I can see that we probably already\nhave \"--no-index\" for free, so there is an escape hatch already, but\nI do not think it would give a good end-user experience to force\nthem to keep saying \"--no-index\" (that is 3 keystrokes longer than\nwhat those who want \"--index\" need to type).\n"},{"id":"518489","messageId":"CALnO6CA0S_54HjyNDWyTAhfmRFcTsFEMF67yWjMeL526O14aQg@mail.gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"Re: [PATCH 0/9] make stash apply with --index by default","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-20T14:36:42Z","receivedAt":"2025-05-20T14:37:05Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Sat, May 10, 2025 at 2:34 PM D. Ben Knoble\n<ben.knoble+github@gmail.com> wrote:\n>\n> Since git-stash's inception, it has defaulted to stashing the index but not\n> restoring it. This has caused some confusion: change the default as part of Git\n> 3.0 to unstash the index, too.\n>\n> I ran into this myself a while back and did some digging; it appears that other\n> have been bit, too (see references in patch 3). Moreover, when git-stash was\n> originally written, defaulting with --index was suggested but not implemented\n> before the script merged. So this RFC should bring us back towards \"less\n> confusing,\" hopefully.\n>\n> The series is structured as follows:\n>\n> Patches 1-2: unrelated prep/style commits noticed while working on tests.\n> Patch 3: update Documentation/BreakingChanges.adoc. This seems like a natural\n>     place to discuss the proposal, so it contains no other changes.\n> Patch 4: make it so in builtin/stash.c.\n> Patches 5-9: update the impacted tests. Separated out for ease of review. I used\n>     a style more like \"split the test into 2: one with, one without breaking\n>     changes.\" In retrospect, the diff might be smaller (and the 2 versions of\n>     the test easier to compare) if I used \"test_has_prereq\" in the tests… but at\n>     the cost of making the tests harder to follow. Thoughts?\n>\n> D. Ben Knoble (9):\n>   t3903: reduce dependencies on previous tests\n>   t3905: remove unneeded blank line\n>   BreakingChanges: announce stash {apply,pop} will imply --index\n>   stash: restore the index by default when breaking changes are enabled\n>   t0450: mark stash documentation as a known discrepancy\n>   t3903: adjust stash test to account for --[no-]index with breaking\n>     changes\n>   t3904: adjust stash -p test to account for index states with breaking\n>     changes\n>   t3905: adjust stash -u tests for breaking changes\n>   t3906: adjust stash submodule tests to account for breaking changes\n>\n>  Documentation/BreakingChanges.adoc |  11 ++\n>  Documentation/git-stash.adoc       |   6 ++\n>  builtin/stash.c                    |  38 +++++++\n>  t/lib-submodule-update.sh          |  24 ++++-\n>  t/t0450/adoc-help-mismatches       |   1 +\n>  t/t3903-stash.sh                   | 161 +++++++++++++++++++++++++++--\n>  t/t3904-stash-patch.sh             |  14 ++-\n>  t/t3905-stash-include-untracked.sh |  40 ++++++-\n>  8 files changed, 276 insertions(+), 19 deletions(-)\n>\n>\n> base-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n> --\n> 2.48.1\n>\n"},{"id":"518490","messageId":"CALnO6CB=2ih-_=VUth=PJZxGkz_GA_mUfWd6gQOFcd36eUpD4A@mail.gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"Re: [PATCH 0/9] make stash apply with --index by default","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-05-20T14:39:04Z","receivedAt":"2025-05-20T14:39:17Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"[Apologies for re-send; mis-clicked]\n\nOn Sat, May 10, 2025 at 2:34 PM D. Ben Knoble\n<ben.knoble+github@gmail.com> wrote:\n>\n> Since git-stash's inception, it has defaulted to stashing the index but not\n> restoring it. This has caused some confusion: change the default as part of Git\n> 3.0 to unstash the index, too.\n>\n> I ran into this myself a while back and did some digging; it appears that other\n> have been bit, too (see references in patch 3). Moreover, when git-stash was\n> originally written, defaulting with --index was suggested but not implemented\n> before the script merged. So this RFC should bring us back towards \"less\n> confusing,\" hopefully.\n>\n> The series is structured as follows:\n>\n> Patches 1-2: unrelated prep/style commits noticed while working on tests.\n> Patch 3: update Documentation/BreakingChanges.adoc. This seems like a natural\n>     place to discuss the proposal, so it contains no other changes.\n> Patch 4: make it so in builtin/stash.c.\n> Patches 5-9: update the impacted tests. Separated out for ease of review. I used\n>     a style more like \"split the test into 2: one with, one without breaking\n>     changes.\" In retrospect, the diff might be smaller (and the 2 versions of\n>     the test easier to compare) if I used \"test_has_prereq\" in the tests… but at\n>     the cost of making the tests harder to follow. Thoughts?\n>\n> D. Ben Knoble (9):\n>   t3903: reduce dependencies on previous tests\n>   t3905: remove unneeded blank line\n>   BreakingChanges: announce stash {apply,pop} will imply --index\n>   stash: restore the index by default when breaking changes are enabled\n>   t0450: mark stash documentation as a known discrepancy\n>   t3903: adjust stash test to account for --[no-]index with breaking\n>     changes\n>   t3904: adjust stash -p test to account for index states with breaking\n>     changes\n>   t3905: adjust stash -u tests for breaking changes\n>   t3906: adjust stash submodule tests to account for breaking changes\n>\n>  Documentation/BreakingChanges.adoc |  11 ++\n>  Documentation/git-stash.adoc       |   6 ++\n>  builtin/stash.c                    |  38 +++++++\n>  t/lib-submodule-update.sh          |  24 ++++-\n>  t/t0450/adoc-help-mismatches       |   1 +\n>  t/t3903-stash.sh                   | 161 +++++++++++++++++++++++++++--\n>  t/t3904-stash-patch.sh             |  14 ++-\n>  t/t3905-stash-include-untracked.sh |  40 ++++++-\n>  8 files changed, 276 insertions(+), 19 deletions(-)\n>\n>\n> base-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n> --\n> 2.48.1\n>\n\nAny comments from others? CC'd folks from individual patches on cover letter.\n"},{"id":"526406","messageId":"cover.1757982870.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"20250510183358.36806-1-ben.knoble+github@gmail.com","subject":"[PATCH v2 0/4] Teach git-stash to use --index from config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T00:37:33Z","receivedAt":"2025-09-16T00:37:53Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Changes from v1:\n- configure --index via config\n- drop BreakingChanges related work\n\nWith stash.index=true, git-stash(1) command now tries to reinstate the\nindex by default in the \"apply\" and \"pop\" modes. Not doing so creates a\ncommon trap: \"git stash apply\" is not the reverse of \"git stash push\"\nbecause carefully staged indices are lost and have to be manually\nrecreated. OTOH, this mode is not always desirable and may create more\nconflicts when applying stashes. Use \"--no-index\" to disable this behavior.\n\nCf. <CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com>,\n<c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com>.\n\nPS I've left some new t3903 tests as copy-pasta for now to get feedback\non the rest of the series; there are bits of that file that could use an\nupdate to the modern style (e.g., not using \"test 1 = $(cat file)\").\nSince some new tests are substantially similar to old tests that use\nthis style, such cleanup is /probably/ warranted but will delay eyeballs\non the core of this series.\n\nPublished-as: https://github.com/benknoble/git/tree/stash-apply-index\nv1: https://lore.kernel.org/git/20250510183358.36806-1-ben.knoble+github@gmail.com/\n\nD. Ben Knoble (4):\n  t3903: reduce dependencies on previous tests\n  t3905: remove unneeded blank line\n  stash: refactor private config globals\n  stash: honor stash.index in apply, pop modes\n\n Documentation/config/stash.adoc    |   5 +\n builtin/stash.c                    |  17 ++--\n t/t3903-stash.sh                   | 158 +++++++++++++++++++++++++++++\n t/t3904-stash-patch.sh             |  11 ++\n t/t3905-stash-include-untracked.sh |  49 ++++++++-\n 5 files changed, 232 insertions(+), 8 deletions(-)\n\nDiff-intervalle contre v1 :\n 1:  1328eb8eac =  1:  1328eb8eac t3903: reduce dependencies on previous tests\n 2:  8ac06ad62d =  2:  8ac06ad62d t3905: remove unneeded blank line\n 3:  c068f1dc0b <  -:  ---------- BreakingChanges: announce stash {apply,pop} will imply --index\n 4:  8caff91c0e <  -:  ---------- stash: restore the index by default when breaking changes are enabled\n 5:  387427bb8c <  -:  ---------- t0450: mark stash documentation as a known discrepancy\n 9:  c72a1fe6ea !  3:  bf0a561ce3 t3906: adjust stash submodule tests to account for breaking changes\n    @@ Metadata\n     Author: D. Ben Knoble <ben.knoble+github@gmail.com>\n     \n      ## Commit message ##\n    -    t3906: adjust stash submodule tests to account for breaking changes\n    +    stash: refactor private config globals\n     \n    -    I cannot explain _why_ this occurs, but it seems that automatically\n    -    unstashing the index from previous commits resolves some known failures\n    -    in t3906 (which are captured by t/lib-submodule-updates.sh).\n    +    A subsequent commit will access a new config variable in the stash\n    +    subcommand implementations, which requires the variables to be declared\n    +    before the relevant functions. Prep with a pure refactoring change to\n    +    consolidate config-related globals with the rest of the globals.\n     \n    -    In particular:\n    -    - 'replace tracked file with submodule creates empty directory' succeeds\n    -      with breaking changes;\n    -    - all KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR tests\n    -      succeed with breaking changes;\n    -    - all KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES suceed with\n    -      breaking changes.\n    +    Best-viewed-with: --color-moved\n     \n    - ## t/lib-submodule-update.sh ##\n    -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n    - \t'\n    - \t# Replacing a tracked file with a submodule produces an empty\n    - \t# directory ...\n    --\ttest_expect_$RESULT \"$command: replace tracked file with submodule creates empty directory\" '\n    -+\ttest_expect_$RESULT !WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n    -+\t\tprolog &&\n    -+\t\treset_work_tree_to replace_sub1_with_file &&\n    -+\t\t(\n    -+\t\t\tcd submodule_update &&\n    -+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n    -+\t\t\t$command replace_file_with_sub1 &&\n    -+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n    -+\t\t\ttest_dir_is_empty sub1 &&\n    -+\t\t\tgit submodule update --init --recursive &&\n    -+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n    -+\t\t)\n    -+\t'\n    -+\t# (unless we automatically unstash the index!)\n    -+\ttest_expect_success WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n    - \t\tprolog &&\n    - \t\treset_work_tree_to replace_sub1_with_file &&\n    - \t\t(\n    -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n    - \t'\n    - \t# ... as does removing a directory with tracked files with a\n    - \t# submodule.\n    --\tif test \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n    -+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n    -+\t\ttest \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n    - \tthen\n    - \t\t# Non fast-forward merges fail with \"Directory sub1 doesn't\n    - \t\t# exist. sub1\" because the empty submodule directory is not\n    -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n    - \t'\n    + ## builtin/stash.c ##\n    +@@ builtin/stash.c: static const char * const git_stash_save_usage[] = {\n    + static const char ref_stash[] = \"refs/stash\";\n    + static struct strbuf stash_index_path = STRBUF_INIT;\n      \n    - \t######################## Disappearing submodule #######################\n    --\t# Removing a submodule doesn't remove its work tree ...\n    --\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n    -+\t# Removing a submodule doesn't remove its work tree (unless stash applies the index!) ...\n    -+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n    -+\t\ttest \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n    - \tthen\n    - \t\tRESULT=\"failure\"\n    - \telse\n    ++static int show_stat = 1;\n    ++static int show_patch;\n    ++static int show_include_untracked;\n    ++\n    + /*\n    +  * w_commit is set to the commit containing the working tree\n    +  * b_commit is set to the base commit\n    +@@ builtin/stash.c: static int list_stash(int argc, const char **argv, const char *prefix,\n    + \treturn run_command(&cp);\n    + }\n    + \n    +-static int show_stat = 1;\n    +-static int show_patch;\n    +-static int show_include_untracked;\n    +-\n    + static int git_stash_config(const char *var, const char *value,\n    + \t\t\t    const struct config_context *ctx, void *cb)\n    + {\n 6:  0a12983c00 !  4:  585e124467 t3903: adjust stash test to account for --[no-]index with breaking changes\n    @@ Metadata\n     Author: D. Ben Knoble <ben.knoble+github@gmail.com>\n     \n      ## Commit message ##\n    -    t3903: adjust stash test to account for --[no-]index with breaking changes\n    +    stash: honor stash.index in apply, pop modes\n     \n    -    A few tests check the results of the index after applying a stash; with\n    -    breaking changes from previous commits that automatically restore the\n    -    stashed index, the expected values are wrong.\n    +    With stash.index=true, git-stash(1) command now tries to reinstate the\n    +    index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n    +    common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n    +    push\" because carefully staged indices are lost and have to be manually\n    +    recreated. OTOH, this mode is not always desirable and may create more\n    +    conflicts when applying stashes. As usual, \"--no-index\" will disable\n    +    this behavior if you set \"stash.index\".\n     \n    -    A few of the relevant tests check the restoration of <pathspec>s; with\n    -    the aforementioned breaking changes, things get more interesting. In\n    -    particular, if we \"git stash push -- foo\" but have \"bar\" in the index,\n    -    then when applying the stash we get a conflict: \"bar\" was not removed\n    -    from the index by the stash, but it was included in the recorded index\n    -    in the stash. In those cases, apply the stash with \"--no-index\" (which\n    -    would be the required user behavior).\n    +    [1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n    +    [2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n     \n    -    Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n    + ## Documentation/config/stash.adoc ##\n    +@@\n    ++stash.index::\n    ++\tIf this is set to true, `git stash apply` and `git stash pop` will\n    ++\tbehave as if `--index` was supplied. Defaults to false. See the\n    ++\tdescriptions in linkgit:git-stash[1].\n    ++\n    + stash.showIncludeUntracked::\n    + \tIf this is set to true, the `git stash show` command will show\n    + \tthe untracked files of a stash entry.  Defaults to false. See\n     \n    -\n    - ## Notes ##\n    -    It looks like the pathspec filtering is not applied to the stashed\n    -    index; should it be?\n    + ## builtin/stash.c ##\n    +@@ builtin/stash.c: static struct strbuf stash_index_path = STRBUF_INIT;\n    + static int show_stat = 1;\n    + static int show_patch;\n    + static int show_include_untracked;\n    ++static int use_index;\n    + \n    + /*\n    +  * w_commit is set to the commit containing the working tree\n    +@@ builtin/stash.c: static int apply_stash(int argc, const char **argv, const char *prefix,\n    + {\n    + \tint ret = -1;\n    + \tint quiet = 0;\n    +-\tint index = 0;\n    ++\tint index = use_index;\n    + \tstruct stash_info info = STASH_INFO_INIT;\n    + \tstruct option options[] = {\n    + \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n    +@@ builtin/stash.c: static int pop_stash(int argc, const char **argv, const char *prefix,\n    + \t\t     struct repository *repo UNUSED)\n    + {\n    + \tint ret = -1;\n    +-\tint index = 0;\n    ++\tint index = use_index;\n    + \tint quiet = 0;\n    + \tstruct stash_info info = STASH_INFO_INIT;\n    + \tstruct option options[] = {\n    +@@ builtin/stash.c: static int git_stash_config(const char *var, const char *value,\n    + \t\tshow_include_untracked = git_config_bool(var, value);\n    + \t\treturn 0;\n    + \t}\n    ++\tif (!strcmp(var, \"stash.index\")) {\n    ++\t\tuse_index = git_config_bool(var, value);\n    ++\t\treturn 0;\n    ++\t}\n    + \treturn git_diff_basic_config(var, value, ctx, cb);\n    + }\n    + \n     \n      ## t/t3903-stash.sh ##\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_cmp expect file\n    - '\n    - \n    --test_expect_success 'apply stashed changes' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'apply stashed changes' '\n    - \tgit reset --hard &&\n    - \techo 5 >other-file &&\n    - \tgit add other-file &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest 1 = $(git show HEAD:file)\n      '\n      \n    -+test_expect_success WITH_BREAKING_CHANGES 'apply stashed changes' '\n    -+\tgit reset --hard &&\n    ++test_expect_success 'apply stashed changes with stash.index' '\n    ++\ttest_config stash.index true &&\n    ++\tgit reset --hard HEAD^ &&\n     +\techo 5 >other-file &&\n     +\tgit add other-file &&\n     +\ttest_tick &&\n    @@ t/t3903-stash.sh: setup_stash()\n      test_expect_success 'apply stashed changes (including index)' '\n      \tgit reset --hard HEAD^ &&\n      \techo 6 >other-file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_must_fail git stash drop --foo\n    - '\n    - \n    --test_expect_success 'drop top stash' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'drop top stash' '\n    - \tgit reset --hard &&\n    - \tgit stash list >expected &&\n    - \techo 7 >file &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest 1 = $(git show HEAD:file)\n      '\n      \n    --test_expect_success 'drop middle stash' '\n    -+test_expect_success WITH_BREAKING_CHANGES 'drop top stash' '\n    ++test_expect_success 'drop top stash with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\tgit reset --hard &&\n     +\tgit stash list >expected &&\n     +\techo 7 >file &&\n    @@ t/t3903-stash.sh: setup_stash()\n     +\ttest 1 = $(git show HEAD:file)\n     +'\n     +\n    -+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash' '\n    + test_expect_success 'drop middle stash' '\n      \tgit reset --hard &&\n      \techo 8 >file &&\n    - \tgit stash &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest 1 = $(git show HEAD:file)\n      '\n      \n    --test_expect_success 'drop middle stash by index' '\n    -+test_expect_success WITH_BREAKING_CHANGES 'drop middle stash' '\n    ++test_expect_success 'drop middle stash with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\tgit reset --hard &&\n     +\techo 8 >file &&\n     +\tgit stash &&\n    @@ t/t3903-stash.sh: setup_stash()\n     +\ttest 1 = $(git show HEAD:file)\n     +'\n     +\n    -+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash by index' '\n    + test_expect_success 'drop middle stash by index' '\n      \tgit reset --hard &&\n      \techo 8 >file &&\n    - \tgit stash &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_cmp expect actual\n    - '\n    - \n    --test_expect_success 'stash pop' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash pop' '\n    - \tgit reset --hard &&\n    - \tgit stash pop &&\n    - \ttest 3 = $(cat file) &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest 0 = $(git stash list | wc -l)\n      '\n      \n    -+test_expect_success WITH_BREAKING_CHANGES 'stash pop' '\n    ++test_expect_success 'stash pop with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\tgit reset --hard &&\n    ++\tsetup_stash &&\n     +\tgit stash pop &&\n     +\ttest 3 = $(cat file) &&\n     +\ttest 2 = $(git show :file) &&\n    @@ t/t3903-stash.sh: setup_stash()\n      \ttest_must_be_empty output.out\n      '\n      \n    --test_expect_success 'pop -q works and is quiet' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n    - \tgit stash pop -q >output.out 2>&1 &&\n    - \techo bar >expect &&\n    - \tgit show :file >actual &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_must_be_empty output.out\n    - '\n    - \n    -+test_expect_success WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n    ++test_expect_success 'pop -q works and is quiet with stash.index' '\n    ++\t# Added file, deleted file, modified file all staged for commit\n    ++\techo foo >new-file &&\n    ++\techo test >file &&\n    ++\tgit add new-file file &&\n    ++\tgit rm other-file &&\n    ++\tgit stash &&\n    ++\n    ++\ttest_config stash.index true &&\n     +\tgit stash pop -q >output.out 2>&1 &&\n     +\techo test >expect &&\n     +\tgit show :file >actual &&\n    @@ t/t3903-stash.sh: setup_stash()\n      test_expect_success 'pop -q --index works and is quiet' '\n      \techo foo >file &&\n      \tgit add file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_cmp expect actual\n    - '\n    - \n    --test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n    - \t>foo &&\n    - \t>bar &&\n    - \tgit add foo bar &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest_path_is_file bar\n      '\n      \n    --test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n    -+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n    ++test_expect_success 'stash -- <pathspec> stashes and restores the file with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\t>foo &&\n     +\t>bar &&\n     +\tgit add foo bar &&\n    @@ t/t3903-stash.sh: setup_stash()\n     +\ttest_path_is_file bar\n     +'\n     +\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n    + test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n      \tmkdir sub &&\n      \t>foo &&\n    - \t>bar &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest_path_is_file bar\n      '\n      \n    --test_expect_success 'stash with multiple pathspec arguments' '\n    -+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n    ++test_expect_success 'stash -- <pathspec> stashes in subdirectory with stash.index' '\n    ++\ttest_config stash.index true &&\n    ++\trm -r sub &&\n     +\tmkdir sub &&\n     +\t>foo &&\n     +\t>bar &&\n    @@ t/t3903-stash.sh: setup_stash()\n     +\ttest_path_is_file bar\n     +'\n     +\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n    + test_expect_success 'stash with multiple pathspec arguments' '\n      \t>foo &&\n      \t>bar &&\n    - \t>extra &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest_path_is_file extra\n      '\n      \n    --test_expect_success 'stash with file including $IFS character' '\n    -+test_expect_success WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n    ++test_expect_success 'stash with multiple pathspec arguments with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\t>foo &&\n     +\t>bar &&\n     +\t>extra &&\n    @@ t/t3903-stash.sh: setup_stash()\n     +\ttest_path_is_file extra\n     +'\n     +\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n    + test_expect_success 'stash with file including $IFS character' '\n      \t>\"foo bar\" &&\n      \t>foo &&\n    - \t>bar &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest_path_is_file bar\n      '\n      \n    -+test_expect_success WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n    ++test_expect_success 'stash with file including $IFS character with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\t>\"foo bar\" &&\n     +\t>foo &&\n     +\t>bar &&\n    @@ t/t3903-stash.sh: setup_stash()\n      test_expect_success 'stash with pathspec matching multiple paths' '\n      \techo original >file &&\n      \techo original >other-file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file untracked\n    - '\n    - \n    --test_expect_success 'stash without verb with pathspec' '\n    -+test_expect_success !WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n    - \t>\"foo bar\" &&\n    - \t>foo &&\n    - \t>bar &&\n     @@ t/t3903-stash.sh: setup_stash()\n      \ttest_path_is_file bar\n      '\n      \n    -+test_expect_success WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n    ++test_expect_success 'stash without verb with pathspec with stash.index' '\n    ++\ttest_config stash.index true &&\n     +\t>\"foo bar\" &&\n     +\t>foo &&\n     +\t>bar &&\n    @@ t/t3903-stash.sh: setup_stash()\n      test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n      \tgit reset &&\n      \t>foo &&\n    +\n    + ## t/t3904-stash-patch.sh ##\n    +@@\n    + \tverify_state dir/foo work head\n    + '\n    + \n    ++test_expect_success 'git stash -p with stash.index' '\n    ++\ttest_config stash.index true &&\n    ++\tset_state HEAD HEADfile_work HEADfile_index &&\n    ++\tset_state dir/foo work index &&\n    ++\ttest_write_lines y n y | git stash save -p &&\n    ++\tgit reset --hard &&\n    ++\tgit stash apply &&\n    ++\tverify_state HEAD HEADfile_work HEADfile_index &&\n    ++\tverify_state dir/foo head index\n    ++'\n    ++\n    + test_expect_success 'git stash -p --no-keep-index' '\n    + \tset_state HEAD HEADfile_work HEADfile_index &&\n    + \tset_state bar bar_work bar_index &&\n    +\n    + ## t/t3905-stash-include-untracked.sh ##\n    +@@\n    + \n    + . ./test-lib.sh\n    + \n    +-test_expect_success 'stash save --include-untracked some dirty working directory' '\n    ++setup() {\n    + \techo 1 >file &&\n    + \tgit add file &&\n    + \ttest_tick &&\n    +@@\n    + \tgit stash --include-untracked &&\n    + \tgit diff-files --quiet &&\n    + \tgit diff-index --cached --quiet HEAD\n    ++}\n    ++\n    ++test_expect_success 'stash save --include-untracked some dirty working directory' '\n    ++\tsetup\n    + '\n    + \n    + test_expect_success 'stash save --include-untracked cleaned the untracked files' '\n    +@@\n    + \ttest_cmp untracked_expect untracked/untracked\n    + '\n    + \n    ++test_expect_success 'stash pop after save --include-untracked leaves files untracked again with stash.index' '\n    ++\tgit init repo &&\n    ++\ttest_when_finished rm -r repo &&\n    ++\t(\n    ++\t\tcd repo &&\n    ++\t\tgit config stash.index true &&\n    ++\t\tsetup &&\n    ++\t\tcat >expect <<-EOF &&\n    ++\t\tMM file\n    ++\t\t?? HEAD\n    ++\t\t?? actual\n    ++\t\t?? expect\n    ++\t\t?? file2\n    ++\t\t?? untracked/\n    ++\t\tEOF\n    ++\n    ++\t\tgit stash pop &&\n    ++\t\tgit status --porcelain >actual &&\n    ++\t\ttest_cmp expect actual &&\n    ++\t\techo 1 >expect_file2 &&\n    ++\t\ttest_cmp expect_file2 file2 &&\n    ++\t\techo untracked >untracked_expect &&\n    ++\t\ttest_cmp untracked_expect untracked/untracked\n    ++\t)\n    ++'\n    ++\n    + test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n    + \tgit clean --force --quiet -d\n    + '\n    +@@\n    + \ttest_path_is_file bar\n    + '\n    + \n    ++test_expect_success 'stash push with $IFS character with stash.index' '\n    ++\ttest_config stash.index true &&\n    ++\t>\"foo bar\" &&\n    ++\t>foo &&\n    ++\t>bar &&\n    ++\tgit add foo* &&\n    ++\tgit stash push --include-untracked -- \"foo b*\" &&\n    ++\ttest_path_is_missing \"foo bar\" &&\n    ++\ttest_path_is_file foo &&\n    ++\ttest_path_is_file bar &&\n    ++\tgit stash pop --no-index &&\n    ++\ttest_path_is_file \"foo bar\" &&\n    ++\ttest_path_is_file foo &&\n    ++\ttest_path_is_file bar\n    ++'\n    ++\n    + test_expect_success 'stash previously ignored file' '\n    + \tcat >.gitignore <<-EOF &&\n    + \tignored\n 7:  4b92d47e16 <  -:  ---------- t3904: adjust stash -p test to account for index states with breaking changes\n 8:  af14dee1be <  -:  ---------- t3905: adjust stash -u tests for breaking changes\n\nbase-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n-- \n2.48.1\n\n"},{"id":"526407","messageId":"1328eb8eac65ec7bbf1f3cb257d7221a372c45c3.1757982870.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"[PATCH v2 1/4] t3903: reduce dependencies on previous tests","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T00:37:34Z","receivedAt":"2025-09-16T00:37:55Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Skipping previous tests to work through only failing tests with\narguments like --run=4,122- causes some tests to fail because subdir\ndoesn't exist yet (it is created by a previous test; typically\n\"unstashing in a subdirectory\"). Create it on demand for tests that need\nit, but don't fail (-p) if the directory already exists.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3903-stash.sh | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 74666ff3e4..b8936a653b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -895,6 +895,7 @@ setup_stash()\n \n test_expect_success 'apply: show same status as git status (relative to ./)' '\n \tgit stash clear &&\n+\tmkdir -p subdir &&\n \techo 1 >subdir/subfile1 &&\n \techo 2 >subdir/subfile2 &&\n \tgit add subdir/subfile1 &&\n@@ -1327,6 +1328,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> leaves untracked files in subdir intact' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked1 &&\n \t>subdir/tracked2 &&\n@@ -1343,6 +1345,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> works with binary files' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked &&\n \tcp \"$TEST_DIRECTORY\"/test-binary-1.png subdir/tracked-binary &&\n-- \n2.48.1\n\n"},{"id":"526408","messageId":"8ac06ad62df581bb84ecdca0b0144c218daa0733.1757982870.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"[PATCH v2 2/4] t3905: remove unneeded blank line","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T00:37:35Z","receivedAt":"2025-09-16T00:37:56Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"This is leftover from 787513027a (stash: Add --include-untracked option\nto stash and remove all untracked files, 2011-06-24) when it was\nconverted in bbaa45c3aa (t3905: move all commands into test cases,\n2021-02-08).\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3905-stash-include-untracked.sh | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 1289ae3e07..7704709054 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -87,7 +87,6 @@\n \n test_expect_success 'clean up untracked/untracked file to prepare for next tests' '\n \tgit clean --force --quiet\n-\n '\n \n test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '\n-- \n2.48.1\n\n"},{"id":"526409","messageId":"bf0a561ce36afe14b6bc03bf851d19b30ef491ad.1757982870.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"[PATCH v2 3/4] stash: refactor private config globals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T00:37:36Z","receivedAt":"2025-09-16T00:37:57Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"A subsequent commit will access a new config variable in the stash\nsubcommand implementations, which requires the variables to be declared\nbefore the relevant functions. Prep with a pure refactoring change to\nconsolidate config-related globals with the rest of the globals.\n\nBest-viewed-with: --color-moved\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n builtin/stash.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex cfbd92852a..d9b478d1d1 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -127,6 +127,10 @@ static const char * const git_stash_save_usage[] = {\n static const char ref_stash[] = \"refs/stash\";\n static struct strbuf stash_index_path = STRBUF_INIT;\n \n+static int show_stat = 1;\n+static int show_patch;\n+static int show_include_untracked;\n+\n /*\n  * w_commit is set to the commit containing the working tree\n  * b_commit is set to the base commit\n@@ -845,10 +849,6 @@ static int list_stash(int argc, const char **argv, const char *prefix,\n \treturn run_command(&cp);\n }\n \n-static int show_stat = 1;\n-static int show_patch;\n-static int show_include_untracked;\n-\n static int git_stash_config(const char *var, const char *value,\n \t\t\t    const struct config_context *ctx, void *cb)\n {\n-- \n2.48.1\n\n"},{"id":"526410","messageId":"585e124467dcb1ec1de71fa72e749140d44dc367.1757982870.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"[PATCH v2 4/4] stash: honor stash.index in apply, pop modes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T00:37:37Z","receivedAt":"2025-09-16T00:38:00Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"With stash.index=true, git-stash(1) command now tries to reinstate the\nindex by default in the \"apply\" and \"pop\" modes. Not doing so creates a\ncommon trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\npush\" because carefully staged indices are lost and have to be manually\nrecreated. OTOH, this mode is not always desirable and may create more\nconflicts when applying stashes. As usual, \"--no-index\" will disable\nthis behavior if you set \"stash.index\".\n\n[1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n[2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n Documentation/config/stash.adoc    |   5 +\n builtin/stash.c                    |   9 +-\n t/t3903-stash.sh                   | 155 +++++++++++++++++++++++++++++\n t/t3904-stash-patch.sh             |  11 ++\n t/t3905-stash-include-untracked.sh |  48 ++++++++-\n 5 files changed, 225 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\nindex ec1edaeba6..e556105a15 100644\n--- a/Documentation/config/stash.adoc\n+++ b/Documentation/config/stash.adoc\n@@ -1,3 +1,8 @@\n+stash.index::\n+\tIf this is set to true, `git stash apply` and `git stash pop` will\n+\tbehave as if `--index` was supplied. Defaults to false. See the\n+\tdescriptions in linkgit:git-stash[1].\n+\n stash.showIncludeUntracked::\n \tIf this is set to true, the `git stash show` command will show\n \tthe untracked files of a stash entry.  Defaults to false. See\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex d9b478d1d1..8a0eef3c70 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -130,6 +130,7 @@ static struct strbuf stash_index_path = STRBUF_INIT;\n static int show_stat = 1;\n static int show_patch;\n static int show_include_untracked;\n+static int use_index;\n \n /*\n  * w_commit is set to the commit containing the working tree\n@@ -662,7 +663,7 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n {\n \tint ret = -1;\n \tint quiet = 0;\n-\tint index = 0;\n+\tint index = use_index;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n@@ -759,7 +760,7 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n \t\t     struct repository *repo UNUSED)\n {\n \tint ret = -1;\n-\tint index = 0;\n+\tint index = use_index;\n \tint quiet = 0;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n@@ -864,6 +865,10 @@ static int git_stash_config(const char *var, const char *value,\n \t\tshow_include_untracked = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"stash.index\")) {\n+\t\tuse_index = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n \treturn git_diff_basic_config(var, value, ctx, cb);\n }\n \ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex b8936a653b..1d53a94165 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -111,6 +111,19 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n+test_expect_success 'apply stashed changes with stash.index' '\n+\ttest_config stash.index true &&\n+\tgit reset --hard HEAD^ &&\n+\techo 5 >other-file &&\n+\tgit add other-file &&\n+\ttest_tick &&\n+\tgit commit -m other-file &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n test_expect_success 'apply stashed changes (including index)' '\n \tgit reset --hard HEAD^ &&\n \techo 6 >other-file &&\n@@ -150,6 +163,21 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n+test_expect_success 'drop top stash with stash.index' '\n+\ttest_config stash.index true &&\n+\tgit reset --hard &&\n+\tgit stash list >expected &&\n+\techo 7 >file &&\n+\tgit stash &&\n+\tgit stash drop &&\n+\tgit stash list >actual &&\n+\ttest_cmp expected actual &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n test_expect_success 'drop middle stash' '\n \tgit reset --hard &&\n \techo 8 >file &&\n@@ -170,6 +198,27 @@ setup_stash()\n \ttest 1 = $(git show HEAD:file)\n '\n \n+test_expect_success 'drop middle stash with stash.index' '\n+\ttest_config stash.index true &&\n+\tgit reset --hard &&\n+\techo 8 >file &&\n+\tgit stash &&\n+\techo 9 >file &&\n+\tgit stash &&\n+\tgit stash drop stash@{1} &&\n+\ttest 2 = $(git stash list | wc -l) &&\n+\tgit stash apply &&\n+\ttest 9 = $(cat file) &&\n+\ttest 1 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file) &&\n+\tgit reset --hard &&\n+\tgit stash drop &&\n+\tgit stash apply &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file)\n+'\n+\n test_expect_success 'drop middle stash by index' '\n \tgit reset --hard &&\n \techo 8 >file &&\n@@ -236,6 +285,17 @@ setup_stash()\n \ttest 0 = $(git stash list | wc -l)\n '\n \n+test_expect_success 'stash pop with stash.index' '\n+\ttest_config stash.index true &&\n+\tgit reset --hard &&\n+\tsetup_stash &&\n+\tgit stash pop &&\n+\ttest 3 = $(cat file) &&\n+\ttest 2 = $(git show :file) &&\n+\ttest 1 = $(git show HEAD:file) &&\n+\ttest 0 = $(git stash list | wc -l)\n+'\n+\n cat >expect <<EOF\n diff --git a/file2 b/file2\n new file mode 100644\n@@ -328,6 +388,22 @@ setup_stash()\n \ttest_must_be_empty output.out\n '\n \n+test_expect_success 'pop -q works and is quiet with stash.index' '\n+\t# Added file, deleted file, modified file all staged for commit\n+\techo foo >new-file &&\n+\techo test >file &&\n+\tgit add new-file file &&\n+\tgit rm other-file &&\n+\tgit stash &&\n+\n+\ttest_config stash.index true &&\n+\tgit stash pop -q >output.out 2>&1 &&\n+\techo test >expect &&\n+\tgit show :file >actual &&\n+\ttest_cmp expect actual &&\n+\ttest_must_be_empty output.out\n+'\n+\n test_expect_success 'pop -q --index works and is quiet' '\n \techo foo >file &&\n \tgit add file &&\n@@ -1178,6 +1254,19 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash -- <pathspec> stashes and restores the file with stash.index' '\n+\ttest_config stash.index true &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\tgit stash push -- foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n \tmkdir sub &&\n \t>foo &&\n@@ -1194,6 +1283,24 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash -- <pathspec> stashes in subdirectory with stash.index' '\n+\ttest_config stash.index true &&\n+\trm -r sub &&\n+\tmkdir sub &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo bar &&\n+\t(\n+\t\tcd sub &&\n+\t\tgit stash push -- ../foo\n+\t) &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_missing foo &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash with multiple pathspec arguments' '\n \t>foo &&\n \t>bar &&\n@@ -1209,6 +1316,22 @@ setup_stash()\n \ttest_path_is_file extra\n '\n \n+test_expect_success 'stash with multiple pathspec arguments with stash.index' '\n+\ttest_config stash.index true &&\n+\t>foo &&\n+\t>bar &&\n+\t>extra &&\n+\tgit add foo bar extra &&\n+\tgit stash push -- foo bar &&\n+\ttest_path_is_missing bar &&\n+\ttest_path_is_missing foo &&\n+\ttest_path_is_file extra &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\ttest_path_is_file extra\n+'\n+\n test_expect_success 'stash with file including $IFS character' '\n \t>\"foo bar\" &&\n \t>foo &&\n@@ -1224,6 +1347,22 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash with file including $IFS character with stash.index' '\n+\ttest_config stash.index true &&\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash with pathspec matching multiple paths' '\n \techo original >file &&\n \techo original >other-file &&\n@@ -1312,6 +1451,22 @@ setup_stash()\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash without verb with pathspec with stash.index' '\n+\ttest_config stash.index true &&\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n \tgit reset &&\n \t>foo &&\ndiff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh\nindex ae313e3c70..fe402f6ab5 100755\n--- a/t/t3904-stash-patch.sh\n+++ b/t/t3904-stash-patch.sh\n@@ -42,6 +42,17 @@\n \tverify_state dir/foo work head\n '\n \n+test_expect_success 'git stash -p with stash.index' '\n+\ttest_config stash.index true &&\n+\tset_state HEAD HEADfile_work HEADfile_index &&\n+\tset_state dir/foo work index &&\n+\ttest_write_lines y n y | git stash save -p &&\n+\tgit reset --hard &&\n+\tgit stash apply &&\n+\tverify_state HEAD HEADfile_work HEADfile_index &&\n+\tverify_state dir/foo head index\n+'\n+\n test_expect_success 'git stash -p --no-keep-index' '\n \tset_state HEAD HEADfile_work HEADfile_index &&\n \tset_state bar bar_work bar_index &&\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 7704709054..5407f11030 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -7,7 +7,7 @@\n \n . ./test-lib.sh\n \n-test_expect_success 'stash save --include-untracked some dirty working directory' '\n+setup() {\n \techo 1 >file &&\n \tgit add file &&\n \ttest_tick &&\n@@ -23,6 +23,10 @@\n \tgit stash --include-untracked &&\n \tgit diff-files --quiet &&\n \tgit diff-index --cached --quiet HEAD\n+}\n+\n+test_expect_success 'stash save --include-untracked some dirty working directory' '\n+\tsetup\n '\n \n test_expect_success 'stash save --include-untracked cleaned the untracked files' '\n@@ -108,6 +112,32 @@\n \ttest_cmp untracked_expect untracked/untracked\n '\n \n+test_expect_success 'stash pop after save --include-untracked leaves files untracked again with stash.index' '\n+\tgit init repo &&\n+\ttest_when_finished rm -r repo &&\n+\t(\n+\t\tcd repo &&\n+\t\tgit config stash.index true &&\n+\t\tsetup &&\n+\t\tcat >expect <<-EOF &&\n+\t\tMM file\n+\t\t?? HEAD\n+\t\t?? actual\n+\t\t?? expect\n+\t\t?? file2\n+\t\t?? untracked/\n+\t\tEOF\n+\n+\t\tgit stash pop &&\n+\t\tgit status --porcelain >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\techo 1 >expect_file2 &&\n+\t\ttest_cmp expect_file2 file2 &&\n+\t\techo untracked >untracked_expect &&\n+\t\ttest_cmp untracked_expect untracked/untracked\n+\t)\n+'\n+\n test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n \tgit clean --force --quiet -d\n '\n@@ -221,6 +251,22 @@\n \ttest_path_is_file bar\n '\n \n+test_expect_success 'stash push with $IFS character with stash.index' '\n+\ttest_config stash.index true &&\n+\t>\"foo bar\" &&\n+\t>foo &&\n+\t>bar &&\n+\tgit add foo* &&\n+\tgit stash push --include-untracked -- \"foo b*\" &&\n+\ttest_path_is_missing \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar &&\n+\tgit stash pop --no-index &&\n+\ttest_path_is_file \"foo bar\" &&\n+\ttest_path_is_file foo &&\n+\ttest_path_is_file bar\n+'\n+\n test_expect_success 'stash previously ignored file' '\n \tcat >.gitignore <<-EOF &&\n \tignored\n-- \n2.48.1\n\n"},{"id":"526436","messageId":"25836bc2-db3a-4761-b13d-c587728f4c3c@gmail.com","threadId":"63436","inReplyTo":"585e124467dcb1ec1de71fa72e749140d44dc367.1757982870.git.ben.knoble+github@gmail.com","subject":"Re: [PATCH v2 4/4] stash: honor stash.index in apply, pop modes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-09-16T09:18:31Z","receivedAt":"2025-09-16T09:18:34Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ben\n\nOn 16/09/2025 01:37, D. Ben Knoble wrote:\n> With stash.index=true, git-stash(1) command now tries to reinstate the\n> index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n> common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n> push\" because carefully staged indices are lost and have to be manually\n> recreated. OTOH, this mode is not always desirable and may create more\n> conflicts when applying stashes. As usual, \"--no-index\" will disable\n> this behavior if you set \"stash.index\".\n\nI don't have a strong opinion either way on the new config setting but I \ndo think we should rationalize the new tests. Assuming we already have \ngood coverage for \"git stash pop --index\" then all we need to do is \ncheck that \"git -c stash.index=true stash pop\", \"git -c stash.index=true \nstash pop --no-index\" and \"git -c stash.index=false stash pop --index\". \nWe don't need an exhaustive list of tests that check the config setting \nin scenarios like \"create twos stashes, drop the second one and apply \nthe first\". Tests like that add no new coverage for the changes in this \npatch and slow the test suite down.\n\nThanks\n\nPhillip\n> [1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n> [2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n> \n> Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n> ---\n>   Documentation/config/stash.adoc    |   5 +\n>   builtin/stash.c                    |   9 +-\n>   t/t3903-stash.sh                   | 155 +++++++++++++++++++++++++++++\n>   t/t3904-stash-patch.sh             |  11 ++\n>   t/t3905-stash-include-untracked.sh |  48 ++++++++-\n>   5 files changed, 225 insertions(+), 3 deletions(-)\n> \n> diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\n> index ec1edaeba6..e556105a15 100644\n> --- a/Documentation/config/stash.adoc\n> +++ b/Documentation/config/stash.adoc\n> @@ -1,3 +1,8 @@\n> +stash.index::\n> +\tIf this is set to true, `git stash apply` and `git stash pop` will\n> +\tbehave as if `--index` was supplied. Defaults to false. See the\n> +\tdescriptions in linkgit:git-stash[1].\n> +\n>   stash.showIncludeUntracked::\n>   \tIf this is set to true, the `git stash show` command will show\n>   \tthe untracked files of a stash entry.  Defaults to false. See\n> diff --git a/builtin/stash.c b/builtin/stash.c\n> index d9b478d1d1..8a0eef3c70 100644\n> --- a/builtin/stash.c\n> +++ b/builtin/stash.c\n> @@ -130,6 +130,7 @@ static struct strbuf stash_index_path = STRBUF_INIT;\n>   static int show_stat = 1;\n>   static int show_patch;\n>   static int show_include_untracked;\n> +static int use_index;\n>   \n>   /*\n>    * w_commit is set to the commit containing the working tree\n> @@ -662,7 +663,7 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n>   {\n>   \tint ret = -1;\n>   \tint quiet = 0;\n> -\tint index = 0;\n> +\tint index = use_index;\n>   \tstruct stash_info info = STASH_INFO_INIT;\n>   \tstruct option options[] = {\n>   \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n> @@ -759,7 +760,7 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n>   \t\t     struct repository *repo UNUSED)\n>   {\n>   \tint ret = -1;\n> -\tint index = 0;\n> +\tint index = use_index;\n>   \tint quiet = 0;\n>   \tstruct stash_info info = STASH_INFO_INIT;\n>   \tstruct option options[] = {\n> @@ -864,6 +865,10 @@ static int git_stash_config(const char *var, const char *value,\n>   \t\tshow_include_untracked = git_config_bool(var, value);\n>   \t\treturn 0;\n>   \t}\n> +\tif (!strcmp(var, \"stash.index\")) {\n> +\t\tuse_index = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n>   \treturn git_diff_basic_config(var, value, ctx, cb);\n>   }\n>   \n> diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\n> index b8936a653b..1d53a94165 100755\n> --- a/t/t3903-stash.sh\n> +++ b/t/t3903-stash.sh\n> @@ -111,6 +111,19 @@ setup_stash()\n>   \ttest 1 = $(git show HEAD:file)\n>   '\n>   \n> +test_expect_success 'apply stashed changes with stash.index' '\n> +\ttest_config stash.index true &&\n> +\tgit reset --hard HEAD^ &&\n> +\techo 5 >other-file &&\n> +\tgit add other-file &&\n> +\ttest_tick &&\n> +\tgit commit -m other-file &&\n> +\tgit stash apply &&\n> +\ttest 3 = $(cat file) &&\n> +\ttest 2 = $(git show :file) &&\n> +\ttest 1 = $(git show HEAD:file)\n> +'\n> +\n>   test_expect_success 'apply stashed changes (including index)' '\n>   \tgit reset --hard HEAD^ &&\n>   \techo 6 >other-file &&\n> @@ -150,6 +163,21 @@ setup_stash()\n>   \ttest 1 = $(git show HEAD:file)\n>   '\n>   \n> +test_expect_success 'drop top stash with stash.index' '\n> +\ttest_config stash.index true &&\n> +\tgit reset --hard &&\n> +\tgit stash list >expected &&\n> +\techo 7 >file &&\n> +\tgit stash &&\n> +\tgit stash drop &&\n> +\tgit stash list >actual &&\n> +\ttest_cmp expected actual &&\n> +\tgit stash apply &&\n> +\ttest 3 = $(cat file) &&\n> +\ttest 2 = $(git show :file) &&\n> +\ttest 1 = $(git show HEAD:file)\n> +'\n> +\n>   test_expect_success 'drop middle stash' '\n>   \tgit reset --hard &&\n>   \techo 8 >file &&\n> @@ -170,6 +198,27 @@ setup_stash()\n>   \ttest 1 = $(git show HEAD:file)\n>   '\n>   \n> +test_expect_success 'drop middle stash with stash.index' '\n> +\ttest_config stash.index true &&\n> +\tgit reset --hard &&\n> +\techo 8 >file &&\n> +\tgit stash &&\n> +\techo 9 >file &&\n> +\tgit stash &&\n> +\tgit stash drop stash@{1} &&\n> +\ttest 2 = $(git stash list | wc -l) &&\n> +\tgit stash apply &&\n> +\ttest 9 = $(cat file) &&\n> +\ttest 1 = $(git show :file) &&\n> +\ttest 1 = $(git show HEAD:file) &&\n> +\tgit reset --hard &&\n> +\tgit stash drop &&\n> +\tgit stash apply &&\n> +\ttest 3 = $(cat file) &&\n> +\ttest 2 = $(git show :file) &&\n> +\ttest 1 = $(git show HEAD:file)\n> +'\n> +\n>   test_expect_success 'drop middle stash by index' '\n>   \tgit reset --hard &&\n>   \techo 8 >file &&\n> @@ -236,6 +285,17 @@ setup_stash()\n>   \ttest 0 = $(git stash list | wc -l)\n>   '\n>   \n> +test_expect_success 'stash pop with stash.index' '\n> +\ttest_config stash.index true &&\n> +\tgit reset --hard &&\n> +\tsetup_stash &&\n> +\tgit stash pop &&\n> +\ttest 3 = $(cat file) &&\n> +\ttest 2 = $(git show :file) &&\n> +\ttest 1 = $(git show HEAD:file) &&\n> +\ttest 0 = $(git stash list | wc -l)\n> +'\n> +\n>   cat >expect <<EOF\n>   diff --git a/file2 b/file2\n>   new file mode 100644\n> @@ -328,6 +388,22 @@ setup_stash()\n>   \ttest_must_be_empty output.out\n>   '\n>   \n> +test_expect_success 'pop -q works and is quiet with stash.index' '\n> +\t# Added file, deleted file, modified file all staged for commit\n> +\techo foo >new-file &&\n> +\techo test >file &&\n> +\tgit add new-file file &&\n> +\tgit rm other-file &&\n> +\tgit stash &&\n> +\n> +\ttest_config stash.index true &&\n> +\tgit stash pop -q >output.out 2>&1 &&\n> +\techo test >expect &&\n> +\tgit show :file >actual &&\n> +\ttest_cmp expect actual &&\n> +\ttest_must_be_empty output.out\n> +'\n> +\n>   test_expect_success 'pop -q --index works and is quiet' '\n>   \techo foo >file &&\n>   \tgit add file &&\n> @@ -1178,6 +1254,19 @@ setup_stash()\n>   \ttest_path_is_file bar\n>   '\n>   \n> +test_expect_success 'stash -- <pathspec> stashes and restores the file with stash.index' '\n> +\ttest_config stash.index true &&\n> +\t>foo &&\n> +\t>bar &&\n> +\tgit add foo bar &&\n> +\tgit stash push -- foo &&\n> +\ttest_path_is_file bar &&\n> +\ttest_path_is_missing foo &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar\n> +'\n> +\n>   test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n>   \tmkdir sub &&\n>   \t>foo &&\n> @@ -1194,6 +1283,24 @@ setup_stash()\n>   \ttest_path_is_file bar\n>   '\n>   \n> +test_expect_success 'stash -- <pathspec> stashes in subdirectory with stash.index' '\n> +\ttest_config stash.index true &&\n> +\trm -r sub &&\n> +\tmkdir sub &&\n> +\t>foo &&\n> +\t>bar &&\n> +\tgit add foo bar &&\n> +\t(\n> +\t\tcd sub &&\n> +\t\tgit stash push -- ../foo\n> +\t) &&\n> +\ttest_path_is_file bar &&\n> +\ttest_path_is_missing foo &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar\n> +'\n> +\n>   test_expect_success 'stash with multiple pathspec arguments' '\n>   \t>foo &&\n>   \t>bar &&\n> @@ -1209,6 +1316,22 @@ setup_stash()\n>   \ttest_path_is_file extra\n>   '\n>   \n> +test_expect_success 'stash with multiple pathspec arguments with stash.index' '\n> +\ttest_config stash.index true &&\n> +\t>foo &&\n> +\t>bar &&\n> +\t>extra &&\n> +\tgit add foo bar extra &&\n> +\tgit stash push -- foo bar &&\n> +\ttest_path_is_missing bar &&\n> +\ttest_path_is_missing foo &&\n> +\ttest_path_is_file extra &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar &&\n> +\ttest_path_is_file extra\n> +'\n> +\n>   test_expect_success 'stash with file including $IFS character' '\n>   \t>\"foo bar\" &&\n>   \t>foo &&\n> @@ -1224,6 +1347,22 @@ setup_stash()\n>   \ttest_path_is_file bar\n>   '\n>   \n> +test_expect_success 'stash with file including $IFS character with stash.index' '\n> +\ttest_config stash.index true &&\n> +\t>\"foo bar\" &&\n> +\t>foo &&\n> +\t>bar &&\n> +\tgit add foo* &&\n> +\tgit stash push -- \"foo b*\" &&\n> +\ttest_path_is_missing \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar\n> +'\n> +\n>   test_expect_success 'stash with pathspec matching multiple paths' '\n>   \techo original >file &&\n>   \techo original >other-file &&\n> @@ -1312,6 +1451,22 @@ setup_stash()\n>   \ttest_path_is_file bar\n>   '\n>   \n> +test_expect_success 'stash without verb with pathspec with stash.index' '\n> +\ttest_config stash.index true &&\n> +\t>\"foo bar\" &&\n> +\t>foo &&\n> +\t>bar &&\n> +\tgit add foo* &&\n> +\tgit stash -- \"foo b*\" &&\n> +\ttest_path_is_missing \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar\n> +'\n> +\n>   test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n>   \tgit reset &&\n>   \t>foo &&\n> diff --git a/t/t3904-stash-patch.sh b/t/t3904-stash-patch.sh\n> index ae313e3c70..fe402f6ab5 100755\n> --- a/t/t3904-stash-patch.sh\n> +++ b/t/t3904-stash-patch.sh\n> @@ -42,6 +42,17 @@\n>   \tverify_state dir/foo work head\n>   '\n>   \n> +test_expect_success 'git stash -p with stash.index' '\n> +\ttest_config stash.index true &&\n> +\tset_state HEAD HEADfile_work HEADfile_index &&\n> +\tset_state dir/foo work index &&\n> +\ttest_write_lines y n y | git stash save -p &&\n> +\tgit reset --hard &&\n> +\tgit stash apply &&\n> +\tverify_state HEAD HEADfile_work HEADfile_index &&\n> +\tverify_state dir/foo head index\n> +'\n> +\n>   test_expect_success 'git stash -p --no-keep-index' '\n>   \tset_state HEAD HEADfile_work HEADfile_index &&\n>   \tset_state bar bar_work bar_index &&\n> diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\n> index 7704709054..5407f11030 100755\n> --- a/t/t3905-stash-include-untracked.sh\n> +++ b/t/t3905-stash-include-untracked.sh\n> @@ -7,7 +7,7 @@\n>   \n>   . ./test-lib.sh\n>   \n> -test_expect_success 'stash save --include-untracked some dirty working directory' '\n> +setup() {\n>   \techo 1 >file &&\n>   \tgit add file &&\n>   \ttest_tick &&\n> @@ -23,6 +23,10 @@\n>   \tgit stash --include-untracked &&\n>   \tgit diff-files --quiet &&\n>   \tgit diff-index --cached --quiet HEAD\n> +}\n> +\n> +test_expect_success 'stash save --include-untracked some dirty working directory' '\n> +\tsetup\n>   '\n>   \n>   test_expect_success 'stash save --include-untracked cleaned the untracked files' '\n> @@ -108,6 +112,32 @@\n>   \ttest_cmp untracked_expect untracked/untracked\n>   '\n>   \n> +test_expect_success 'stash pop after save --include-untracked leaves files untracked again with stash.index' '\n> +\tgit init repo &&\n> +\ttest_when_finished rm -r repo &&\n> +\t(\n> +\t\tcd repo &&\n> +\t\tgit config stash.index true &&\n> +\t\tsetup &&\n> +\t\tcat >expect <<-EOF &&\n> +\t\tMM file\n> +\t\t?? HEAD\n> +\t\t?? actual\n> +\t\t?? expect\n> +\t\t?? file2\n> +\t\t?? untracked/\n> +\t\tEOF\n> +\n> +\t\tgit stash pop &&\n> +\t\tgit status --porcelain >actual &&\n> +\t\ttest_cmp expect actual &&\n> +\t\techo 1 >expect_file2 &&\n> +\t\ttest_cmp expect_file2 file2 &&\n> +\t\techo untracked >untracked_expect &&\n> +\t\ttest_cmp untracked_expect untracked/untracked\n> +\t)\n> +'\n> +\n>   test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n>   \tgit clean --force --quiet -d\n>   '\n> @@ -221,6 +251,22 @@\n>   \ttest_path_is_file bar\n>   '\n>   \n> +test_expect_success 'stash push with $IFS character with stash.index' '\n> +\ttest_config stash.index true &&\n> +\t>\"foo bar\" &&\n> +\t>foo &&\n> +\t>bar &&\n> +\tgit add foo* &&\n> +\tgit stash push --include-untracked -- \"foo b*\" &&\n> +\ttest_path_is_missing \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar &&\n> +\tgit stash pop --no-index &&\n> +\ttest_path_is_file \"foo bar\" &&\n> +\ttest_path_is_file foo &&\n> +\ttest_path_is_file bar\n> +'\n> +\n>   test_expect_success 'stash previously ignored file' '\n>   \tcat >.gitignore <<-EOF &&\n>   \tignored\n\n"},{"id":"526437","messageId":"4736597d-1144-43ce-8c09-e78e4563765b@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"Re: [PATCH v2 0/4] Teach git-stash to use --index from config","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-09-16T09:24:59Z","receivedAt":"2025-09-16T09:25:03Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ben\n\nOn 16/09/2025 01:37, D. Ben Knoble wrote:\n> \n> PS I've left some new t3903 tests as copy-pasta for now to get feedback\n> on the rest of the series; there are bits of that file that could use an\n> update to the modern style (e.g., not using \"test 1 = $(cat file)\").\n> Since some new tests are substantially similar to old tests that use\n> this style, such cleanup is /probably/ warranted but will delay eyeballs\n> on the core of this series.\n\nIn situations like this even if we don't convert the old tests, I think \nit is worth using a modern style for the new ones. Some people argue \nthat the style within a file should be consistent but in practice that \nmeans if someone decides to clean them up in the future they have even \nmore work to do and in the meantime we have a harder time debugging test \nfailures.\n\nThe cleanups in patches 1 and 2 look very welcome. I've left a comment \nabout the tests on patch 4.\n\nThanks\n\nPhillip\n> Published-as: https://github.com/benknoble/git/tree/stash-apply-index\n> v1: https://lore.kernel.org/git/20250510183358.36806-1-ben.knoble+github@gmail.com/\n> \n> D. Ben Knoble (4):\n>    t3903: reduce dependencies on previous tests\n>    t3905: remove unneeded blank line\n>    stash: refactor private config globals\n>    stash: honor stash.index in apply, pop modes\n> \n>   Documentation/config/stash.adoc    |   5 +\n>   builtin/stash.c                    |  17 ++--\n>   t/t3903-stash.sh                   | 158 +++++++++++++++++++++++++++++\n>   t/t3904-stash-patch.sh             |  11 ++\n>   t/t3905-stash-include-untracked.sh |  49 ++++++++-\n>   5 files changed, 232 insertions(+), 8 deletions(-)\n> \n> Diff-intervalle contre v1 :\n>   1:  1328eb8eac =  1:  1328eb8eac t3903: reduce dependencies on previous tests\n>   2:  8ac06ad62d =  2:  8ac06ad62d t3905: remove unneeded blank line\n>   3:  c068f1dc0b <  -:  ---------- BreakingChanges: announce stash {apply,pop} will imply --index\n>   4:  8caff91c0e <  -:  ---------- stash: restore the index by default when breaking changes are enabled\n>   5:  387427bb8c <  -:  ---------- t0450: mark stash documentation as a known discrepancy\n>   9:  c72a1fe6ea !  3:  bf0a561ce3 t3906: adjust stash submodule tests to account for breaking changes\n>      @@ Metadata\n>       Author: D. Ben Knoble <ben.knoble+github@gmail.com>\n>       \n>        ## Commit message ##\n>      -    t3906: adjust stash submodule tests to account for breaking changes\n>      +    stash: refactor private config globals\n>       \n>      -    I cannot explain _why_ this occurs, but it seems that automatically\n>      -    unstashing the index from previous commits resolves some known failures\n>      -    in t3906 (which are captured by t/lib-submodule-updates.sh).\n>      +    A subsequent commit will access a new config variable in the stash\n>      +    subcommand implementations, which requires the variables to be declared\n>      +    before the relevant functions. Prep with a pure refactoring change to\n>      +    consolidate config-related globals with the rest of the globals.\n>       \n>      -    In particular:\n>      -    - 'replace tracked file with submodule creates empty directory' succeeds\n>      -      with breaking changes;\n>      -    - all KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR tests\n>      -      succeed with breaking changes;\n>      -    - all KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES suceed with\n>      -      breaking changes.\n>      +    Best-viewed-with: --color-moved\n>       \n>      - ## t/lib-submodule-update.sh ##\n>      -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n>      - \t'\n>      - \t# Replacing a tracked file with a submodule produces an empty\n>      - \t# directory ...\n>      --\ttest_expect_$RESULT \"$command: replace tracked file with submodule creates empty directory\" '\n>      -+\ttest_expect_$RESULT !WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n>      -+\t\tprolog &&\n>      -+\t\treset_work_tree_to replace_sub1_with_file &&\n>      -+\t\t(\n>      -+\t\t\tcd submodule_update &&\n>      -+\t\t\tgit branch -t replace_file_with_sub1 origin/replace_file_with_sub1 &&\n>      -+\t\t\t$command replace_file_with_sub1 &&\n>      -+\t\t\ttest_superproject_content origin/replace_file_with_sub1 &&\n>      -+\t\t\ttest_dir_is_empty sub1 &&\n>      -+\t\t\tgit submodule update --init --recursive &&\n>      -+\t\t\ttest_submodule_content sub1 origin/replace_file_with_sub1\n>      -+\t\t)\n>      -+\t'\n>      -+\t# (unless we automatically unstash the index!)\n>      -+\ttest_expect_success WITH_BREAKING_CHANGES \"$command: replace tracked file with submodule creates empty directory\" '\n>      - \t\tprolog &&\n>      - \t\treset_work_tree_to replace_sub1_with_file &&\n>      - \t\t(\n>      -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n>      - \t'\n>      - \t# ... as does removing a directory with tracked files with a\n>      - \t# submodule.\n>      --\tif test \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n>      -+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n>      -+\t\ttest \"$KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR\" = 1\n>      - \tthen\n>      - \t\t# Non fast-forward merges fail with \"Directory sub1 doesn't\n>      - \t\t# exist. sub1\" because the empty submodule directory is not\n>      -@@ t/lib-submodule-update.sh: test_submodule_switch_common ()\n>      - \t'\n>      + ## builtin/stash.c ##\n>      +@@ builtin/stash.c: static const char * const git_stash_save_usage[] = {\n>      + static const char ref_stash[] = \"refs/stash\";\n>      + static struct strbuf stash_index_path = STRBUF_INIT;\n>        \n>      - \t######################## Disappearing submodule #######################\n>      --\t# Removing a submodule doesn't remove its work tree ...\n>      --\tif test \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n>      -+\t# Removing a submodule doesn't remove its work tree (unless stash applies the index!) ...\n>      -+\tif ! test_have_prereq WITH_BREAKING_CHANGES &&\n>      -+\t\ttest \"$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES\" = 1\n>      - \tthen\n>      - \t\tRESULT=\"failure\"\n>      - \telse\n>      ++static int show_stat = 1;\n>      ++static int show_patch;\n>      ++static int show_include_untracked;\n>      ++\n>      + /*\n>      +  * w_commit is set to the commit containing the working tree\n>      +  * b_commit is set to the base commit\n>      +@@ builtin/stash.c: static int list_stash(int argc, const char **argv, const char *prefix,\n>      + \treturn run_command(&cp);\n>      + }\n>      +\n>      +-static int show_stat = 1;\n>      +-static int show_patch;\n>      +-static int show_include_untracked;\n>      +-\n>      + static int git_stash_config(const char *var, const char *value,\n>      + \t\t\t    const struct config_context *ctx, void *cb)\n>      + {\n>   6:  0a12983c00 !  4:  585e124467 t3903: adjust stash test to account for --[no-]index with breaking changes\n>      @@ Metadata\n>       Author: D. Ben Knoble <ben.knoble+github@gmail.com>\n>       \n>        ## Commit message ##\n>      -    t3903: adjust stash test to account for --[no-]index with breaking changes\n>      +    stash: honor stash.index in apply, pop modes\n>       \n>      -    A few tests check the results of the index after applying a stash; with\n>      -    breaking changes from previous commits that automatically restore the\n>      -    stashed index, the expected values are wrong.\n>      +    With stash.index=true, git-stash(1) command now tries to reinstate the\n>      +    index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n>      +    common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n>      +    push\" because carefully staged indices are lost and have to be manually\n>      +    recreated. OTOH, this mode is not always desirable and may create more\n>      +    conflicts when applying stashes. As usual, \"--no-index\" will disable\n>      +    this behavior if you set \"stash.index\".\n>       \n>      -    A few of the relevant tests check the restoration of <pathspec>s; with\n>      -    the aforementioned breaking changes, things get more interesting. In\n>      -    particular, if we \"git stash push -- foo\" but have \"bar\" in the index,\n>      -    then when applying the stash we get a conflict: \"bar\" was not removed\n>      -    from the index by the stash, but it was included in the recorded index\n>      -    in the stash. In those cases, apply the stash with \"--no-index\" (which\n>      -    would be the required user behavior).\n>      +    [1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n>      +    [2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n>       \n>      -    Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n>      + ## Documentation/config/stash.adoc ##\n>      +@@\n>      ++stash.index::\n>      ++\tIf this is set to true, `git stash apply` and `git stash pop` will\n>      ++\tbehave as if `--index` was supplied. Defaults to false. See the\n>      ++\tdescriptions in linkgit:git-stash[1].\n>      ++\n>      + stash.showIncludeUntracked::\n>      + \tIf this is set to true, the `git stash show` command will show\n>      + \tthe untracked files of a stash entry.  Defaults to false. See\n>       \n>      -\n>      - ## Notes ##\n>      -    It looks like the pathspec filtering is not applied to the stashed\n>      -    index; should it be?\n>      + ## builtin/stash.c ##\n>      +@@ builtin/stash.c: static struct strbuf stash_index_path = STRBUF_INIT;\n>      + static int show_stat = 1;\n>      + static int show_patch;\n>      + static int show_include_untracked;\n>      ++static int use_index;\n>      +\n>      + /*\n>      +  * w_commit is set to the commit containing the working tree\n>      +@@ builtin/stash.c: static int apply_stash(int argc, const char **argv, const char *prefix,\n>      + {\n>      + \tint ret = -1;\n>      + \tint quiet = 0;\n>      +-\tint index = 0;\n>      ++\tint index = use_index;\n>      + \tstruct stash_info info = STASH_INFO_INIT;\n>      + \tstruct option options[] = {\n>      + \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n>      +@@ builtin/stash.c: static int pop_stash(int argc, const char **argv, const char *prefix,\n>      + \t\t     struct repository *repo UNUSED)\n>      + {\n>      + \tint ret = -1;\n>      +-\tint index = 0;\n>      ++\tint index = use_index;\n>      + \tint quiet = 0;\n>      + \tstruct stash_info info = STASH_INFO_INIT;\n>      + \tstruct option options[] = {\n>      +@@ builtin/stash.c: static int git_stash_config(const char *var, const char *value,\n>      + \t\tshow_include_untracked = git_config_bool(var, value);\n>      + \t\treturn 0;\n>      + \t}\n>      ++\tif (!strcmp(var, \"stash.index\")) {\n>      ++\t\tuse_index = git_config_bool(var, value);\n>      ++\t\treturn 0;\n>      ++\t}\n>      + \treturn git_diff_basic_config(var, value, ctx, cb);\n>      + }\n>      +\n>       \n>        ## t/t3903-stash.sh ##\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_cmp expect file\n>      - '\n>      -\n>      --test_expect_success 'apply stashed changes' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'apply stashed changes' '\n>      - \tgit reset --hard &&\n>      - \techo 5 >other-file &&\n>      - \tgit add other-file &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest 1 = $(git show HEAD:file)\n>        '\n>        \n>      -+test_expect_success WITH_BREAKING_CHANGES 'apply stashed changes' '\n>      -+\tgit reset --hard &&\n>      ++test_expect_success 'apply stashed changes with stash.index' '\n>      ++\ttest_config stash.index true &&\n>      ++\tgit reset --hard HEAD^ &&\n>       +\techo 5 >other-file &&\n>       +\tgit add other-file &&\n>       +\ttest_tick &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>        test_expect_success 'apply stashed changes (including index)' '\n>        \tgit reset --hard HEAD^ &&\n>        \techo 6 >other-file &&\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_must_fail git stash drop --foo\n>      - '\n>      -\n>      --test_expect_success 'drop top stash' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'drop top stash' '\n>      - \tgit reset --hard &&\n>      - \tgit stash list >expected &&\n>      - \techo 7 >file &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest 1 = $(git show HEAD:file)\n>        '\n>        \n>      --test_expect_success 'drop middle stash' '\n>      -+test_expect_success WITH_BREAKING_CHANGES 'drop top stash' '\n>      ++test_expect_success 'drop top stash with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\tgit reset --hard &&\n>       +\tgit stash list >expected &&\n>       +\techo 7 >file &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>       +\ttest 1 = $(git show HEAD:file)\n>       +'\n>       +\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash' '\n>      + test_expect_success 'drop middle stash' '\n>        \tgit reset --hard &&\n>        \techo 8 >file &&\n>      - \tgit stash &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest 1 = $(git show HEAD:file)\n>        '\n>        \n>      --test_expect_success 'drop middle stash by index' '\n>      -+test_expect_success WITH_BREAKING_CHANGES 'drop middle stash' '\n>      ++test_expect_success 'drop middle stash with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\tgit reset --hard &&\n>       +\techo 8 >file &&\n>       +\tgit stash &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>       +\ttest 1 = $(git show HEAD:file)\n>       +'\n>       +\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'drop middle stash by index' '\n>      + test_expect_success 'drop middle stash by index' '\n>        \tgit reset --hard &&\n>        \techo 8 >file &&\n>      - \tgit stash &&\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_cmp expect actual\n>      - '\n>      -\n>      --test_expect_success 'stash pop' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash pop' '\n>      - \tgit reset --hard &&\n>      - \tgit stash pop &&\n>      - \ttest 3 = $(cat file) &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest 0 = $(git stash list | wc -l)\n>        '\n>        \n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash pop' '\n>      ++test_expect_success 'stash pop with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\tgit reset --hard &&\n>      ++\tsetup_stash &&\n>       +\tgit stash pop &&\n>       +\ttest 3 = $(cat file) &&\n>       +\ttest 2 = $(git show :file) &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_must_be_empty output.out\n>        '\n>        \n>      --test_expect_success 'pop -q works and is quiet' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n>      - \tgit stash pop -q >output.out 2>&1 &&\n>      - \techo bar >expect &&\n>      - \tgit show :file >actual &&\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_must_be_empty output.out\n>      - '\n>      -\n>      -+test_expect_success WITH_BREAKING_CHANGES 'pop -q works and is quiet' '\n>      ++test_expect_success 'pop -q works and is quiet with stash.index' '\n>      ++\t# Added file, deleted file, modified file all staged for commit\n>      ++\techo foo >new-file &&\n>      ++\techo test >file &&\n>      ++\tgit add new-file file &&\n>      ++\tgit rm other-file &&\n>      ++\tgit stash &&\n>      ++\n>      ++\ttest_config stash.index true &&\n>       +\tgit stash pop -q >output.out 2>&1 &&\n>       +\techo test >expect &&\n>       +\tgit show :file >actual &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>        test_expect_success 'pop -q --index works and is quiet' '\n>        \techo foo >file &&\n>        \tgit add file &&\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_cmp expect actual\n>      - '\n>      -\n>      --test_expect_success 'stash -- <pathspec> stashes and restores the file' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n>      - \t>foo &&\n>      - \t>bar &&\n>      - \tgit add foo bar &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_path_is_file bar\n>        '\n>        \n>      --test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes and restores the file' '\n>      ++test_expect_success 'stash -- <pathspec> stashes and restores the file with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\t>foo &&\n>       +\t>bar &&\n>       +\tgit add foo bar &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>       +\ttest_path_is_file bar\n>       +'\n>       +\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n>      + test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n>        \tmkdir sub &&\n>        \t>foo &&\n>      - \t>bar &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_path_is_file bar\n>        '\n>        \n>      --test_expect_success 'stash with multiple pathspec arguments' '\n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash -- <pathspec> stashes in subdirectory' '\n>      ++test_expect_success 'stash -- <pathspec> stashes in subdirectory with stash.index' '\n>      ++\ttest_config stash.index true &&\n>      ++\trm -r sub &&\n>       +\tmkdir sub &&\n>       +\t>foo &&\n>       +\t>bar &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>       +\ttest_path_is_file bar\n>       +'\n>       +\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n>      + test_expect_success 'stash with multiple pathspec arguments' '\n>        \t>foo &&\n>        \t>bar &&\n>      - \t>extra &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_path_is_file extra\n>        '\n>        \n>      --test_expect_success 'stash with file including $IFS character' '\n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash with multiple pathspec arguments' '\n>      ++test_expect_success 'stash with multiple pathspec arguments with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\t>foo &&\n>       +\t>bar &&\n>       +\t>extra &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>       +\ttest_path_is_file extra\n>       +'\n>       +\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n>      + test_expect_success 'stash with file including $IFS character' '\n>        \t>\"foo bar\" &&\n>        \t>foo &&\n>      - \t>bar &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_path_is_file bar\n>        '\n>        \n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash with file including $IFS character' '\n>      ++test_expect_success 'stash with file including $IFS character with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\t>\"foo bar\" &&\n>       +\t>foo &&\n>       +\t>bar &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>        test_expect_success 'stash with pathspec matching multiple paths' '\n>        \techo original >file &&\n>        \techo original >other-file &&\n>      -@@ t/t3903-stash.sh: setup_stash()\n>      - \ttest_path_is_file untracked\n>      - '\n>      -\n>      --test_expect_success 'stash without verb with pathspec' '\n>      -+test_expect_success !WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n>      - \t>\"foo bar\" &&\n>      - \t>foo &&\n>      - \t>bar &&\n>       @@ t/t3903-stash.sh: setup_stash()\n>        \ttest_path_is_file bar\n>        '\n>        \n>      -+test_expect_success WITH_BREAKING_CHANGES 'stash without verb with pathspec' '\n>      ++test_expect_success 'stash without verb with pathspec with stash.index' '\n>      ++\ttest_config stash.index true &&\n>       +\t>\"foo bar\" &&\n>       +\t>foo &&\n>       +\t>bar &&\n>      @@ t/t3903-stash.sh: setup_stash()\n>        test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n>        \tgit reset &&\n>        \t>foo &&\n>      +\n>      + ## t/t3904-stash-patch.sh ##\n>      +@@\n>      + \tverify_state dir/foo work head\n>      + '\n>      +\n>      ++test_expect_success 'git stash -p with stash.index' '\n>      ++\ttest_config stash.index true &&\n>      ++\tset_state HEAD HEADfile_work HEADfile_index &&\n>      ++\tset_state dir/foo work index &&\n>      ++\ttest_write_lines y n y | git stash save -p &&\n>      ++\tgit reset --hard &&\n>      ++\tgit stash apply &&\n>      ++\tverify_state HEAD HEADfile_work HEADfile_index &&\n>      ++\tverify_state dir/foo head index\n>      ++'\n>      ++\n>      + test_expect_success 'git stash -p --no-keep-index' '\n>      + \tset_state HEAD HEADfile_work HEADfile_index &&\n>      + \tset_state bar bar_work bar_index &&\n>      +\n>      + ## t/t3905-stash-include-untracked.sh ##\n>      +@@\n>      +\n>      + . ./test-lib.sh\n>      +\n>      +-test_expect_success 'stash save --include-untracked some dirty working directory' '\n>      ++setup() {\n>      + \techo 1 >file &&\n>      + \tgit add file &&\n>      + \ttest_tick &&\n>      +@@\n>      + \tgit stash --include-untracked &&\n>      + \tgit diff-files --quiet &&\n>      + \tgit diff-index --cached --quiet HEAD\n>      ++}\n>      ++\n>      ++test_expect_success 'stash save --include-untracked some dirty working directory' '\n>      ++\tsetup\n>      + '\n>      +\n>      + test_expect_success 'stash save --include-untracked cleaned the untracked files' '\n>      +@@\n>      + \ttest_cmp untracked_expect untracked/untracked\n>      + '\n>      +\n>      ++test_expect_success 'stash pop after save --include-untracked leaves files untracked again with stash.index' '\n>      ++\tgit init repo &&\n>      ++\ttest_when_finished rm -r repo &&\n>      ++\t(\n>      ++\t\tcd repo &&\n>      ++\t\tgit config stash.index true &&\n>      ++\t\tsetup &&\n>      ++\t\tcat >expect <<-EOF &&\n>      ++\t\tMM file\n>      ++\t\t?? HEAD\n>      ++\t\t?? actual\n>      ++\t\t?? expect\n>      ++\t\t?? file2\n>      ++\t\t?? untracked/\n>      ++\t\tEOF\n>      ++\n>      ++\t\tgit stash pop &&\n>      ++\t\tgit status --porcelain >actual &&\n>      ++\t\ttest_cmp expect actual &&\n>      ++\t\techo 1 >expect_file2 &&\n>      ++\t\ttest_cmp expect_file2 file2 &&\n>      ++\t\techo untracked >untracked_expect &&\n>      ++\t\ttest_cmp untracked_expect untracked/untracked\n>      ++\t)\n>      ++'\n>      ++\n>      + test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n>      + \tgit clean --force --quiet -d\n>      + '\n>      +@@\n>      + \ttest_path_is_file bar\n>      + '\n>      +\n>      ++test_expect_success 'stash push with $IFS character with stash.index' '\n>      ++\ttest_config stash.index true &&\n>      ++\t>\"foo bar\" &&\n>      ++\t>foo &&\n>      ++\t>bar &&\n>      ++\tgit add foo* &&\n>      ++\tgit stash push --include-untracked -- \"foo b*\" &&\n>      ++\ttest_path_is_missing \"foo bar\" &&\n>      ++\ttest_path_is_file foo &&\n>      ++\ttest_path_is_file bar &&\n>      ++\tgit stash pop --no-index &&\n>      ++\ttest_path_is_file \"foo bar\" &&\n>      ++\ttest_path_is_file foo &&\n>      ++\ttest_path_is_file bar\n>      ++'\n>      ++\n>      + test_expect_success 'stash previously ignored file' '\n>      + \tcat >.gitignore <<-EOF &&\n>      + \tignored\n>   7:  4b92d47e16 <  -:  ---------- t3904: adjust stash -p test to account for index states with breaking changes\n>   8:  af14dee1be <  -:  ---------- t3905: adjust stash -u tests for breaking changes\n> \n> base-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n\n"},{"id":"526455","messageId":"xmqq8qieny0o.fsf@gitster.g","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"Re: [PATCH v2 0/4] Teach git-stash to use --index from config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-16T16:49:11Z","receivedAt":"2025-09-16T16:49:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"D. Ben Knoble\" <ben.knoble+github@gmail.com> writes:\n\n> With stash.index=true, git-stash(1) command now tries to reinstate the\n> index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n> common trap: \"git stash apply\" is not the reverse of \"git stash push\"\n> because carefully staged indices are lost and have to be manually\n> recreated. OTOH, this mode is not always desirable and may create more\n> conflicts when applying stashes. Use \"--no-index\" to disable this behavior.\n\nI've read the patches and I think I can agree with all the changes\nproposed.  We might eventually flip the default, but we do not truly\nknow until we unleash the version with choices to end users.\n\nI agree with Phillip's comment on minimum tests to ensure that the\ninteraction between configuration variables and the command option\nis sane.\n\nThanks.\n"},{"id":"526459","messageId":"CALnO6CCpcy2E4Q4u3+fVTtb3iNOCPUx2fdL+Lgd-+vWhptK2EQ@mail.gmail.com","threadId":"63436","inReplyTo":"4736597d-1144-43ce-8c09-e78e4563765b@gmail.com","subject":"Re: [PATCH v2 0/4] Teach git-stash to use --index from config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T17:06:29Z","receivedAt":"2025-09-16T17:06:44Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Tue, Sep 16, 2025 at 5:25 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Ben\n>\n> On 16/09/2025 01:37, D. Ben Knoble wrote:\n> >\n> > PS I've left some new t3903 tests as copy-pasta for now to get feedback\n> > on the rest of the series; there are bits of that file that could use an\n> > update to the modern style (e.g., not using \"test 1 = $(cat file)\").\n> > Since some new tests are substantially similar to old tests that use\n> > this style, such cleanup is /probably/ warranted but will delay eyeballs\n> > on the core of this series.\n>\n> In situations like this even if we don't convert the old tests, I think\n> it is worth using a modern style for the new ones. Some people argue\n> that the style within a file should be consistent but in practice that\n> means if someone decides to clean them up in the future they have even\n> more work to do and in the meantime we have a harder time debugging test\n> failures.\n\nAgreed—with Junio's \"mostly good\" downthread, I'll work on a v3 which\n_at least_ does the right thing for new tests. No promises on the old\nones…\n\n>\n> The cleanups in patches 1 and 2 look very welcome. I've left a comment\n> about the tests on patch 4.\n\nThanks, will look.\n"},{"id":"526460","messageId":"CALnO6CByUNHWFRYBSOpP-uD8moBrm48UW7k0MaGTUtL=bDL6GQ@mail.gmail.com","threadId":"63436","inReplyTo":"25836bc2-db3a-4761-b13d-c587728f4c3c@gmail.com","subject":"Re: [PATCH v2 4/4] stash: honor stash.index in apply, pop modes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-16T17:07:47Z","receivedAt":"2025-09-16T17:08:00Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Tue, Sep 16, 2025 at 5:18 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Ben\n>\n> On 16/09/2025 01:37, D. Ben Knoble wrote:\n> > With stash.index=true, git-stash(1) command now tries to reinstate the\n> > index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n> > common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n> > push\" because carefully staged indices are lost and have to be manually\n> > recreated. OTOH, this mode is not always desirable and may create more\n> > conflicts when applying stashes. As usual, \"--no-index\" will disable\n> > this behavior if you set \"stash.index\".\n>\n> I don't have a strong opinion either way on the new config setting but I\n> do think we should rationalize the new tests. Assuming we already have\n> good coverage for \"git stash pop --index\" then all we need to do is\n> check that \"git -c stash.index=true stash pop\", \"git -c stash.index=true\n> stash pop --no-index\" and \"git -c stash.index=false stash pop --index\".\n> We don't need an exhaustive list of tests that check the config setting\n> in scenarios like \"create twos stashes, drop the second one and apply\n> the first\". Tests like that add no new coverage for the changes in this\n> patch and slow the test suite down.\n\nAh, yep. That's much saner.\n\nI started from a \"git reset @{u}\" of the original series, so it was\n\"cheaper\" to keep that copy-pasta. But I much prefer your idea.\nThanks!\n"},{"id":"526908","messageId":"cover.1758505011.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1757982870.git.ben.knoble+github@gmail.com","subject":"[PATCH v3 0/4] Teach git-stash to use --index from config","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-22T01:39:02Z","receivedAt":"2025-09-22T01:39:19Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Changes from v2:\n- use \"rational\" tests (check interactions between CLI, config; drop\n  duplicate tests) thanks to Phillip's review\n\nChanges from v1:\n- configure --index via config\n- drop BreakingChanges related work\n\nWith stash.index=true, git-stash(1) command now tries to reinstate the\nindex by default in the \"apply\" and \"pop\" modes. Not doing so creates a\ncommon trap: \"git stash apply\" is not the reverse of \"git stash push\"\nbecause carefully staged indices are lost and have to be manually\nrecreated. OTOH, this mode is not always desirable and may create more\nconflicts when applying stashes. Use \"--no-index\" to disable this behavior.\n\nCf. <CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com>,\n<c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com>.\n\nPS I've left some new t3903 tests as copy-pasta for now to get feedback\non the rest of the series; there are bits of that file that could use an\nupdate to the modern style (e.g., not using \"test 1 = $(cat file)\").\nSince some new tests are substantially similar to old tests that use\nthis style, such cleanup is /probably/ warranted but will delay eyeballs\non the core of this series.\n\nPublished-as: https://github.com/benknoble/git/tree/stash-apply-index\nv1: https://lore.kernel.org/git/20250510183358.36806-1-ben.knoble+github@gmail.com/\nv2: https://lore.kernel.org/git/cover.1757982870.git.ben.knoble+github@gmail.com/\n\nD. Ben Knoble (4):\n  t3903: reduce dependencies on previous tests\n  t3905: remove unneeded blank line\n  stash: refactor private config globals\n  stash: honor stash.index in apply, pop modes\n\n Documentation/config/stash.adoc    |  5 ++++\n builtin/stash.c                    | 17 ++++++++-----\n t/t3903-stash.sh                   | 40 ++++++++++++++++++++++++++++++\n t/t3905-stash-include-untracked.sh |  1 -\n 4 files changed, 56 insertions(+), 7 deletions(-)\n\nDiff-intervalle contre v2 :\n1:  1328eb8eac = 1:  1328eb8eac t3903: reduce dependencies on previous tests\n2:  8ac06ad62d = 2:  8ac06ad62d t3905: remove unneeded blank line\n3:  bf0a561ce3 = 3:  bf0a561ce3 stash: refactor private config globals\n4:  585e124467 ! 4:  8e6cafbf3a stash: honor stash.index in apply, pop modes\n    @@ builtin/stash.c: static int git_stash_config(const char *var, const char *value,\n     \n      ## t/t3903-stash.sh ##\n     @@ t/t3903-stash.sh: setup_stash()\n    - \ttest 1 = $(git show HEAD:file)\n    + \t)\n      '\n      \n    -+test_expect_success 'apply stashed changes with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\tgit reset --hard HEAD^ &&\n    -+\techo 5 >other-file &&\n    -+\tgit add other-file &&\n    -+\ttest_tick &&\n    -+\tgit commit -m other-file &&\n    -+\tgit stash apply &&\n    -+\ttest 3 = $(cat file) &&\n    -+\ttest 2 = $(git show :file) &&\n    -+\ttest 1 = $(git show HEAD:file)\n    -+'\n    -+\n    - test_expect_success 'apply stashed changes (including index)' '\n    - \tgit reset --hard HEAD^ &&\n    - \techo 6 >other-file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest 1 = $(git show HEAD:file)\n    - '\n    - \n    -+test_expect_success 'drop top stash with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\tgit reset --hard &&\n    -+\tgit stash list >expected &&\n    -+\techo 7 >file &&\n    -+\tgit stash &&\n    -+\tgit stash drop &&\n    -+\tgit stash list >actual &&\n    -+\ttest_cmp expected actual &&\n    -+\tgit stash apply &&\n    -+\ttest 3 = $(cat file) &&\n    -+\ttest 2 = $(git show :file) &&\n    -+\ttest 1 = $(git show HEAD:file)\n    -+'\n    -+\n    - test_expect_success 'drop middle stash' '\n    - \tgit reset --hard &&\n    - \techo 8 >file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest 1 = $(git show HEAD:file)\n    - '\n    - \n    -+test_expect_success 'drop middle stash with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\tgit reset --hard &&\n    -+\techo 8 >file &&\n    -+\tgit stash &&\n    -+\techo 9 >file &&\n    -+\tgit stash &&\n    -+\tgit stash drop stash@{1} &&\n    -+\ttest 2 = $(git stash list | wc -l) &&\n    -+\tgit stash apply &&\n    -+\ttest 9 = $(cat file) &&\n    -+\ttest 1 = $(git show :file) &&\n    -+\ttest 1 = $(git show HEAD:file) &&\n    -+\tgit reset --hard &&\n    -+\tgit stash drop &&\n    -+\tgit stash apply &&\n    -+\ttest 3 = $(cat file) &&\n    -+\ttest 2 = $(git show :file) &&\n    -+\ttest 1 = $(git show HEAD:file)\n    -+'\n    -+\n    - test_expect_success 'drop middle stash by index' '\n    - \tgit reset --hard &&\n    - \techo 8 >file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest 0 = $(git stash list | wc -l)\n    - '\n    - \n    -+test_expect_success 'stash pop with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\tgit reset --hard &&\n    -+\tsetup_stash &&\n    -+\tgit stash pop &&\n    -+\ttest 3 = $(cat file) &&\n    -+\ttest 2 = $(git show :file) &&\n    -+\ttest 1 = $(git show HEAD:file) &&\n    -+\ttest 0 = $(git stash list | wc -l)\n    -+'\n    -+\n    - cat >expect <<EOF\n    - diff --git a/file2 b/file2\n    - new file mode 100644\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_must_be_empty output.out\n    - '\n    - \n    -+test_expect_success 'pop -q works and is quiet with stash.index' '\n    -+\t# Added file, deleted file, modified file all staged for commit\n    -+\techo foo >new-file &&\n    -+\techo test >file &&\n    -+\tgit add new-file file &&\n    -+\tgit rm other-file &&\n    ++test_expect_success 'stash.index=true implies --index' '\n    ++\t# setup for a few related tests\n    ++\ttest_commit file base &&\n    ++\techo index >file &&\n    ++\tgit add file &&\n    ++\techo working >file &&\n     +\tgit stash &&\n     +\n    -+\ttest_config stash.index true &&\n    -+\tgit stash pop -q >output.out 2>&1 &&\n    -+\techo test >expect &&\n    -+\tgit show :file >actual &&\n    ++\ttest_when_finished \"git reset --hard\" &&\n    ++\tgit -c stash.index=true stash apply &&\n    ++\techo index >expect &&\n    ++\tgit show :0:file >actual &&\n     +\ttest_cmp expect actual &&\n    -+\ttest_must_be_empty output.out\n    ++\techo working >expect &&\n    ++\ttest_cmp expect file\n     +'\n     +\n    - test_expect_success 'pop -q --index works and is quiet' '\n    - \techo foo >file &&\n    - \tgit add file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file bar\n    - '\n    - \n    -+test_expect_success 'stash -- <pathspec> stashes and restores the file with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\tgit add foo bar &&\n    -+\tgit stash push -- foo &&\n    -+\ttest_path_is_file bar &&\n    -+\ttest_path_is_missing foo &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar\n    ++test_expect_success 'stash.index=true overridden by --no-index' '\n    ++\ttest_when_finished \"git reset --hard\" &&\n    ++\tgit -c stash.index=true stash apply --no-index &&\n    ++\techo base >expect &&\n    ++\tgit show :0:file >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\techo working >expect &&\n    ++\ttest_cmp expect file\n     +'\n     +\n    - test_expect_success 'stash -- <pathspec> stashes in subdirectory' '\n    - \tmkdir sub &&\n    - \t>foo &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file bar\n    - '\n    - \n    -+test_expect_success 'stash -- <pathspec> stashes in subdirectory with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\trm -r sub &&\n    -+\tmkdir sub &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\tgit add foo bar &&\n    -+\t(\n    -+\t\tcd sub &&\n    -+\t\tgit stash push -- ../foo\n    -+\t) &&\n    -+\ttest_path_is_file bar &&\n    -+\ttest_path_is_missing foo &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar\n    ++test_expect_success 'stash.index=false overridden by --index' '\n    ++\ttest_when_finished \"git reset --hard\" &&\n    ++\tgit -c stash.index=false stash apply --index &&\n    ++\techo index >expect &&\n    ++\tgit show :0:file >actual &&\n    ++\ttest_cmp expect actual &&\n    ++\techo working >expect &&\n    ++\ttest_cmp expect file\n     +'\n     +\n    - test_expect_success 'stash with multiple pathspec arguments' '\n    - \t>foo &&\n    - \t>bar &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file extra\n    - '\n    - \n    -+test_expect_success 'stash with multiple pathspec arguments with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\t>extra &&\n    -+\tgit add foo bar extra &&\n    -+\tgit stash push -- foo bar &&\n    -+\ttest_path_is_missing bar &&\n    -+\ttest_path_is_missing foo &&\n    -+\ttest_path_is_file extra &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar &&\n    -+\ttest_path_is_file extra\n    -+'\n    -+\n    - test_expect_success 'stash with file including $IFS character' '\n    - \t>\"foo bar\" &&\n    - \t>foo &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file bar\n    - '\n    - \n    -+test_expect_success 'stash with file including $IFS character with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\t>\"foo bar\" &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\tgit add foo* &&\n    -+\tgit stash push -- \"foo b*\" &&\n    -+\ttest_path_is_missing \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar\n    -+'\n    -+\n    - test_expect_success 'stash with pathspec matching multiple paths' '\n    - \techo original >file &&\n    - \techo original >other-file &&\n    -@@ t/t3903-stash.sh: setup_stash()\n    - \ttest_path_is_file bar\n    - '\n    - \n    -+test_expect_success 'stash without verb with pathspec with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\t>\"foo bar\" &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\tgit add foo* &&\n    -+\tgit stash -- \"foo b*\" &&\n    -+\ttest_path_is_missing \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar\n    -+'\n    -+\n    - test_expect_success 'stash -k -- <pathspec> leaves unstaged files intact' '\n    - \tgit reset &&\n    - \t>foo &&\n    -\n    - ## t/t3904-stash-patch.sh ##\n    -@@\n    - \tverify_state dir/foo work head\n    - '\n    - \n    -+test_expect_success 'git stash -p with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\tset_state HEAD HEADfile_work HEADfile_index &&\n    -+\tset_state dir/foo work index &&\n    -+\ttest_write_lines y n y | git stash save -p &&\n    -+\tgit reset --hard &&\n    -+\tgit stash apply &&\n    -+\tverify_state HEAD HEADfile_work HEADfile_index &&\n    -+\tverify_state dir/foo head index\n    -+'\n    -+\n    - test_expect_success 'git stash -p --no-keep-index' '\n    - \tset_state HEAD HEADfile_work HEADfile_index &&\n    - \tset_state bar bar_work bar_index &&\n    -\n    - ## t/t3905-stash-include-untracked.sh ##\n    -@@\n    - \n    - . ./test-lib.sh\n    - \n    --test_expect_success 'stash save --include-untracked some dirty working directory' '\n    -+setup() {\n    - \techo 1 >file &&\n    - \tgit add file &&\n    - \ttest_tick &&\n    -@@\n    - \tgit stash --include-untracked &&\n    - \tgit diff-files --quiet &&\n    - \tgit diff-index --cached --quiet HEAD\n    -+}\n    -+\n    -+test_expect_success 'stash save --include-untracked some dirty working directory' '\n    -+\tsetup\n    - '\n    - \n    - test_expect_success 'stash save --include-untracked cleaned the untracked files' '\n    -@@\n    - \ttest_cmp untracked_expect untracked/untracked\n    - '\n    - \n    -+test_expect_success 'stash pop after save --include-untracked leaves files untracked again with stash.index' '\n    -+\tgit init repo &&\n    -+\ttest_when_finished rm -r repo &&\n    -+\t(\n    -+\t\tcd repo &&\n    -+\t\tgit config stash.index true &&\n    -+\t\tsetup &&\n    -+\t\tcat >expect <<-EOF &&\n    -+\t\tMM file\n    -+\t\t?? HEAD\n    -+\t\t?? actual\n    -+\t\t?? expect\n    -+\t\t?? file2\n    -+\t\t?? untracked/\n    -+\t\tEOF\n    -+\n    -+\t\tgit stash pop &&\n    -+\t\tgit status --porcelain >actual &&\n    -+\t\ttest_cmp expect actual &&\n    -+\t\techo 1 >expect_file2 &&\n    -+\t\ttest_cmp expect_file2 file2 &&\n    -+\t\techo untracked >untracked_expect &&\n    -+\t\ttest_cmp untracked_expect untracked/untracked\n    -+\t)\n    -+'\n    -+\n    - test_expect_success 'clean up untracked/ directory to prepare for next tests' '\n    - \tgit clean --force --quiet -d\n    - '\n    -@@\n    - \ttest_path_is_file bar\n    - '\n    - \n    -+test_expect_success 'stash push with $IFS character with stash.index' '\n    -+\ttest_config stash.index true &&\n    -+\t>\"foo bar\" &&\n    -+\t>foo &&\n    -+\t>bar &&\n    -+\tgit add foo* &&\n    -+\tgit stash push --include-untracked -- \"foo b*\" &&\n    -+\ttest_path_is_missing \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar &&\n    -+\tgit stash pop --no-index &&\n    -+\ttest_path_is_file \"foo bar\" &&\n    -+\ttest_path_is_file foo &&\n    -+\ttest_path_is_file bar\n    -+'\n    -+\n    - test_expect_success 'stash previously ignored file' '\n    - \tcat >.gitignore <<-EOF &&\n    - \tignored\n    + test_done\n\nbase-commit: 1ee85f0e215f22b0878d0ad4b2445d12bbb63887\n-- \n2.48.1\n\n"},{"id":"526909","messageId":"1328eb8eac65ec7bbf1f3cb257d7221a372c45c3.1758505011.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1758505011.git.ben.knoble+github@gmail.com","subject":"[PATCH v3 1/4] t3903: reduce dependencies on previous tests","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-22T01:39:03Z","receivedAt":"2025-09-22T01:39:20Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"Skipping previous tests to work through only failing tests with\narguments like --run=4,122- causes some tests to fail because subdir\ndoesn't exist yet (it is created by a previous test; typically\n\"unstashing in a subdirectory\"). Create it on demand for tests that need\nit, but don't fail (-p) if the directory already exists.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3903-stash.sh | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 74666ff3e4..b8936a653b 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -895,6 +895,7 @@ setup_stash()\n \n test_expect_success 'apply: show same status as git status (relative to ./)' '\n \tgit stash clear &&\n+\tmkdir -p subdir &&\n \techo 1 >subdir/subfile1 &&\n \techo 2 >subdir/subfile2 &&\n \tgit add subdir/subfile1 &&\n@@ -1327,6 +1328,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> leaves untracked files in subdir intact' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked1 &&\n \t>subdir/tracked2 &&\n@@ -1343,6 +1345,7 @@ setup_stash()\n \n test_expect_success 'stash -- <subdir> works with binary files' '\n \tgit reset &&\n+\tmkdir -p subdir &&\n \t>subdir/untracked &&\n \t>subdir/tracked &&\n \tcp \"$TEST_DIRECTORY\"/test-binary-1.png subdir/tracked-binary &&\n-- \n2.48.1\n\n"},{"id":"526910","messageId":"8ac06ad62df581bb84ecdca0b0144c218daa0733.1758505011.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1758505011.git.ben.knoble+github@gmail.com","subject":"[PATCH v3 2/4] t3905: remove unneeded blank line","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-22T01:39:04Z","receivedAt":"2025-09-22T01:39:22Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"This is leftover from 787513027a (stash: Add --include-untracked option\nto stash and remove all untracked files, 2011-06-24) when it was\nconverted in bbaa45c3aa (t3905: move all commands into test cases,\n2021-02-08).\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n t/t3905-stash-include-untracked.sh | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh\nindex 1289ae3e07..7704709054 100755\n--- a/t/t3905-stash-include-untracked.sh\n+++ b/t/t3905-stash-include-untracked.sh\n@@ -87,7 +87,6 @@\n \n test_expect_success 'clean up untracked/untracked file to prepare for next tests' '\n \tgit clean --force --quiet\n-\n '\n \n test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '\n-- \n2.48.1\n\n"},{"id":"526911","messageId":"bf0a561ce36afe14b6bc03bf851d19b30ef491ad.1758505011.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1758505011.git.ben.knoble+github@gmail.com","subject":"[PATCH v3 3/4] stash: refactor private config globals","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-22T01:39:05Z","receivedAt":"2025-09-22T01:39:23Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"A subsequent commit will access a new config variable in the stash\nsubcommand implementations, which requires the variables to be declared\nbefore the relevant functions. Prep with a pure refactoring change to\nconsolidate config-related globals with the rest of the globals.\n\nBest-viewed-with: --color-moved\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n builtin/stash.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex cfbd92852a..d9b478d1d1 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -127,6 +127,10 @@ static const char * const git_stash_save_usage[] = {\n static const char ref_stash[] = \"refs/stash\";\n static struct strbuf stash_index_path = STRBUF_INIT;\n \n+static int show_stat = 1;\n+static int show_patch;\n+static int show_include_untracked;\n+\n /*\n  * w_commit is set to the commit containing the working tree\n  * b_commit is set to the base commit\n@@ -845,10 +849,6 @@ static int list_stash(int argc, const char **argv, const char *prefix,\n \treturn run_command(&cp);\n }\n \n-static int show_stat = 1;\n-static int show_patch;\n-static int show_include_untracked;\n-\n static int git_stash_config(const char *var, const char *value,\n \t\t\t    const struct config_context *ctx, void *cb)\n {\n-- \n2.48.1\n\n"},{"id":"526912","messageId":"8e6cafbf3a01b968663b65559acf3df615eecbad.1758505011.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"cover.1758505011.git.ben.knoble+github@gmail.com","subject":"[PATCH v3 4/4] stash: honor stash.index in apply, pop modes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-22T01:39:06Z","receivedAt":"2025-09-22T01:39:24Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"With stash.index=true, git-stash(1) command now tries to reinstate the\nindex by default in the \"apply\" and \"pop\" modes. Not doing so creates a\ncommon trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\npush\" because carefully staged indices are lost and have to be manually\nrecreated. OTOH, this mode is not always desirable and may create more\nconflicts when applying stashes. As usual, \"--no-index\" will disable\nthis behavior if you set \"stash.index\".\n\n[1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n[2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n Documentation/config/stash.adoc |  5 +++++\n builtin/stash.c                 |  9 ++++++--\n t/t3903-stash.sh                | 37 +++++++++++++++++++++++++++++++++\n 3 files changed, 49 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\nindex ec1edaeba6..e556105a15 100644\n--- a/Documentation/config/stash.adoc\n+++ b/Documentation/config/stash.adoc\n@@ -1,3 +1,8 @@\n+stash.index::\n+\tIf this is set to true, `git stash apply` and `git stash pop` will\n+\tbehave as if `--index` was supplied. Defaults to false. See the\n+\tdescriptions in linkgit:git-stash[1].\n+\n stash.showIncludeUntracked::\n \tIf this is set to true, the `git stash show` command will show\n \tthe untracked files of a stash entry.  Defaults to false. See\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex d9b478d1d1..8a0eef3c70 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -130,6 +130,7 @@ static struct strbuf stash_index_path = STRBUF_INIT;\n static int show_stat = 1;\n static int show_patch;\n static int show_include_untracked;\n+static int use_index;\n \n /*\n  * w_commit is set to the commit containing the working tree\n@@ -662,7 +663,7 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n {\n \tint ret = -1;\n \tint quiet = 0;\n-\tint index = 0;\n+\tint index = use_index;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n@@ -759,7 +760,7 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n \t\t     struct repository *repo UNUSED)\n {\n \tint ret = -1;\n-\tint index = 0;\n+\tint index = use_index;\n \tint quiet = 0;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct option options[] = {\n@@ -864,6 +865,10 @@ static int git_stash_config(const char *var, const char *value,\n \t\tshow_include_untracked = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"stash.index\")) {\n+\t\tuse_index = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n \treturn git_diff_basic_config(var, value, ctx, cb);\n }\n \ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex b8936a653b..d6127173b1 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -1595,4 +1595,41 @@ setup_stash()\n \t)\n '\n \n+test_expect_success 'stash.index=true implies --index' '\n+\t# setup for a few related tests\n+\ttest_commit file base &&\n+\techo index >file &&\n+\tgit add file &&\n+\techo working >file &&\n+\tgit stash &&\n+\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit -c stash.index=true stash apply &&\n+\techo index >expect &&\n+\tgit show :0:file >actual &&\n+\ttest_cmp expect actual &&\n+\techo working >expect &&\n+\ttest_cmp expect file\n+'\n+\n+test_expect_success 'stash.index=true overridden by --no-index' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit -c stash.index=true stash apply --no-index &&\n+\techo base >expect &&\n+\tgit show :0:file >actual &&\n+\ttest_cmp expect actual &&\n+\techo working >expect &&\n+\ttest_cmp expect file\n+'\n+\n+test_expect_success 'stash.index=false overridden by --index' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\tgit -c stash.index=false stash apply --index &&\n+\techo index >expect &&\n+\tgit show :0:file >actual &&\n+\ttest_cmp expect actual &&\n+\techo working >expect &&\n+\ttest_cmp expect file\n+'\n+\n test_done\n-- \n2.48.1\n\n"},{"id":"526938","messageId":"d7721018-3b2f-4764-b33d-4fc6bdc034a1@gmail.com","threadId":"63436","inReplyTo":"8e6cafbf3a01b968663b65559acf3df615eecbad.1758505011.git.ben.knoble+github@gmail.com","subject":"Re: [PATCH v3 4/4] stash: honor stash.index in apply, pop modes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-09-22T14:11:10Z","receivedAt":"2025-09-22T14:11:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Ben\n\nOn 22/09/2025 02:39, D. Ben Knoble wrote:\n> With stash.index=true, git-stash(1) command now tries to reinstate the\n> index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n> common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n> push\" because carefully staged indices are lost and have to be manually\n> recreated. OTOH, this mode is not always desirable and may create more\n> conflicts when applying stashes. As usual, \"--no-index\" will disable\n> this behavior if you set \"stash.index\".\n\nThanks for updating the tests, they look good. As I said before I don't \nhave a strong opinion about this change but I certainly don't object to \nit. I think this change will also affect the behavior of \"git \nmerge/pull/rebase --autostash\" which we should maybe call out in the \ncommit message. I don't think that change in behavior is a problem as it \nis probably what the user would expect when they set this config.\n\nThanks\n\nPhillip\n\n> [1]: https://lore.kernel.org/git/CAPx1GvcxyDDQmCssMjEnt6JoV6qPc5ZUpgPLX3mpUC_4PNYA1w@mail.gmail.com/\n> [2]: https://lore.kernel.org/git/c5a811ac-8cd3-c389-ac6d-29020a648c87@gmail.com/\n> \n> Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n> ---\n>   Documentation/config/stash.adoc |  5 +++++\n>   builtin/stash.c                 |  9 ++++++--\n>   t/t3903-stash.sh                | 37 +++++++++++++++++++++++++++++++++\n>   3 files changed, 49 insertions(+), 2 deletions(-)\n> \n> diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\n> index ec1edaeba6..e556105a15 100644\n> --- a/Documentation/config/stash.adoc\n> +++ b/Documentation/config/stash.adoc\n> @@ -1,3 +1,8 @@\n> +stash.index::\n> +\tIf this is set to true, `git stash apply` and `git stash pop` will\n> +\tbehave as if `--index` was supplied. Defaults to false. See the\n> +\tdescriptions in linkgit:git-stash[1].\n> +\n>   stash.showIncludeUntracked::\n>   \tIf this is set to true, the `git stash show` command will show\n>   \tthe untracked files of a stash entry.  Defaults to false. See\n> diff --git a/builtin/stash.c b/builtin/stash.c\n> index d9b478d1d1..8a0eef3c70 100644\n> --- a/builtin/stash.c\n> +++ b/builtin/stash.c\n> @@ -130,6 +130,7 @@ static struct strbuf stash_index_path = STRBUF_INIT;\n>   static int show_stat = 1;\n>   static int show_patch;\n>   static int show_include_untracked;\n> +static int use_index;\n>   \n>   /*\n>    * w_commit is set to the commit containing the working tree\n> @@ -662,7 +663,7 @@ static int apply_stash(int argc, const char **argv, const char *prefix,\n>   {\n>   \tint ret = -1;\n>   \tint quiet = 0;\n> -\tint index = 0;\n> +\tint index = use_index;\n>   \tstruct stash_info info = STASH_INFO_INIT;\n>   \tstruct option options[] = {\n>   \t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n> @@ -759,7 +760,7 @@ static int pop_stash(int argc, const char **argv, const char *prefix,\n>   \t\t     struct repository *repo UNUSED)\n>   {\n>   \tint ret = -1;\n> -\tint index = 0;\n> +\tint index = use_index;\n>   \tint quiet = 0;\n>   \tstruct stash_info info = STASH_INFO_INIT;\n>   \tstruct option options[] = {\n> @@ -864,6 +865,10 @@ static int git_stash_config(const char *var, const char *value,\n>   \t\tshow_include_untracked = git_config_bool(var, value);\n>   \t\treturn 0;\n>   \t}\n> +\tif (!strcmp(var, \"stash.index\")) {\n> +\t\tuse_index = git_config_bool(var, value);\n> +\t\treturn 0;\n> +\t}\n>   \treturn git_diff_basic_config(var, value, ctx, cb);\n>   }\n>   \n> diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\n> index b8936a653b..d6127173b1 100755\n> --- a/t/t3903-stash.sh\n> +++ b/t/t3903-stash.sh\n> @@ -1595,4 +1595,41 @@ setup_stash()\n>   \t)\n>   '\n>   \n> +test_expect_success 'stash.index=true implies --index' '\n> +\t# setup for a few related tests\n> +\ttest_commit file base &&\n> +\techo index >file &&\n> +\tgit add file &&\n> +\techo working >file &&\n> +\tgit stash &&\n> +\n> +\ttest_when_finished \"git reset --hard\" &&\n> +\tgit -c stash.index=true stash apply &&\n> +\techo index >expect &&\n> +\tgit show :0:file >actual &&\n> +\ttest_cmp expect actual &&\n> +\techo working >expect &&\n> +\ttest_cmp expect file\n> +'\n> +\n> +test_expect_success 'stash.index=true overridden by --no-index' '\n> +\ttest_when_finished \"git reset --hard\" &&\n> +\tgit -c stash.index=true stash apply --no-index &&\n> +\techo base >expect &&\n> +\tgit show :0:file >actual &&\n> +\ttest_cmp expect actual &&\n> +\techo working >expect &&\n> +\ttest_cmp expect file\n> +'\n> +\n> +test_expect_success 'stash.index=false overridden by --index' '\n> +\ttest_when_finished \"git reset --hard\" &&\n> +\tgit -c stash.index=false stash apply --index &&\n> +\techo index >expect &&\n> +\tgit show :0:file >actual &&\n> +\ttest_cmp expect actual &&\n> +\techo working >expect &&\n> +\ttest_cmp expect file\n> +'\n> +\n>   test_done\n\n"},{"id":"527258","messageId":"CALnO6CA9z39rgGd673p-ZMzMOBM_G37YPOs4ysNtPHGGCDVM-A@mail.gmail.com","threadId":"63436","inReplyTo":"d7721018-3b2f-4764-b33d-4fc6bdc034a1@gmail.com","subject":"Re: [PATCH v3 4/4] stash: honor stash.index in apply, pop modes","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-09-24T20:40:48Z","receivedAt":"2025-09-24T20:41:02Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Mon, Sep 22, 2025 at 10:11 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Ben\n>\n> On 22/09/2025 02:39, D. Ben Knoble wrote:\n> > With stash.index=true, git-stash(1) command now tries to reinstate the\n> > index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n> > common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n> > push\" because carefully staged indices are lost and have to be manually\n> > recreated. OTOH, this mode is not always desirable and may create more\n> > conflicts when applying stashes. As usual, \"--no-index\" will disable\n> > this behavior if you set \"stash.index\".\n>\n> Thanks for updating the tests, they look good. As I said before I don't\n> have a strong opinion about this change but I certainly don't object to\n> it. I think this change will also affect the behavior of \"git\n> merge/pull/rebase --autostash\" which we should maybe call out in the\n> commit message. I don't think that change in behavior is a problem as it\n> is probably what the user would expect when they set this config.\n\nAgreed, I hadn't considered that here. Should we also update the docs,\ndo you think?\n"},{"id":"527580","messageId":"b36d2dbf-7cf4-46cd-81bb-b502e0eed380@gmail.com","threadId":"63436","inReplyTo":"CALnO6CA9z39rgGd673p-ZMzMOBM_G37YPOs4ysNtPHGGCDVM-A@mail.gmail.com","subject":"Re: [PATCH v3 4/4] stash: honor stash.index in apply, pop modes","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-09-29T10:01:04Z","receivedAt":"2025-09-29T10:01:02Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 24/09/2025 21:40, D. Ben Knoble wrote:\n> On Mon, Sep 22, 2025 at 10:11 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Ben\n>>\n>> On 22/09/2025 02:39, D. Ben Knoble wrote:\n>>> With stash.index=true, git-stash(1) command now tries to reinstate the\n>>> index by default in the \"apply\" and \"pop\" modes. Not doing so creates a\n>>> common trap [1], [2]: \"git stash apply\" is not the reverse of \"git stash\n>>> push\" because carefully staged indices are lost and have to be manually\n>>> recreated. OTOH, this mode is not always desirable and may create more\n>>> conflicts when applying stashes. As usual, \"--no-index\" will disable\n>>> this behavior if you set \"stash.index\".\n>>\n>> Thanks for updating the tests, they look good. As I said before I don't\n>> have a strong opinion about this change but I certainly don't object to\n>> it. I think this change will also affect the behavior of \"git\n>> merge/pull/rebase --autostash\" which we should maybe call out in the\n>> commit message. I don't think that change in behavior is a problem as it\n>> is probably what the user would expect when they set this config.\n> \n> Agreed, I hadn't considered that here. Should we also update the docs,\n> do you think?\n\nGood idea, we should certainly mention it in the documentation for the \nnew config setting, I'm not sure whether it is worth mentioning it in \nthe \"--autostash\" documentation for the individual commands.\n\nThanks\n\nPhillip\n"},{"id":"527977","messageId":"d4a277b6b0695d86636562f4c07efae17f9249f9.1759755379.git.ben.knoble+github@gmail.com","threadId":"63436","inReplyTo":"b36d2dbf-7cf4-46cd-81bb-b502e0eed380@gmail.com","subject":"[PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-10-06T12:59:29Z","receivedAt":"2025-10-06T12:59:41Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"With 9842c0c749 (stash: honor stash.index in apply, pop modes,\n2025-09-21) merged in a5d4779e6e (Merge branch 'dk/stash-apply-index',\n2025-09-29), we did not advertise the connection between the new config\noption stash.index and the implicit use of git-stash via --autostash\n(which may also be configured). Do so.\n\nSigned-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n---\n\nThis builds on dk/stash-apply-index from gitster/git and is published at\nhttps://github.com/benknoble/git/tree/stash-apply-index-doc\n\n Documentation/config/stash.adoc | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\nindex e556105a15..fcb9a4a7a0 100644\n--- a/Documentation/config/stash.adoc\n+++ b/Documentation/config/stash.adoc\n@@ -2,6 +2,10 @@ stash.index::\n \tIf this is set to true, `git stash apply` and `git stash pop` will\n \tbehave as if `--index` was supplied. Defaults to false. See the\n \tdescriptions in linkgit:git-stash[1].\n++\n+This also affects invocations of linkgit:git-stash[1] via `--autostash` from\n+commands like linkgit:git-merge[1], linkgit:git-rebase[1], and\n+linkgit:git-pull[1].\n \n stash.showIncludeUntracked::\n \tIf this is set to true, the `git stash show` command will show\n\nbase-commit: 9842c0c7492d2858d64ef81128f7b1f0b38e326b\n-- \n2.48.1\n\n"},{"id":"528431","messageId":"e77d07d0-c26e-4d91-9777-ebaffffd764c@app.fastmail.com","threadId":"63436","inReplyTo":"d4a277b6b0695d86636562f4c07efae17f9249f9.1759755379.git.ben.knoble+github@gmail.com","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2025-10-09T22:54:36Z","receivedAt":"2025-10-09T22:55:05Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"This follow-up patch makes sense.\n\n• It reads like a logical continuation of the previous commit 9842c0c749\n• The log message is clear (and with no spelling mistakes)\n• The markup is correct (list continuation, links)\n• `make lint-docs` passes\n• `./ci/check-whitespace.sh @^` passes\n\nOn Mon, Oct 6, 2025, at 14:59, D. Ben Knoble wrote:\n> With 9842c0c749 (stash: honor stash.index in apply, pop modes,\n> 2025-09-21)\n\nCuriously, since this is also the base commit, referring to “the\nprevious commit” would also work if this patch is indeed applied on top\nof that one. But maybe that contextual reference is a bad idea?\n\n> merged in a5d4779e6e (Merge branch 'dk/stash-apply-index',\n> 2025-09-29),\n\nThis is over-specified IMO. Like mentioned this patch could be applied\non top of commit 9842c0c749. Then that merge commit will not be\nreachable from this resulting commit.\n\nI also don’t see the point of mentioning when things were merged in in\nthe commit message.\n\n> we did not advertise the connection between the new config\n> option stash.index and the implicit use of git-stash via --autostash\n> (which may also be configured). Do so.\n>\n> Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>\n> ---\n>\n> This builds on dk/stash-apply-index from gitster/git and is published at\n> https://github.com/benknoble/git/tree/stash-apply-index-doc\n>\n>  Documentation/config/stash.adoc | 4 ++++\n>  1 file changed, 4 insertions(+)\n>\n> diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\n> index e556105a15..fcb9a4a7a0 100644\n> --- a/Documentation/config/stash.adoc\n> +++ b/Documentation/config/stash.adoc\n> @@ -2,6 +2,10 @@ stash.index::\n>  \tIf this is set to true, `git stash apply` and `git stash pop` will\n>  \tbehave as if `--index` was supplied. Defaults to false. See the\n>  \tdescriptions in linkgit:git-stash[1].\n> ++\n> +This also affects invocations of linkgit:git-stash[1] via `--autostash` from\n> +commands like linkgit:git-merge[1], linkgit:git-rebase[1], and\n> +linkgit:git-pull[1].\n\nAccording to these\n\n• `git grep -- --autostash`\n• `git grep merge-options.adoc`\n\nThis text exhaustively covers all commands which have this option.\n\n... which might mean that “like” is an unneeded hedge? (it’s probably\nnot intended to be a hedge)\n\n>\n>  stash.showIncludeUntracked::\n>  \tIf this is set to true, the `git stash show` command will show\n>\n> base-commit: 9842c0c7492d2858d64ef81128f7b1f0b38e326b\n> --\n> 2.48.1\n"},{"id":"528574","messageId":"CALnO6CA0SEGrzsrS_yqZ3Ztep0Gi=zPFjjGzSW94EvDW8RZ2Bg@mail.gmail.com","threadId":"63436","inReplyTo":"e77d07d0-c26e-4d91-9777-ebaffffd764c@app.fastmail.com","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"D. Ben Knoble","fromEmail":"ben.knoble+github@gmail.com","sentAt":"2025-10-11T14:44:22Z","receivedAt":"2025-10-11T14:44:35Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Thu, Oct 9, 2025 at 6:55 PM Kristoffer Haugsbakk\n<code@khaugsbakk.name> wrote:\n>\n> This follow-up patch makes sense.\n>\n> • It reads like a logical continuation of the previous commit 9842c0c749\n> • The log message is clear (and with no spelling mistakes)\n> • The markup is correct (list continuation, links)\n> • `make lint-docs` passes\n> • `./ci/check-whitespace.sh @^` passes\n>\n> On Mon, Oct 6, 2025, at 14:59, D. Ben Knoble wrote:\n> > With 9842c0c749 (stash: honor stash.index in apply, pop modes,\n> > 2025-09-21)\n>\n> Curiously, since this is also the base commit, referring to “the\n> previous commit” would also work if this patch is indeed applied on top\n> of that one. But maybe that contextual reference is a bad idea?\n\nGenerally I think so, but that's just my preference. Once commits have\nstable reference points, I'd rather use that. But I'm not attached to\nthis one, so if we end up re-rolling, I can adjust either way.\n\n> > merged in a5d4779e6e (Merge branch 'dk/stash-apply-index',\n> > 2025-09-29),\n>\n> This is over-specified IMO. Like mentioned this patch could be applied\n> on top of commit 9842c0c749. Then that merge commit will not be\n> reachable from this resulting commit.\n>\n> I also don’t see the point of mentioning when things were merged in in\n> the commit message.\n\nIndeed. I think I wanted to call out the topic branch this was part\nof, especially since my understanding of the process of queueing\npatches on top of in-flight topics is shaky from parts of\nDocumentation/SubmittingPatches and …/howto/maintain-git:\n\n * A topic already in 'next' can get fixes while still in\n   'next'.  Such a topic will have many merges to 'next' (in\n   other words, \"git log --first-parent next\" will show many\n   \"Merge branch 'ai/topic' to next\" for the same topic.\n\nSo, idk. If the eventual merge to master won't have the prior \"topic\nmerge,\" it's probably important to omit (since the final topology of\nmaster won't contain the referenced commit). In this case, since that\nmerge _is_ part of master, it seemed worth explaining what topic we\nwere improving.\n\n> > diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc\n> > index e556105a15..fcb9a4a7a0 100644\n> > --- a/Documentation/config/stash.adoc\n> > +++ b/Documentation/config/stash.adoc\n> > @@ -2,6 +2,10 @@ stash.index::\n> >       If this is set to true, `git stash apply` and `git stash pop` will\n> >       behave as if `--index` was supplied. Defaults to false. See the\n> >       descriptions in linkgit:git-stash[1].\n> > ++\n> > +This also affects invocations of linkgit:git-stash[1] via `--autostash` from\n> > +commands like linkgit:git-merge[1], linkgit:git-rebase[1], and\n> > +linkgit:git-pull[1].\n>\n> According to these\n>\n> • `git grep -- --autostash`\n> • `git grep merge-options.adoc`\n>\n> This text exhaustively covers all commands which have this option.\n>\n> ... which might mean that “like” is an unneeded hedge? (it’s probably\n> not intended to be a hedge)\n\nIndeed. I'm not sure where autostash might be introduced in the future\n(git-history?), so it might be more \"hedge\" by way of \"listing\nexamples\" than necessary.\n\nI could go either way on all of this, so will defer to guidance from\nothers (but don't have the impetus to rewrite without a strong opinion\nat the moment).\n"},{"id":"528576","messageId":"xmqqy0ph5ov8.fsf@gitster.g","threadId":"63436","inReplyTo":"CALnO6CA0SEGrzsrS_yqZ3Ztep0Gi=zPFjjGzSW94EvDW8RZ2Bg@mail.gmail.com","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-10-11T17:28:59Z","receivedAt":"2025-10-11T17:29:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"D. Ben Knoble\" <ben.knoble+github@gmail.com> writes:\n\n> On Thu, Oct 9, 2025 at 6:55 PM Kristoffer Haugsbakk\n> <code@khaugsbakk.name> wrote:\n>>\n>> This follow-up patch makes sense.\n>>\n>> • It reads like a logical continuation of the previous commit 9842c0c749\n>> • The log message is clear (and with no spelling mistakes)\n>> • The markup is correct (list continuation, links)\n>> • `make lint-docs` passes\n>> • `./ci/check-whitespace.sh @^` passes\n>>\n>> On Mon, Oct 6, 2025, at 14:59, D. Ben Knoble wrote:\n>> > With 9842c0c749 (stash: honor stash.index in apply, pop modes,\n>> > 2025-09-21)\n>>\n>> Curiously, since this is also the base commit, referring to “the\n>> previous commit” would also work if this patch is indeed applied on top\n>> of that one. But maybe that contextual reference is a bad idea?\n> Generally I think so, but that's just my preference. Once commits have\n> stable reference points, I'd rather use that. But I'm not attached to\n> this one, so if we end up re-rolling, I can adjust either way.\n\nThat matches my preference, too.  Use of relative \"previous\" or\n\"next\", unless they are in the same series, can make things\nconfusing.\n\nFor example, you could say something silly like \"The test added in\nthe previous commit revealed age-old bug.  Here is a fix and more\ntest\", and the fix may be important enough that it wants to be\nforked from a maintenance track that is far older than the \"previous\"\ncommit.\n\n>> This is over-specified IMO. Like mentioned this patch could be applied\n>> on top of commit 9842c0c749. Then that merge commit will not be\n>> reachable from this resulting commit.\n>>\n>> I also don’t see the point of mentioning when things were merged in in\n>> the commit message.\n\nYeah, that is less useful to me (there is a tool, given a commit\nobject, to figure out at which merge it got merged to the mainline);\nI didn't think of a way the information can be useful to general\nreaders.  If the mainline merge was a release or more ago, then it\nmay make sense to say \"commit X, which appeared in version Y, was\nbroken in such and such way, and here is to fix its breakage\".\n\n>> >       If this is set to true, `git stash apply` and `git stash pop` will\n>> >       behave as if `--index` was supplied. Defaults to false. See the\n>> >       descriptions in linkgit:git-stash[1].\n>> > ++\n>> > +This also affects invocations of linkgit:git-stash[1] via `--autostash` from\n>> > +commands like linkgit:git-merge[1], linkgit:git-rebase[1], and\n>> > +linkgit:git-pull[1].\n>>\n>> According to these\n>>\n>> • `git grep -- --autostash`\n>> • `git grep merge-options.adoc`\n>>\n>> This text exhaustively covers all commands which have this option.\n>>\n>> ... which might mean that “like” is an unneeded hedge? (it’s probably\n>> not intended to be a hedge)\n\nYou have to devise a way to somehow ensure that a list, which\nhappens to be exhaustive right now, stays exhaustive, if you present\nit as authoritative exhaustive list to your readers.  But as long as\nthe list covers the use cases majority of readers would encounter\nevery day, it does not make the list any less useful even if it were\nnot exhausitive (and does not pretend to be).\n\nSo I prefer to keep the presented text than making it sound an\nauthoritative exhaustive list and add maintenance cost.\n\nThanks.\n"},{"id":"528587","messageId":"B78CD1B1-67C1-4EA1-94A7-13AD40C43585@gmail.com","threadId":"63436","inReplyTo":"xmqqy0ph5ov8.fsf@gitster.g","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-10-12T18:04:22Z","receivedAt":"2025-10-12T18:41:10Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"\n> \n> Le 11 oct. 2025 à 13:29, Junio C Hamano <gitster@pobox.com> a écrit :\n> \n> ﻿\"D. Ben Knoble\" <ben.knoble+github@gmail.com> writes:\n> \n>>> On Thu, Oct 9, 2025 at 6:55 PM Kristoffer Haugsbakk\n>>> <code@khaugsbakk.name> wrote:\n>>> \n>>> This is over-specified IMO. Like mentioned this patch could be applied\n>>> on top of commit 9842c0c749. Then that merge commit will not be\n>>> reachable from this resulting commit.\n>>> \n>>> I also don’t see the point of mentioning when things were merged in in\n>>> the commit message.\n> \n> Yeah, that is less useful to me (there is a tool, given a commit\n> object, to figure out at which merge it got merged to the mainline);\n> I didn't think of a way the information can be useful to general\n> readers.  If the mainline merge was a release or more ago, then it\n> may make sense to say \"commit X, which appeared in version Y, was\n> broken in such and such way, and here is to fix its breakage\"\n\nIt’s not clear to me if you’d like to see a v2 or not, but given you were already happy to merge in the latest what’s cooking, I don’t mind not sending one ;)"},{"id":"528618","messageId":"d4dc8042-b996-4889-88cb-f0862a12d09c@app.fastmail.com","threadId":"63436","inReplyTo":"B78CD1B1-67C1-4EA1-94A7-13AD40C43585@gmail.com","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"Kristoffer Haugsbakk","fromEmail":"code@khaugsbakk.name","sentAt":"2025-10-13T12:17:40Z","receivedAt":"2025-10-13T12:18:02Z","isPatch":true,"sender":{"key":"code@khaugsbakk.name","avatar":"https://avatars.githubusercontent.com/u/2229597?v=4"},"body":"On Sun, Oct 12, 2025, at 20:04, Ben Knoble wrote:\n>>>[snip]\n>>\n>> Yeah, that is less useful to me (there is a tool, given a commit\n>> object, to figure out at which merge it got merged to the mainline);\n>> I didn't think of a way the information can be useful to general\n>> readers.  If the mainline merge was a release or more ago, then it\n>> may make sense to say \"commit X, which appeared in version Y, was\n>> broken in such and such way, and here is to fix its breakage\"\n>\n> It’s not clear to me if you’d like to see a v2 or not, but given you\n> were already happy to merge in the latest what’s cooking, I don’t mind\n> not sending one ;)\n\nSorry.  I misread a What’s Cooking email[1] as asking why a topic hadn’t\nbeen picked up. But you were asking about sending another patch on top\nof something which was already in `next`.\n\nI wouldn’t have sent that email if I knew it was already in `next` (if I\nhad checked better).\n"},{"id":"528682","messageId":"CALnO6CDULtw1UmqHfiqLCH4v6U=MuiECHhYwz1-Omkh8x=9yFg@mail.gmail.com","threadId":"63436","inReplyTo":"d4dc8042-b996-4889-88cb-f0862a12d09c@app.fastmail.com","subject":"Re: [PATCH] doc: explain the impact of stash.index on --autostash options","fromName":"D. Ben Knoble","fromEmail":"ben.knoble@gmail.com","sentAt":"2025-10-14T02:18:50Z","receivedAt":"2025-10-14T02:19:03Z","isPatch":true,"sender":{"key":"ben.knoble@gmail.com","avatar":"https://avatars.githubusercontent.com/u/22802209?v=4"},"body":"On Mon, Oct 13, 2025 at 8:18 AM Kristoffer Haugsbakk\n<code@khaugsbakk.name> wrote:\n>\n> On Sun, Oct 12, 2025, at 20:04, Ben Knoble wrote:\n> >>>[snip]\n> >>\n> >> Yeah, that is less useful to me (there is a tool, given a commit\n> >> object, to figure out at which merge it got merged to the mainline);\n> >> I didn't think of a way the information can be useful to general\n> >> readers.  If the mainline merge was a release or more ago, then it\n> >> may make sense to say \"commit X, which appeared in version Y, was\n> >> broken in such and such way, and here is to fix its breakage\"\n> >\n> > It’s not clear to me if you’d like to see a v2 or not, but given you\n> > were already happy to merge in the latest what’s cooking, I don’t mind\n> > not sending one ;)\n>\n> Sorry.  I misread a What’s Cooking email[1] as asking why a topic hadn’t\n> been picked up. But you were asking about sending another patch on top\n> of something which was already in `next`.\n\nApologies. That's probably my poor wording.\n\n> I wouldn’t have sent that email if I knew it was already in `next` (if I\n> had checked better).\n\nAnything I can do to make it easier next time? Appreciate the review, btw :)\n\n-- \nD. Ben Knoble\n"}]}