Skip to contentSkip to conversation

stash: add --include-untracked support to git stash create

PATCH/RFC Shabbir Bhojani via GitGitGadget 2 participants 2 messages Mar 29 – Apr 11 Documentation

lore
Share & tools
lore
#0 lore raw

From: SBhojani <[email protected]>

The git stash create command now supports the --include-untracked flag, allowing users to include untracked files in the stash entry. This brings parity with git stash push, which already supports this option.

Previously, git stash create would only stash tracked changes. With this change, users can optionally include untracked files by specifying --include-untracked. The implementation involves parsing the new option in create_stash and passing it to do_create_stash, which handles the creation of the stash entry.

The check for tracked changes is skipped when --include-untracked is set, as do_create_stash performs its own check internally. Test cases were added to t3903-stash.sh to ensure the correct behavior, and the documentation was updated accordingly.

---
stash: add --include-untracked support to git stash create

This is a single-commit pull request, and the commit message already describes the changes.

I just want to add context for where I felt the need for this. While working on a logical single commit task, my working tree is often in a state where certain changes are staged and others are not. I use this staging strategy as a conceptual model of which changes I intend to mostly keep as they are and which I intend to change, rewrite, refactor, discard, or not commit. Some of the changes in the latter category might be new untracked files. Now, I often use (my git GUI tool's equivalent of) git stash --include-untracked followed by git stash apply to take a snapshot of these changes to be able to come back to the state if I mess things up too much from that point on. Doing that results in the working directory being cleaned momentarily and then being repopulated again. My development tools often detect this as the files having been changed and then prompt me to reload them or cause rebuilds and so on. git stash store $(git stash create) has the nice feature that it doesn't touch the working directory, but it was missing the ability to also stash untracked files. This change fixes that.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1892%2FSBhojani%2Fstash-create-untracked-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1892/SBhojani/stash-create-untracked-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1892

 Documentation/git-stash.adoc |  9 +++++++--
 builtin/stash.c              | 25 +++++++++++++++++++------
 t/t3903-stash.sh             | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 8 deletions(-)
Documentation/git-stash.adoc +7 -2
index 235d57ddd8..c379062110 100644
@@ -21,7 +21,7 @@ git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --
 git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
            [-u | --include-untracked] [-a | --all] [<message>]
 git stash clear
-git stash create [<message>]
+git stash create [-u | --include-untracked] [<message>]
 git stash store [(-m | --message) <message>] [-q | --quiet] <commit>
 git stash export (--print | --to-ref <ref>) [<stash>...]
 git stash import <commit>
@@ -140,10 +140,12 @@ with no conflicts.
 `drop [-q | --quiet] [<stash>]`::
 	Remove a single stash entry from the list of stash entries.
 
-`create`::
+`create [-u | --include-untracked]`::
 	Create a stash entry (which is a regular commit object) and
 	return its object name, without storing it anywhere in the ref
 	namespace.
+	If the `--include-untracked` option is used, all untracked files are
+	also included in the stash entry.
 	This is intended to be useful for scripts.  It is probably not
 	the command you want to use; see "push" above.
 
@@ -181,6 +183,9 @@ up with `git clean`.
 	all untracked files are also stashed and then cleaned up with
 	`git clean`.
 +
+When used with the `create` command, all untracked files are also included
+in the stash entry.
++
 When used with the `show` command, show the untracked files in the stash
 entry as part of the diff.
 
builtin/stash.c +19 -6
index 95c5005b0b..419f70ea39 100644
@@ -58,7 +58,7 @@
 	N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
 	   "          [-u | --include-untracked] [-a | --all] [<message>]")
 #define BUILTIN_STASH_CREATE_USAGE \
-	N_("git stash create [<message>]")
+	N_("git stash create [-u | --include-untracked] [<message>]")
 #define BUILTIN_STASH_EXPORT_USAGE \
 	N_("git stash export (--print | --to-ref <ref>) [<stash>...]")
 #define BUILTIN_STASH_IMPORT_USAGE \
@@ -118,6 +118,11 @@ static const char * const git_stash_clear_usage[] = {
 	NULL
 };
 
+static const char * const git_stash_create_usage[] = {
+	BUILTIN_STASH_CREATE_USAGE,
+	NULL
+};
+
 static const char * const git_stash_store_usage[] = {
 	BUILTIN_STASH_STORE_USAGE,
 	NULL
@@ -1570,22 +1575,30 @@ done:
 	return ret;
 }
 
-static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
+static int create_stash(int argc, const char **argv, const char *prefix,
 			struct repository *repo UNUSED)
 {
 	int ret;
+	int include_untracked = 0;
+	struct option options[] = {
+		OPT_BOOL('u', "include-untracked", &include_untracked,
+			N_("include untracked files")),
+		OPT_END()
+	};
+
 	struct strbuf stash_msg_buf = STRBUF_INIT;
 	struct stash_info info = STASH_INFO_INIT;
 	struct pathspec ps;
 
-	/* Starting with argv[1], since argv[0] is "create" */
-	strbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' ');
+	argc = parse_options(argc, argv, prefix, options, git_stash_create_usage, 0);
+
+	strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');
 
 	memset(&ps, 0, sizeof(ps));
-	if (!check_changes_tracked_files(&ps))
+	if (!include_untracked && !check_changes_tracked_files(&ps))
 		return 0;
 
-	ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, NULL, 0, &info,
+	ret = do_create_stash(&ps, &stash_msg_buf, include_untracked, 0, NULL, 0, &info,
 			      NULL, 0);
 	if (!ret)
 		printf_ln("%s", oid_to_hex(&info.w_commit));
t/t3903-stash.sh +33 -0
index 70879941c2..4e0243e315 100755
@@ -639,6 +639,39 @@ test_expect_success 'stash create - no changes' '
 	test_must_be_empty actual
 '
 
+test_expect_success 'stash create with --include-untracked' '
+	test_when_finished "git reset --hard && git clean -fd" &&
+	test_commit stash-create-untracked-1 file1 committed &&
+	echo staged >file2 &&
+	git add file2 &&
+	echo unstaged >file3 &&
+	echo untracked >untracked_file &&
+	STASH_ID=$(git stash create --include-untracked "test message") &&
+	git cat-file -p $STASH_ID >stash_commit &&
+	grep "test message" stash_commit &&
+	grep parent stash_commit >parents &&
+	test_line_count = 3 parents &&
+	UNTRACKED_TREE=$(git rev-parse $STASH_ID^3^{tree}) &&
+	git ls-tree $UNTRACKED_TREE >files &&
+	grep untracked_file files &&
+	test_path_is_file untracked_file
+'
+
+test_expect_success 'stash create without --include-untracked does not include untracked files' '
+	test_when_finished "git reset --hard && git clean -fd" &&
+	test_commit stash-create-no-untracked-1 file4 committed &&
+	echo staged >file5 &&
+	git add file5 &&
+	echo unstaged >file6 &&
+	echo untracked >untracked_file2 &&
+	STASH_ID=$(git stash create "test message") &&
+	git cat-file -p $STASH_ID >stash_commit &&
+	grep "test message" stash_commit &&
+	grep parent stash_commit >parents &&
+	test_line_count = 2 parents &&
+	test_path_is_file untracked_file2
+'
+
 test_expect_success 'stash branch - no stashes on stack, stash-like argument' '
 	git stash clear &&
 	test_when_finished "git reset --hard HEAD" &&

base-commit: 5361983c075154725be47b65cca9a2421789e410

Signature · 1 line
gitgitgadget
#1 lore raw

Friendly ping — this patch was submitted about two weeks ago and hasn't received any review or been picked up in "What's cooking" yet. Would appreciate it if someone could take a look when they get a chance. Thanks!