mirror of
https://github.com/git/git.git
synced 2024-11-24 02:17:02 +08:00
Merge branch 'dc/stash-con-untracked'
* dc/stash-con-untracked: stash: Add --include-untracked option to stash and remove all untracked files Conflicts: git-stash.sh
This commit is contained in:
commit
22f41286be
@ -13,7 +13,8 @@ SYNOPSIS
|
||||
'git stash' drop [-q|--quiet] [<stash>]
|
||||
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
|
||||
'git stash' branch <branchname> [<stash>]
|
||||
'git stash' [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]]
|
||||
'git stash' [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
|
||||
[-u|--include-untracked] [-a|--all] [<message>]]
|
||||
'git stash' clear
|
||||
'git stash' create
|
||||
|
||||
@ -42,7 +43,7 @@ is also possible).
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
save [-p|--patch] [--[no-]keep-index] [-q|--quiet] [<message>]::
|
||||
save [-p|--patch] [--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
|
||||
|
||||
Save your local modifications to a new 'stash', and run `git reset
|
||||
--hard` to revert them. The <message> part is optional and gives
|
||||
@ -54,6 +55,11 @@ save [-p|--patch] [--[no-]keep-index] [-q|--quiet] [<message>]::
|
||||
If the `--keep-index` option is used, all changes already added to the
|
||||
index are left intact.
|
||||
+
|
||||
If the `--include-untracked` option is used, all untracked files are also
|
||||
stashed and then cleaned up with `git clean`, leaving the working directory
|
||||
in a very clean state. If the `--all` option is used instead then the
|
||||
ignored files are stashed and cleaned in addition to the untracked files.
|
||||
+
|
||||
With `--patch`, you can interactively select hunks from the diff
|
||||
between HEAD and the working tree to be stashed. The stash entry is
|
||||
constructed such that its index state is the same as the index state
|
||||
|
68
git-stash.sh
68
git-stash.sh
@ -7,7 +7,8 @@ USAGE="list [<options>]
|
||||
or: $dashless drop [-q|--quiet] [<stash>]
|
||||
or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
|
||||
or: $dashless branch <branchname> [<stash>]
|
||||
or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]]
|
||||
or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
|
||||
[-u|--include-untracked] [-a|--all] [<message>]]
|
||||
or: $dashless clear"
|
||||
|
||||
SUBDIRECTORY_OK=Yes
|
||||
@ -34,7 +35,14 @@ fi
|
||||
|
||||
no_changes () {
|
||||
git diff-index --quiet --cached HEAD --ignore-submodules -- &&
|
||||
git diff-files --quiet --ignore-submodules
|
||||
git diff-files --quiet --ignore-submodules &&
|
||||
(test -z "$untracked" || test -z "$(untracked_files)")
|
||||
}
|
||||
|
||||
untracked_files () {
|
||||
excl_opt=--exclude-standard
|
||||
test "$untracked" = "all" && excl_opt=
|
||||
git ls-files -o -z $excl_opt
|
||||
}
|
||||
|
||||
clear_stash () {
|
||||
@ -50,6 +58,7 @@ clear_stash () {
|
||||
|
||||
create_stash () {
|
||||
stash_msg="$1"
|
||||
untracked="$2"
|
||||
|
||||
git update-index -q --refresh
|
||||
if no_changes
|
||||
@ -79,6 +88,25 @@ create_stash () {
|
||||
git commit-tree $i_tree -p $b_commit) ||
|
||||
die "$(gettext "Cannot save the current index state")"
|
||||
|
||||
if test -n "$untracked"
|
||||
then
|
||||
# Untracked files are stored by themselves in a parentless commit, for
|
||||
# ease of unpacking later.
|
||||
u_commit=$(
|
||||
untracked_files | (
|
||||
export GIT_INDEX_FILE="$TMPindex"
|
||||
rm -f "$TMPindex" &&
|
||||
git update-index -z --add --remove --stdin &&
|
||||
u_tree=$(git write-tree) &&
|
||||
printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree &&
|
||||
rm -f "$TMPindex"
|
||||
) ) || die "Cannot save the untracked files"
|
||||
|
||||
untracked_commit_option="-p $u_commit";
|
||||
else
|
||||
untracked_commit_option=
|
||||
fi
|
||||
|
||||
if test -z "$patch_mode"
|
||||
then
|
||||
|
||||
@ -123,13 +151,14 @@ create_stash () {
|
||||
stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
|
||||
fi
|
||||
w_commit=$(printf '%s\n' "$stash_msg" |
|
||||
git commit-tree $w_tree -p $b_commit -p $i_commit) ||
|
||||
git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||
|
||||
die "$(gettext "Cannot record working tree state")"
|
||||
}
|
||||
|
||||
save_stash () {
|
||||
keep_index=
|
||||
patch_mode=
|
||||
untracked=
|
||||
while test $# != 0
|
||||
do
|
||||
case "$1" in
|
||||
@ -147,6 +176,12 @@ save_stash () {
|
||||
-q|--quiet)
|
||||
GIT_QUIET=t
|
||||
;;
|
||||
-u|--include-untracked)
|
||||
untracked=untracked
|
||||
;;
|
||||
-a|--all)
|
||||
untracked=all
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
@ -174,6 +209,11 @@ save_stash () {
|
||||
shift
|
||||
done
|
||||
|
||||
if test -n "$patch_mode" && test -n "$untracked"
|
||||
then
|
||||
die "Can't use --patch and ---include-untracked or --all at the same time"
|
||||
fi
|
||||
|
||||
stash_msg="$*"
|
||||
|
||||
git update-index -q --refresh
|
||||
@ -185,7 +225,7 @@ save_stash () {
|
||||
test -f "$GIT_DIR/logs/$ref_stash" ||
|
||||
clear_stash || die "$(gettext "Cannot initialize stash")"
|
||||
|
||||
create_stash "$stash_msg"
|
||||
create_stash "$stash_msg" $untracked
|
||||
|
||||
# Make sure the reflog for stash is kept.
|
||||
: >>"$GIT_DIR/logs/$ref_stash"
|
||||
@ -197,6 +237,11 @@ save_stash () {
|
||||
if test -z "$patch_mode"
|
||||
then
|
||||
git reset --hard ${GIT_QUIET:+-q}
|
||||
test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
|
||||
if test -n "$untracked"
|
||||
then
|
||||
git clean --force --quiet $CLEAN_X_OPTION
|
||||
fi
|
||||
|
||||
if test "$keep_index" = "t" && test -n $i_tree
|
||||
then
|
||||
@ -246,9 +291,11 @@ show_stash () {
|
||||
# w_commit is set to the commit containing the working tree
|
||||
# b_commit is set to the base commit
|
||||
# i_commit is set to the commit containing the index tree
|
||||
# u_commit is set to the commit containing the untracked files tree
|
||||
# w_tree is set to the working tree
|
||||
# b_tree is set to the base tree
|
||||
# i_tree is set to the index tree
|
||||
# u_tree is set to the untracked files tree
|
||||
#
|
||||
# GIT_QUIET is set to t if -q is specified
|
||||
# INDEX_OPTION is set to --index if --index is specified.
|
||||
@ -273,9 +320,11 @@ parse_flags_and_rev()
|
||||
w_commit=
|
||||
b_commit=
|
||||
i_commit=
|
||||
u_commit=
|
||||
w_tree=
|
||||
b_tree=
|
||||
i_tree=
|
||||
u_tree=
|
||||
|
||||
REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1
|
||||
|
||||
@ -326,6 +375,9 @@ parse_flags_and_rev()
|
||||
IS_STASH_LIKE=t &&
|
||||
test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
|
||||
IS_STASH_REF=t
|
||||
|
||||
u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null) &&
|
||||
u_tree=$(git rev-parse $REV^3: 2>/dev/null)
|
||||
}
|
||||
|
||||
is_stash_like()
|
||||
@ -374,6 +426,14 @@ apply_stash () {
|
||||
git reset
|
||||
fi
|
||||
|
||||
if test -n "$u_tree"
|
||||
then
|
||||
GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" &&
|
||||
GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
|
||||
rm -f "$TMPindex" ||
|
||||
die 'Could not restore untracked files from stash'
|
||||
fi
|
||||
|
||||
eval "
|
||||
GITHEAD_$w_tree='Stashed changes' &&
|
||||
GITHEAD_$c_tree='Updated upstream' &&
|
||||
|
155
t/t3905-stash-include-untracked.sh
Executable file
155
t/t3905-stash-include-untracked.sh
Executable file
@ -0,0 +1,155 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011 David Caldwell
|
||||
#
|
||||
|
||||
test_description='Test git stash --include-untracked'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'stash save --include-untracked some dirty working directory' '
|
||||
echo 1 > file &&
|
||||
git add file &&
|
||||
test_tick &&
|
||||
git commit -m initial &&
|
||||
echo 2 > file &&
|
||||
git add file &&
|
||||
echo 3 > file &&
|
||||
test_tick &&
|
||||
echo 1 > file2 &&
|
||||
git stash --include-untracked &&
|
||||
git diff-files --quiet &&
|
||||
git diff-index --cached --quiet HEAD
|
||||
'
|
||||
|
||||
cat > expect <<EOF
|
||||
?? expect
|
||||
?? output
|
||||
EOF
|
||||
|
||||
test_expect_success 'stash save --include-untracked cleaned the untracked files' '
|
||||
git status --porcelain > output
|
||||
test_cmp output expect
|
||||
'
|
||||
|
||||
cat > expect.diff <<EOF
|
||||
diff --git a/file2 b/file2
|
||||
new file mode 100644
|
||||
index 0000000..d00491f
|
||||
--- /dev/null
|
||||
+++ b/file2
|
||||
@@ -0,0 +1 @@
|
||||
+1
|
||||
EOF
|
||||
cat > expect.lstree <<EOF
|
||||
file2
|
||||
EOF
|
||||
|
||||
test_expect_success 'stash save --include-untracked stashed the untracked files' '
|
||||
test "!" -f file2 &&
|
||||
git diff HEAD..stash^3 -- file2 > output &&
|
||||
test_cmp output expect.diff &&
|
||||
git ls-tree --name-only stash^3: > output &&
|
||||
test_cmp output expect.lstree
|
||||
'
|
||||
test_expect_success 'stash save --patch --include-untracked fails' '
|
||||
test_must_fail git stash --patch --include-untracked
|
||||
'
|
||||
|
||||
test_expect_success 'stash save --patch --all fails' '
|
||||
test_must_fail git stash --patch --all
|
||||
'
|
||||
|
||||
git clean --force --quiet
|
||||
|
||||
cat > expect <<EOF
|
||||
M file
|
||||
?? expect
|
||||
?? file2
|
||||
?? output
|
||||
EOF
|
||||
|
||||
test_expect_success 'stash pop after save --include-untracked leaves files untracked again' '
|
||||
git stash pop &&
|
||||
git status --porcelain > output
|
||||
test_cmp output expect
|
||||
'
|
||||
|
||||
git clean --force --quiet
|
||||
|
||||
test_expect_success 'stash save -u dirty index' '
|
||||
echo 4 > file3 &&
|
||||
git add file3 &&
|
||||
test_tick &&
|
||||
git stash -u
|
||||
'
|
||||
|
||||
cat > expect <<EOF
|
||||
diff --git a/file3 b/file3
|
||||
new file mode 100644
|
||||
index 0000000..b8626c4
|
||||
--- /dev/null
|
||||
+++ b/file3
|
||||
@@ -0,0 +1 @@
|
||||
+4
|
||||
EOF
|
||||
|
||||
test_expect_success 'stash save --include-untracked dirty index got stashed' '
|
||||
git stash pop --index &&
|
||||
git diff --cached > output &&
|
||||
test_cmp output expect
|
||||
'
|
||||
|
||||
git reset > /dev/null
|
||||
|
||||
test_expect_success 'stash save --include-untracked -q is quiet' '
|
||||
echo 1 > file5 &&
|
||||
git stash save --include-untracked --quiet > output.out 2>&1 &&
|
||||
test ! -s output.out
|
||||
'
|
||||
|
||||
test_expect_success 'stash save --include-untracked removed files' '
|
||||
rm -f file &&
|
||||
git stash save --include-untracked &&
|
||||
echo 1 > expect &&
|
||||
test_cmp file expect
|
||||
'
|
||||
|
||||
rm -f expect
|
||||
|
||||
test_expect_success 'stash save --include-untracked removed files got stashed' '
|
||||
git stash pop &&
|
||||
test ! -f file
|
||||
'
|
||||
|
||||
cat > .gitignore <<EOF
|
||||
.gitignore
|
||||
ignored
|
||||
EOF
|
||||
|
||||
test_expect_success 'stash save --include-untracked respects .gitignore' '
|
||||
echo ignored > ignored &&
|
||||
git stash -u &&
|
||||
test -s ignored &&
|
||||
test -s .gitignore
|
||||
'
|
||||
|
||||
test_expect_success 'stash save -u can stash with only untracked files different' '
|
||||
echo 4 > file4 &&
|
||||
git stash -u
|
||||
test "!" -f file4
|
||||
'
|
||||
|
||||
test_expect_success 'stash save --all does not respect .gitignore' '
|
||||
git stash -a &&
|
||||
test "!" -f ignored &&
|
||||
test "!" -f .gitignore
|
||||
'
|
||||
|
||||
test_expect_success 'stash save --all is stash poppable' '
|
||||
git stash pop &&
|
||||
test -s ignored &&
|
||||
test -s .gitignore
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user