{"thread":{"id":"66466","subject":"[PATCH 0/2] stash: stop checking for changes twice","startedAt":"2026-10-05T16:35:29Z","lastAt":"2026-10-05T16:35:31Z","messageCount":3,"participants":["Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"554193","messageId":"cover.1791218125.git.phillip.wood@dunelm.org.uk","threadId":"66466","inReplyTo":null,"subject":"[PATCH 0/2] stash: stop checking for changes twice","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-10-05T16:35:29Z","receivedAt":"2026-10-05T16:35:29Z","isPatch":true,"body":"\"git stash push\" and \"git stash create\" check if there are\nany unstaged or uncommitted changes at startup, and then again\nwhen they try to create the stash. This short series removes\nthat duplication of effort which I spotted while looking at\n<20260929074222.11942-1-kazumasa.shigeta@kanamei.com>.\n\nbase-commit: c46c1e37724f0478939de636ab8ea5a89086d532\nPublished-As: https://github.com/phillipwood/git/releases/tag/pw%2Fstash-optimize-check_changes-calls%2Fv1\nView-Changes-At: https://github.com/phillipwood/git/compare/c46c1e377...95b7d582a\nFetch-It-Via: git fetch https://github.com/phillipwood/git pw/stash-optimize-check_changes-calls/v1\n\n\nPhillip Wood (2):\n  stash create: remove duplicate changes detection\n  stash push: remove duplicate changes detection\n\n builtin/stash.c | 27 +++++++++++++++------------\n 1 file changed, 15 insertions(+), 12 deletions(-)\n\n-- \n2.56.0.134.g299a3c16181\n\n\n"},{"id":"554194","messageId":"1617d92942d283017272ca6f27f1254f8f9389b0.1791218125.git.phillip.wood@dunelm.org.uk","threadId":"66466","inReplyTo":"cover.1791218125.git.phillip.wood@dunelm.org.uk","subject":"[PATCH 1/2] stash create: remove duplicate changes detection","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-10-05T16:35:30Z","receivedAt":"2026-10-05T16:35:30Z","isPatch":true,"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nBefore it creates a stash, git checks if there are any unstaged,\nor uncommitted changes. If there isn't anything to stash it bails\nout. Since ef0f0b4509 (stash: optimize `get_untracked_files()`\nand `check_changes()`, 2019-02-25) \"git stash store\" has checked\nfor changes twice, once in create_stash() before we refresh the\nindex and then again in do_create_stash() after the index has been\nrefreshed. That commit claims it is an optimization but it is not\nclear what it is trying to optimize by checking for changes twice,\nespecially as checking for changes before refreshing the index is\nunreliable (the scripted version of \"git stash store\", called \"git\nupdate-index -q --refresh\" before looking for any changes).\n\nAvoid checking for changes twice by removing the call to\ncheck_changes_tracked_files() from store_stash() and restore the return\ncode handling in store_stash() that was removed by ef0f0b4509 so that\nwe continue to exit 0 when there are no changes to stash. In principle\nwe could remove the call to check_changes() from do_store_stash()\ninstead, but then we'd need to pass in the list of untracked files.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/stash.c | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex 7a9843413b1..9a5006e3d92 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -1655,8 +1655,6 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,\n \tstrbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' ');\n \n \tmemset(&ps, 0, sizeof(ps));\n-\tif (!check_changes_tracked_files(&ps))\n-\t\treturn 0;\n \n \tret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info,\n \t\t\t      NULL, 0);\n@@ -1665,7 +1663,11 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,\n \n \tfree_stash_info(&info);\n \tstrbuf_release(&stash_msg_buf);\n-\treturn ret;\n+\t/*\n+\t * ret is 1 if there were no changes. In this case, we should\n+\t * not error out.\n+\t */\n+\treturn ret < 0;\n }\n \n static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet,\n-- \n2.56.0.134.g299a3c16181\n\n\n"},{"id":"554195","messageId":"95b7d582a2f86a3db4a9e182e482e9eb904ddeee.1791218125.git.phillip.wood@dunelm.org.uk","threadId":"66466","inReplyTo":"cover.1791218125.git.phillip.wood@dunelm.org.uk","subject":"[PATCH 2/2] stash push: remove duplicate changes detection","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-10-05T16:35:31Z","receivedAt":"2026-10-05T16:35:31Z","isPatch":true,"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nBefore it creates a stash, git checks if there are any unstaged,\nor uncommitted changes. If there isn't anything to stash it bails\nout. \"git stash push\" checks for changes twice, once in do_push_stash()\nand then again in do_create_stash(). Avoid that by removing the call\nto check_changes() from do_push_stash() and checking the return value\nof do_create_stash() to see if there were any changes to stash. If\ncheck_changes() finds there are no changes do_create_stash() now\nreturns 2 rather than 1. This enables us to distinguish between there\nbeing no changes and there being nothing stashed so that \"git stash\npush --patch\" when nothing is select, and \"git stash push --staged\"\nwhen the index matches HEAD still exit 1 rather than 0.\n\nThere is still one small change in behavior as, if there is nothing\nto stash, we'll try now to create the reflog for stashes before we\nrealize that there is nothing to stash. I don't think that should\nmatter in practice.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/stash.c | 23 ++++++++++++-----------\n 1 file changed, 12 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex 9a5006e3d92..79fdfff09a2 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -1538,7 +1538,7 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b\n \t}\n \n \tif (!check_changes(ps, include_untracked, &untracked_files)) {\n-\t\tret = 1;\n+\t\tret = 2;\n \t\tgoto done;\n \t}\n \n@@ -1664,8 +1664,8 @@ static int create_stash(int argc, const char **argv, const char *prefix UNUSED,\n \tfree_stash_info(&info);\n \tstrbuf_release(&stash_msg_buf);\n \t/*\n-\t * ret is 1 if there were no changes. In this case, we should\n-\t * not error out.\n+\t * ret is greater than zero if there were no changes. In this case,\n+\t * we should not error out.\n \t */\n \treturn ret < 0;\n }\n@@ -1728,12 +1728,6 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q\n \t\tgoto done;\n \t}\n \n-\tif (!check_changes(ps, include_untracked, &untracked_files)) {\n-\t\tif (!quiet)\n-\t\t\tprintf_ln(_(\"No local changes to save\"));\n-\t\tgoto done;\n-\t}\n-\n \tif (!refs_reflog_exists(get_main_ref_store(the_repository), ref_stash) && do_clear_stash()) {\n \t\tret = -1;\n \t\tif (!quiet)\n@@ -1743,8 +1737,15 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q\n \n \tif (stash_msg)\n \t\tstrbuf_addstr(&stash_msg_buf, stash_msg);\n-\tif (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode,\n-\t\t\t    interactive_opts, only_staged, &info, &patch, quiet)) {\n+\tret =  do_create_stash(ps, &stash_msg_buf, include_untracked,\n+\t\t\t       patch_mode, interactive_opts, only_staged, &info,\n+\t\t\t       &patch, quiet);\n+\tif (ret == 2) {\n+\t\tif (!quiet)\n+\t\t\tprintf_ln(_(\"No local changes to save\"));\n+\t\tret = 0;\n+\t\tgoto done;\n+\t} else if (ret) {\n \t\tret = -1;\n \t\tgoto done;\n \t}\n-- \n2.56.0.134.g299a3c16181\n\n\n"}]}