Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Documentation/git-stash.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ SYNOPSIS
'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>

DESCRIPTION
Expand Down Expand Up @@ -139,11 +139,13 @@ drop [-q|--quiet] [<stash>]::

Remove a single stash entry from the list of stash entries.

create::
create [-u | --include-untracked] [<message>]::

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.

Expand All @@ -170,6 +172,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.

Expand Down
23 changes: 18 additions & 5 deletions builtin/stash.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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_CLEAR_USAGE \
"git stash clear"

Expand Down Expand Up @@ -110,6 +110,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
Expand Down Expand Up @@ -1499,22 +1504,30 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
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, ' ');
Comment on lines -1510 to +1524
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want the --include-untracked option to be included in the message? In other words:

 	/* Starting with argv[1], since argv[0] is "create" */
-	strbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' ');
+	strbuf_join_argv(&stash_msg_buf, argc - 1, argv + 1, ' ');
 


memset(&ps, 0, sizeof(ps));
if (!check_changes_tracked_files(&ps))
return 0;

ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info,
ret = do_create_stash(&ps, &stash_msg_buf, include_untracked, 0, 0, &info,
NULL, 0);
if (!ret)
printf_ln("%s", oid_to_hex(&info.w_commit));
Expand Down
41 changes: 41 additions & 0 deletions t/t3903-stash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,47 @@ test_expect_success 'stash create - no changes' '
test_must_be_empty actual
'

test_expect_success 'stash create with --include-untracked' '
git init repo &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should not be any need to initialize a repository; When test_expect_success' code runs, it does so in a Git worktree that was prepared specifically for testing.

cd repo &&
echo committed >file1 &&
git add file1 &&
git commit -m "initial commit" &&
Comment on lines +638 to +640
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more concise to run test_commit file1...

Also, wouldn't it be possible to reuse what had already been set up by an earlier test case?

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 | wc -l >parent_count &&
echo 3 >expect &&
test_cmp expect parent_count &&
Comment on lines +648 to +650
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SBhojani As pointed out by the test failures, you will want to use grep parent stash_commit >parents && test_line_count = 3 parents instead (see the documentation of test_line_count; wc -l's output is not strictly portable).

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' '
git init repo2 &&
cd repo2 &&
echo committed >file1 &&
git add file1 &&
git commit -m "initial commit" &&
echo staged >file2 &&
git add file2 &&
echo unstaged >file3 &&
echo untracked >untracked_file &&
STASH_ID=$(git stash create "test message") &&
git cat-file -p $STASH_ID >stash_commit &&
grep "test message" stash_commit &&
grep "parent" stash_commit | wc -l >parent_count &&
echo 2 >expect &&
test_cmp expect parent_count &&
test_path_is_file untracked_file
'

test_expect_success 'stash branch - no stashes on stack, stash-like argument' '
git stash clear &&
test_when_finished "git reset --hard HEAD" &&
Expand Down
Loading