{"thread":{"id":"65380","subject":"[PATCH/RFC] stash: add --include-untracked support to git stash create","startedAt":"2026-03-29T07:16:22Z","lastAt":"2026-04-11T07:17:39Z","messageCount":2,"participants":["Shabbir Bhojani via GitGitGadget","Shabbir Bhojani"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"540312","messageId":"pull.1892.git.1774768580147.gitgitgadget@gmail.com","threadId":"65380","inReplyTo":null,"subject":"[PATCH/RFC] stash: add --include-untracked support to git stash create","fromName":"Shabbir Bhojani via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-03-29T07:16:20Z","receivedAt":"2026-03-29T07:16:22Z","isPatch":true,"body":"From: SBhojani <shabbir.r.bhojani+git@gmail.com>\n\nThe `git stash create` command now supports the `--include-untracked` flag,\nallowing users to include untracked files in the stash entry. This brings\nparity with `git stash push`, which already supports this option.\n\nPreviously, `git stash create` would only stash tracked changes. With this\nchange, users can optionally include untracked files by specifying\n`--include-untracked`. The implementation involves parsing the new option\nin `create_stash` and passing it to `do_create_stash`, which handles the\ncreation of the stash entry.\n\nThe check for tracked changes is skipped when `--include-untracked` is\nset, as `do_create_stash` performs its own check internally. Test cases\nwere added to `t3903-stash.sh` to ensure the correct behavior, and the\ndocumentation was updated accordingly.\n\nSigned-off-by: SBhojani <shabbir.r.bhojani+git@gmail.com>\n---\n    stash: add --include-untracked support to git stash create\n    \n    This is a single-commit pull request, and the commit message already\n    describes the changes.\n    \n    I just want to add context for where I felt the need for this. While\n    working on a logical single commit task, my working tree is often in a\n    state where certain changes are staged and others are not. I use this\n    staging strategy as a conceptual model of which changes I intend to\n    mostly keep as they are and which I intend to change, rewrite, refactor,\n    discard, or not commit. Some of the changes in the latter category might\n    be new untracked files. Now, I often use (my git GUI tool's equivalent\n    of) git stash --include-untracked followed by git stash apply to take a\n    snapshot of these changes to be able to come back to the state if I mess\n    things up too much from that point on. Doing that results in the working\n    directory being cleaned momentarily and then being repopulated again. My\n    development tools often detect this as the files having been changed and\n    then prompt me to reload them or cause rebuilds and so on. git stash\n    store $(git stash create) has the nice feature that it doesn't touch the\n    working directory, but it was missing the ability to also stash\n    untracked files. This change fixes that.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1892%2FSBhojani%2Fstash-create-untracked-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1892/SBhojani/stash-create-untracked-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1892\n\n Documentation/git-stash.adoc |  9 +++++++--\n builtin/stash.c              | 25 +++++++++++++++++++------\n t/t3903-stash.sh             | 33 +++++++++++++++++++++++++++++++++\n 3 files changed, 59 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc\nindex 235d57ddd8..c379062110 100644\n--- a/Documentation/git-stash.adoc\n+++ b/Documentation/git-stash.adoc\n@@ -21,7 +21,7 @@ git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --\n git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n            [-u | --include-untracked] [-a | --all] [<message>]\n git stash clear\n-git stash create [<message>]\n+git stash create [-u | --include-untracked] [<message>]\n git stash store [(-m | --message) <message>] [-q | --quiet] <commit>\n git stash export (--print | --to-ref <ref>) [<stash>...]\n git stash import <commit>\n@@ -140,10 +140,12 @@ with no conflicts.\n `drop [-q | --quiet] [<stash>]`::\n \tRemove a single stash entry from the list of stash entries.\n \n-`create`::\n+`create [-u | --include-untracked]`::\n \tCreate a stash entry (which is a regular commit object) and\n \treturn its object name, without storing it anywhere in the ref\n \tnamespace.\n+\tIf the `--include-untracked` option is used, all untracked files are\n+\talso included in the stash entry.\n \tThis is intended to be useful for scripts.  It is probably not\n \tthe command you want to use; see \"push\" above.\n \n@@ -181,6 +183,9 @@ up with `git clean`.\n \tall untracked files are also stashed and then cleaned up with\n \t`git clean`.\n +\n+When used with the `create` command, all untracked files are also included\n+in the stash entry.\n++\n When used with the `show` command, show the untracked files in the stash\n entry as part of the diff.\n \ndiff --git a/builtin/stash.c b/builtin/stash.c\nindex 95c5005b0b..419f70ea39 100644\n--- a/builtin/stash.c\n+++ b/builtin/stash.c\n@@ -58,7 +58,7 @@\n \tN_(\"git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\\n\" \\\n \t   \"          [-u | --include-untracked] [-a | --all] [<message>]\")\n #define BUILTIN_STASH_CREATE_USAGE \\\n-\tN_(\"git stash create [<message>]\")\n+\tN_(\"git stash create [-u | --include-untracked] [<message>]\")\n #define BUILTIN_STASH_EXPORT_USAGE \\\n \tN_(\"git stash export (--print | --to-ref <ref>) [<stash>...]\")\n #define BUILTIN_STASH_IMPORT_USAGE \\\n@@ -118,6 +118,11 @@ static const char * const git_stash_clear_usage[] = {\n \tNULL\n };\n \n+static const char * const git_stash_create_usage[] = {\n+\tBUILTIN_STASH_CREATE_USAGE,\n+\tNULL\n+};\n+\n static const char * const git_stash_store_usage[] = {\n \tBUILTIN_STASH_STORE_USAGE,\n \tNULL\n@@ -1570,22 +1575,30 @@ done:\n \treturn ret;\n }\n \n-static int create_stash(int argc, const char **argv, const char *prefix UNUSED,\n+static int create_stash(int argc, const char **argv, const char *prefix,\n \t\t\tstruct repository *repo UNUSED)\n {\n \tint ret;\n+\tint include_untracked = 0;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL('u', \"include-untracked\", &include_untracked,\n+\t\t\tN_(\"include untracked files\")),\n+\t\tOPT_END()\n+\t};\n+\n \tstruct strbuf stash_msg_buf = STRBUF_INIT;\n \tstruct stash_info info = STASH_INFO_INIT;\n \tstruct pathspec ps;\n \n-\t/* Starting with argv[1], since argv[0] is \"create\" */\n-\tstrbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' ');\n+\targc = parse_options(argc, argv, prefix, options, git_stash_create_usage, 0);\n+\n+\tstrbuf_join_argv(&stash_msg_buf, argc, argv, ' ');\n \n \tmemset(&ps, 0, sizeof(ps));\n-\tif (!check_changes_tracked_files(&ps))\n+\tif (!include_untracked && !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+\tret = do_create_stash(&ps, &stash_msg_buf, include_untracked, 0, NULL, 0, &info,\n \t\t\t      NULL, 0);\n \tif (!ret)\n \t\tprintf_ln(\"%s\", oid_to_hex(&info.w_commit));\ndiff --git a/t/t3903-stash.sh b/t/t3903-stash.sh\nindex 70879941c2..4e0243e315 100755\n--- a/t/t3903-stash.sh\n+++ b/t/t3903-stash.sh\n@@ -639,6 +639,39 @@ test_expect_success 'stash create - no changes' '\n \ttest_must_be_empty actual\n '\n \n+test_expect_success 'stash create with --include-untracked' '\n+\ttest_when_finished \"git reset --hard && git clean -fd\" &&\n+\ttest_commit stash-create-untracked-1 file1 committed &&\n+\techo staged >file2 &&\n+\tgit add file2 &&\n+\techo unstaged >file3 &&\n+\techo untracked >untracked_file &&\n+\tSTASH_ID=$(git stash create --include-untracked \"test message\") &&\n+\tgit cat-file -p $STASH_ID >stash_commit &&\n+\tgrep \"test message\" stash_commit &&\n+\tgrep parent stash_commit >parents &&\n+\ttest_line_count = 3 parents &&\n+\tUNTRACKED_TREE=$(git rev-parse $STASH_ID^3^{tree}) &&\n+\tgit ls-tree $UNTRACKED_TREE >files &&\n+\tgrep untracked_file files &&\n+\ttest_path_is_file untracked_file\n+'\n+\n+test_expect_success 'stash create without --include-untracked does not include untracked files' '\n+\ttest_when_finished \"git reset --hard && git clean -fd\" &&\n+\ttest_commit stash-create-no-untracked-1 file4 committed &&\n+\techo staged >file5 &&\n+\tgit add file5 &&\n+\techo unstaged >file6 &&\n+\techo untracked >untracked_file2 &&\n+\tSTASH_ID=$(git stash create \"test message\") &&\n+\tgit cat-file -p $STASH_ID >stash_commit &&\n+\tgrep \"test message\" stash_commit &&\n+\tgrep parent stash_commit >parents &&\n+\ttest_line_count = 2 parents &&\n+\ttest_path_is_file untracked_file2\n+'\n+\n test_expect_success 'stash branch - no stashes on stack, stash-like argument' '\n \tgit stash clear &&\n \ttest_when_finished \"git reset --hard HEAD\" &&\n\nbase-commit: 5361983c075154725be47b65cca9a2421789e410\n-- \ngitgitgadget\n"},{"id":"541420","messageId":"CAEc8y5QM+gV0saHUO6xbTMP-GWH_KZWPb9V-khcML0+3=67ZCA@mail.gmail.com","threadId":"65380","inReplyTo":"pull.1892.git.1774768580147.gitgitgadget@gmail.com","subject":"Re: [PATCH/RFC] stash: add --include-untracked support to git stash create","fromName":"Shabbir Bhojani","fromEmail":"shabbir.r.bhojani@gmail.com","sentAt":"2026-04-11T07:17:27Z","receivedAt":"2026-04-11T07:17:39Z","isPatch":true,"body":"Friendly ping — this patch was submitted about two weeks ago and\nhasn't received any review or been picked up in \"What's cooking\" yet.\nWould appreciate it if someone could take a look when they get a\nchance. Thanks!\n"}]}