Merge branch 'am/pathspec-f-f-more'
"git rm" and "git stash" learns the new "--pathspec-from-file" option. * am/pathspec-f-f-more: stash push: support the --pathspec-from-file option stash: eliminate crude option parsing doc: stash: synchronize <pathspec> description doc: stash: document more options doc: stash: split options from description (2) doc: stash: split options from description (1) rm: support the --pathspec-from-file option doc: rm: synchronize <pathspec> description
This commit is contained in:
commit
9b7f726dfc
@ -8,16 +8,18 @@ git-rm - Remove files from the working tree and from the index
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...
|
'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]
|
||||||
|
[--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]
|
||||||
|
[--] [<pathspec>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Remove files from the index, or from the working tree and the index.
|
Remove files matching pathspec from the index, or from the working tree
|
||||||
`git rm` will not remove a file from just your working directory.
|
and the index. `git rm` will not remove a file from just your working
|
||||||
(There is no option to remove a file only from the working tree
|
directory. (There is no option to remove a file only from the working
|
||||||
and yet keep it in the index; use `/bin/rm` if you want to do that.)
|
tree and yet keep it in the index; use `/bin/rm` if you want to do
|
||||||
The files being removed have to be identical to the tip of the branch,
|
that.) The files being removed have to be identical to the tip of the
|
||||||
and no updates to their contents can be staged in the index,
|
branch, and no updates to their contents can be staged in the index,
|
||||||
though that default behavior can be overridden with the `-f` option.
|
though that default behavior can be overridden with the `-f` option.
|
||||||
When `--cached` is given, the staged content has to
|
When `--cached` is given, the staged content has to
|
||||||
match either the tip of the branch or the file on disk,
|
match either the tip of the branch or the file on disk,
|
||||||
@ -26,15 +28,20 @@ allowing the file to be removed from just the index.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<file>...::
|
<pathspec>...::
|
||||||
Files to remove. Fileglobs (e.g. `*.c`) can be given to
|
Files to remove. A leading directory name (e.g. `dir` to remove
|
||||||
remove all matching files. If you want Git to expand
|
`dir/file1` and `dir/file2`) can be given to remove all files in
|
||||||
file glob characters, you may need to shell-escape them.
|
the directory, and recursively all sub-directories, but this
|
||||||
A leading directory name
|
requires the `-r` option to be explicitly given.
|
||||||
(e.g. `dir` to remove `dir/file1` and `dir/file2`) can be
|
+
|
||||||
given to remove all files in the directory, and recursively
|
The command removes only the paths that are known to Git.
|
||||||
all sub-directories,
|
+
|
||||||
but this requires the `-r` option to be explicitly given.
|
File globbing matches across directory boundaries. Thus, given two
|
||||||
|
directories `d` and `d2`, there is a difference between using
|
||||||
|
`git rm 'd*'` and `git rm 'd/*'`, as the former will also remove all
|
||||||
|
of directory `d2`.
|
||||||
|
+
|
||||||
|
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
|
||||||
|
|
||||||
-f::
|
-f::
|
||||||
--force::
|
--force::
|
||||||
@ -68,19 +75,19 @@ OPTIONS
|
|||||||
`git rm` normally outputs one line (in the form of an `rm` command)
|
`git rm` normally outputs one line (in the form of an `rm` command)
|
||||||
for each file removed. This option suppresses that output.
|
for each file removed. This option suppresses that output.
|
||||||
|
|
||||||
|
--pathspec-from-file=<file>::
|
||||||
|
Pathspec is passed in `<file>` instead of commandline args. If
|
||||||
|
`<file>` is exactly `-` then standard input is used. Pathspec
|
||||||
|
elements are separated by LF or CR/LF. Pathspec elements can be
|
||||||
|
quoted as explained for the configuration variable `core.quotePath`
|
||||||
|
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
|
||||||
|
global `--literal-pathspecs`.
|
||||||
|
|
||||||
DISCUSSION
|
--pathspec-file-nul::
|
||||||
----------
|
Only meaningful with `--pathspec-from-file`. Pathspec elements are
|
||||||
|
separated with NUL character and all other characters are taken
|
||||||
|
literally (including newlines and quotes).
|
||||||
|
|
||||||
The <file> list given to the command can be exact pathnames,
|
|
||||||
file glob patterns, or leading directory names. The command
|
|
||||||
removes only the paths that are known to Git. Giving the name of
|
|
||||||
a file that you have not told Git about does not remove that file.
|
|
||||||
|
|
||||||
File globbing matches across directory boundaries. Thus, given
|
|
||||||
two directories `d` and `d2`, there is a difference between
|
|
||||||
using `git rm 'd*'` and `git rm 'd/*'`, as the former will
|
|
||||||
also remove all of directory `d2`.
|
|
||||||
|
|
||||||
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
|
REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
@ -15,6 +15,7 @@ SYNOPSIS
|
|||||||
'git stash' branch <branchname> [<stash>]
|
'git stash' branch <branchname> [<stash>]
|
||||||
'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
|
'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
|
||||||
[-u|--include-untracked] [-a|--all] [-m|--message <message>]
|
[-u|--include-untracked] [-a|--all] [-m|--message <message>]
|
||||||
|
[--pathspec-from-file=<file> [--pathspec-file-nul]]
|
||||||
[--] [<pathspec>...]]
|
[--] [<pathspec>...]]
|
||||||
'git stash' clear
|
'git stash' clear
|
||||||
'git stash' create [<message>]
|
'git stash' create [<message>]
|
||||||
@ -43,10 +44,10 @@ created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
|
|||||||
is also possible). Stashes may also be referenced by specifying just the
|
is also possible). Stashes may also be referenced by specifying just the
|
||||||
stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
|
stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
|
||||||
|
|
||||||
OPTIONS
|
COMMANDS
|
||||||
-------
|
--------
|
||||||
|
|
||||||
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
|
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
|
||||||
|
|
||||||
Save your local modifications to a new 'stash entry' and roll them
|
Save your local modifications to a new 'stash entry' and roll them
|
||||||
back to HEAD (in the working tree and in the index).
|
back to HEAD (in the working tree and in the index).
|
||||||
@ -56,38 +57,13 @@ push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q
|
|||||||
For quickly making a snapshot, you can omit "push". In this mode,
|
For quickly making a snapshot, you can omit "push". In this mode,
|
||||||
non-option arguments are not allowed to prevent a misspelled
|
non-option arguments are not allowed to prevent a misspelled
|
||||||
subcommand from making an unwanted stash entry. The two exceptions to this
|
subcommand from making an unwanted stash entry. The two exceptions to this
|
||||||
are `stash -p` which acts as alias for `stash push -p` and pathspecs,
|
are `stash -p` which acts as alias for `stash push -p` and pathspec elements,
|
||||||
which are allowed after a double hyphen `--` for disambiguation.
|
which are allowed after a double hyphen `--` for disambiguation.
|
||||||
+
|
|
||||||
When pathspec is given to 'git stash push', the new stash entry records the
|
|
||||||
modified states only for the files that match the pathspec. The index
|
|
||||||
entries and working tree files are then rolled back to the state in
|
|
||||||
HEAD only for these files, too, leaving files that do not match the
|
|
||||||
pathspec intact.
|
|
||||||
+
|
|
||||||
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
|
|
||||||
of your repository, and its worktree contains only the changes you
|
|
||||||
selected interactively. The selected changes are then rolled back
|
|
||||||
from your worktree. See the ``Interactive Mode'' section of
|
|
||||||
linkgit:git-add[1] to learn how to operate the `--patch` mode.
|
|
||||||
+
|
|
||||||
The `--patch` option implies `--keep-index`. You can use
|
|
||||||
`--no-keep-index` to override this.
|
|
||||||
|
|
||||||
save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
|
save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
|
||||||
|
|
||||||
This option is deprecated in favour of 'git stash push'. It
|
This option is deprecated in favour of 'git stash push'. It
|
||||||
differs from "stash push" in that it cannot take pathspecs.
|
differs from "stash push" in that it cannot take pathspec.
|
||||||
Instead, all non-option arguments are concatenated to form the stash
|
Instead, all non-option arguments are concatenated to form the stash
|
||||||
message.
|
message.
|
||||||
|
|
||||||
@ -111,7 +87,7 @@ show [<options>] [<stash>]::
|
|||||||
|
|
||||||
Show the changes recorded in the stash entry as a diff between the
|
Show the changes recorded in the stash entry as a diff between the
|
||||||
stashed contents and the commit back when the stash entry was first
|
stashed contents and the commit back when the stash entry was first
|
||||||
created. When no `<stash>` is given, it shows the latest one.
|
created.
|
||||||
By default, the command shows the diffstat, but it will accept any
|
By default, the command shows the diffstat, but it will accept any
|
||||||
format known to 'git diff' (e.g., `git stash show -p stash@{1}`
|
format known to 'git diff' (e.g., `git stash show -p stash@{1}`
|
||||||
to view the second most recent entry in patch form).
|
to view the second most recent entry in patch form).
|
||||||
@ -128,14 +104,6 @@ pop [--index] [-q|--quiet] [<stash>]::
|
|||||||
Applying the state can fail with conflicts; in this case, it is not
|
Applying the state can fail with conflicts; in this case, it is not
|
||||||
removed from the stash list. You need to resolve the conflicts by hand
|
removed from the stash list. You need to resolve the conflicts by hand
|
||||||
and call `git stash drop` manually afterwards.
|
and call `git stash drop` manually afterwards.
|
||||||
+
|
|
||||||
If the `--index` option is used, then tries to reinstate not only the working
|
|
||||||
tree's changes, but also the index's ones. However, this can fail, when you
|
|
||||||
have conflicts (which are stored in the index, where you therefore can no
|
|
||||||
longer apply the changes as they were originally).
|
|
||||||
+
|
|
||||||
When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must
|
|
||||||
be a reference of the form `stash@{<revision>}`.
|
|
||||||
|
|
||||||
apply [--index] [-q|--quiet] [<stash>]::
|
apply [--index] [-q|--quiet] [<stash>]::
|
||||||
|
|
||||||
@ -149,8 +117,7 @@ branch <branchname> [<stash>]::
|
|||||||
the commit at which the `<stash>` was originally created, applies the
|
the commit at which the `<stash>` was originally created, applies the
|
||||||
changes recorded in `<stash>` to the new working tree and index.
|
changes recorded in `<stash>` to the new working tree and index.
|
||||||
If that succeeds, and `<stash>` is a reference of the form
|
If that succeeds, and `<stash>` is a reference of the form
|
||||||
`stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>`
|
`stash@{<revision>}`, it then drops the `<stash>`.
|
||||||
is given, applies the latest one.
|
|
||||||
+
|
+
|
||||||
This is useful if the branch on which you ran `git stash push` has
|
This is useful if the branch on which you ran `git stash push` has
|
||||||
changed enough that `git stash apply` fails due to conflicts. Since
|
changed enough that `git stash apply` fails due to conflicts. Since
|
||||||
@ -166,9 +133,6 @@ clear::
|
|||||||
drop [-q|--quiet] [<stash>]::
|
drop [-q|--quiet] [<stash>]::
|
||||||
|
|
||||||
Remove a single stash entry from the list of stash entries.
|
Remove a single stash entry from the list of stash entries.
|
||||||
When no `<stash>` is given, it removes the latest one.
|
|
||||||
i.e. `stash@{0}`, otherwise `<stash>` must be a valid stash
|
|
||||||
log reference of the form `stash@{<revision>}`.
|
|
||||||
|
|
||||||
create::
|
create::
|
||||||
|
|
||||||
@ -185,6 +149,98 @@ store::
|
|||||||
reflog. This is intended to be useful for scripts. It is
|
reflog. This is intended to be useful for scripts. It is
|
||||||
probably not the command you want to use; see "push" above.
|
probably not the command you want to use; see "push" above.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
-a::
|
||||||
|
--all::
|
||||||
|
This option is only valid for `push` and `save` commands.
|
||||||
|
+
|
||||||
|
All ignored and untracked files are also stashed and then cleaned
|
||||||
|
up with `git clean`.
|
||||||
|
|
||||||
|
-u::
|
||||||
|
--include-untracked::
|
||||||
|
This option is only valid for `push` and `save` commands.
|
||||||
|
+
|
||||||
|
All untracked files are also stashed and then cleaned up with
|
||||||
|
`git clean`.
|
||||||
|
|
||||||
|
--index::
|
||||||
|
This option is only valid for `pop` and `apply` commands.
|
||||||
|
+
|
||||||
|
Tries to reinstate not only the working tree's changes, but also
|
||||||
|
the index's ones. However, this can fail, when you have conflicts
|
||||||
|
(which are stored in the index, where you therefore can no longer
|
||||||
|
apply the changes as they were originally).
|
||||||
|
|
||||||
|
-k::
|
||||||
|
--keep-index::
|
||||||
|
--no-keep-index::
|
||||||
|
This option is only valid for `push` and `save` commands.
|
||||||
|
+
|
||||||
|
All changes already added to the index are left intact.
|
||||||
|
|
||||||
|
-p::
|
||||||
|
--patch::
|
||||||
|
This option is only valid for `push` and `save` commands.
|
||||||
|
+
|
||||||
|
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 of your
|
||||||
|
repository, and its worktree contains only the changes you selected
|
||||||
|
interactively. The selected changes are then rolled back from your
|
||||||
|
worktree. See the ``Interactive Mode'' section of linkgit:git-add[1]
|
||||||
|
to learn how to operate the `--patch` mode.
|
||||||
|
+
|
||||||
|
The `--patch` option implies `--keep-index`. You can use
|
||||||
|
`--no-keep-index` to override this.
|
||||||
|
|
||||||
|
--pathspec-from-file=<file>::
|
||||||
|
This option is only valid for `push` command.
|
||||||
|
+
|
||||||
|
Pathspec is passed in `<file>` instead of commandline args. If
|
||||||
|
`<file>` is exactly `-` then standard input is used. Pathspec
|
||||||
|
elements are separated by LF or CR/LF. Pathspec elements can be
|
||||||
|
quoted as explained for the configuration variable `core.quotePath`
|
||||||
|
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
|
||||||
|
global `--literal-pathspecs`.
|
||||||
|
|
||||||
|
--pathspec-file-nul::
|
||||||
|
This option is only valid for `push` command.
|
||||||
|
+
|
||||||
|
Only meaningful with `--pathspec-from-file`. Pathspec elements are
|
||||||
|
separated with NUL character and all other characters are taken
|
||||||
|
literally (including newlines and quotes).
|
||||||
|
|
||||||
|
-q::
|
||||||
|
--quiet::
|
||||||
|
This option is only valid for `apply`, `drop`, `pop`, `push`,
|
||||||
|
`save`, `store` commands.
|
||||||
|
+
|
||||||
|
Quiet, suppress feedback messages.
|
||||||
|
|
||||||
|
\--::
|
||||||
|
This option is only valid for `push` command.
|
||||||
|
+
|
||||||
|
Separates pathspec from options for disambiguation purposes.
|
||||||
|
|
||||||
|
<pathspec>...::
|
||||||
|
This option is only valid for `push` command.
|
||||||
|
+
|
||||||
|
The new stash entry records the modified states only for the files
|
||||||
|
that match the pathspec. The index entries and working tree files
|
||||||
|
are then rolled back to the state in HEAD only for these files,
|
||||||
|
too, leaving files that do not match the pathspec intact.
|
||||||
|
+
|
||||||
|
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
|
||||||
|
|
||||||
|
<stash>::
|
||||||
|
This option is only valid for `apply`, `branch`, `drop`, `pop`,
|
||||||
|
`show` commands.
|
||||||
|
+
|
||||||
|
A reference of the form `stash@{<revision>}`. When no `<stash>` is
|
||||||
|
given, the latest stash is assumed (that is, `stash@{0}`).
|
||||||
|
|
||||||
DISCUSSION
|
DISCUSSION
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
28
builtin/rm.c
28
builtin/rm.c
@ -235,7 +235,8 @@ static int check_local_mod(struct object_id *head, int index_only)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
|
static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
|
||||||
static int ignore_unmatch = 0;
|
static int ignore_unmatch = 0, pathspec_file_nul;
|
||||||
|
static char *pathspec_from_file;
|
||||||
|
|
||||||
static struct option builtin_rm_options[] = {
|
static struct option builtin_rm_options[] = {
|
||||||
OPT__DRY_RUN(&show_only, N_("dry run")),
|
OPT__DRY_RUN(&show_only, N_("dry run")),
|
||||||
@ -245,6 +246,8 @@ static struct option builtin_rm_options[] = {
|
|||||||
OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
|
OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
|
||||||
OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
|
OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
|
||||||
N_("exit with a zero status even if nothing matched")),
|
N_("exit with a zero status even if nothing matched")),
|
||||||
|
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
|
||||||
|
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, builtin_rm_options,
|
argc = parse_options(argc, argv, prefix, builtin_rm_options,
|
||||||
builtin_rm_usage, 0);
|
builtin_rm_usage, 0);
|
||||||
if (!argc)
|
|
||||||
usage_with_options(builtin_rm_usage, builtin_rm_options);
|
parse_pathspec(&pathspec, 0,
|
||||||
|
PATHSPEC_PREFER_CWD,
|
||||||
|
prefix, argv);
|
||||||
|
|
||||||
|
if (pathspec_from_file) {
|
||||||
|
if (pathspec.nr)
|
||||||
|
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
|
||||||
|
|
||||||
|
parse_pathspec_file(&pathspec, 0,
|
||||||
|
PATHSPEC_PREFER_CWD,
|
||||||
|
prefix, pathspec_from_file, pathspec_file_nul);
|
||||||
|
} else if (pathspec_file_nul) {
|
||||||
|
die(_("--pathspec-file-nul requires --pathspec-from-file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pathspec.nr)
|
||||||
|
die(_("No pathspec was given. Which files should I remove?"));
|
||||||
|
|
||||||
if (!index_only)
|
if (!index_only)
|
||||||
setup_work_tree();
|
setup_work_tree();
|
||||||
@ -270,9 +289,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
|||||||
if (read_cache() < 0)
|
if (read_cache() < 0)
|
||||||
die(_("index file corrupt"));
|
die(_("index file corrupt"));
|
||||||
|
|
||||||
parse_pathspec(&pathspec, 0,
|
|
||||||
PATHSPEC_PREFER_CWD,
|
|
||||||
prefix, argv);
|
|
||||||
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
|
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
|
||||||
|
|
||||||
seen = xcalloc(pathspec.nr, 1);
|
seen = xcalloc(pathspec.nr, 1);
|
||||||
|
@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {
|
|||||||
N_("git stash clear"),
|
N_("git stash clear"),
|
||||||
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
|
N_("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
|
||||||
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
|
" [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
|
||||||
|
" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
|
||||||
" [--] [<pathspec>...]]"),
|
" [--] [<pathspec>...]]"),
|
||||||
N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
|
N_("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
|
||||||
" [-u|--include-untracked] [-a|--all] [<message>]"),
|
" [-u|--include-untracked] [-a|--all] [<message>]"),
|
||||||
@ -1451,13 +1452,17 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int push_stash(int argc, const char **argv, const char *prefix)
|
static int push_stash(int argc, const char **argv, const char *prefix,
|
||||||
|
int push_assumed)
|
||||||
{
|
{
|
||||||
|
int force_assume = 0;
|
||||||
int keep_index = -1;
|
int keep_index = -1;
|
||||||
int patch_mode = 0;
|
int patch_mode = 0;
|
||||||
int include_untracked = 0;
|
int include_untracked = 0;
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
|
int pathspec_file_nul = 0;
|
||||||
const char *stash_msg = NULL;
|
const char *stash_msg = NULL;
|
||||||
|
const char *pathspec_from_file = NULL;
|
||||||
struct pathspec ps;
|
struct pathspec ps;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_BOOL('k', "keep-index", &keep_index,
|
OPT_BOOL('k', "keep-index", &keep_index,
|
||||||
@ -1471,16 +1476,45 @@ static int push_stash(int argc, const char **argv, const char *prefix)
|
|||||||
N_("include ignore files"), 2),
|
N_("include ignore files"), 2),
|
||||||
OPT_STRING('m', "message", &stash_msg, N_("message"),
|
OPT_STRING('m', "message", &stash_msg, N_("message"),
|
||||||
N_("stash message")),
|
N_("stash message")),
|
||||||
|
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
|
||||||
|
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (argc)
|
if (argc) {
|
||||||
|
force_assume = !strcmp(argv[0], "-p");
|
||||||
argc = parse_options(argc, argv, prefix, options,
|
argc = parse_options(argc, argv, prefix, options,
|
||||||
git_stash_push_usage,
|
git_stash_push_usage,
|
||||||
0);
|
PARSE_OPT_KEEP_DASHDASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc) {
|
||||||
|
if (!strcmp(argv[0], "--")) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
} else if (push_assumed && !force_assume) {
|
||||||
|
die("subcommand wasn't specified; 'push' can't be assumed due to unexpected token '%s'",
|
||||||
|
argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
|
parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
|
||||||
prefix, argv);
|
prefix, argv);
|
||||||
|
|
||||||
|
if (pathspec_from_file) {
|
||||||
|
if (patch_mode)
|
||||||
|
die(_("--pathspec-from-file is incompatible with --patch"));
|
||||||
|
|
||||||
|
if (ps.nr)
|
||||||
|
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
|
||||||
|
|
||||||
|
parse_pathspec_file(&ps, 0,
|
||||||
|
PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
|
||||||
|
prefix, pathspec_from_file, pathspec_file_nul);
|
||||||
|
} else if (pathspec_file_nul) {
|
||||||
|
die(_("--pathspec-file-nul requires --pathspec-from-file"));
|
||||||
|
}
|
||||||
|
|
||||||
return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
|
return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
|
||||||
include_untracked);
|
include_untracked);
|
||||||
}
|
}
|
||||||
@ -1550,7 +1584,6 @@ static int use_builtin_stash(void)
|
|||||||
|
|
||||||
int cmd_stash(int argc, const char **argv, const char *prefix)
|
int cmd_stash(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i = -1;
|
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
const char *index_file;
|
const char *index_file;
|
||||||
struct argv_array args = ARGV_ARRAY_INIT;
|
struct argv_array args = ARGV_ARRAY_INIT;
|
||||||
@ -1583,7 +1616,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
|
|||||||
(uintmax_t)pid);
|
(uintmax_t)pid);
|
||||||
|
|
||||||
if (!argc)
|
if (!argc)
|
||||||
return !!push_stash(0, NULL, prefix);
|
return !!push_stash(0, NULL, prefix, 0);
|
||||||
else if (!strcmp(argv[0], "apply"))
|
else if (!strcmp(argv[0], "apply"))
|
||||||
return !!apply_stash(argc, argv, prefix);
|
return !!apply_stash(argc, argv, prefix);
|
||||||
else if (!strcmp(argv[0], "clear"))
|
else if (!strcmp(argv[0], "clear"))
|
||||||
@ -1603,45 +1636,15 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
|
|||||||
else if (!strcmp(argv[0], "create"))
|
else if (!strcmp(argv[0], "create"))
|
||||||
return !!create_stash(argc, argv, prefix);
|
return !!create_stash(argc, argv, prefix);
|
||||||
else if (!strcmp(argv[0], "push"))
|
else if (!strcmp(argv[0], "push"))
|
||||||
return !!push_stash(argc, argv, prefix);
|
return !!push_stash(argc, argv, prefix, 0);
|
||||||
else if (!strcmp(argv[0], "save"))
|
else if (!strcmp(argv[0], "save"))
|
||||||
return !!save_stash(argc, argv, prefix);
|
return !!save_stash(argc, argv, prefix);
|
||||||
else if (*argv[0] != '-')
|
else if (*argv[0] != '-')
|
||||||
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
|
usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
|
||||||
git_stash_usage, options);
|
git_stash_usage, options);
|
||||||
|
|
||||||
if (strcmp(argv[0], "-p")) {
|
/* Assume 'stash push' */
|
||||||
while (++i < argc && strcmp(argv[i], "--")) {
|
|
||||||
/*
|
|
||||||
* `akpqu` is a string which contains all short options,
|
|
||||||
* except `-m` which is verified separately.
|
|
||||||
*/
|
|
||||||
if ((strlen(argv[i]) == 2) && *argv[i] == '-' &&
|
|
||||||
strchr("akpqu", argv[i][1]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!strcmp(argv[i], "--all") ||
|
|
||||||
!strcmp(argv[i], "--keep-index") ||
|
|
||||||
!strcmp(argv[i], "--no-keep-index") ||
|
|
||||||
!strcmp(argv[i], "--patch") ||
|
|
||||||
!strcmp(argv[i], "--quiet") ||
|
|
||||||
!strcmp(argv[i], "--include-untracked"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* `-m` and `--message=` are verified separately because
|
|
||||||
* they need to be immediately followed by a string
|
|
||||||
* (i.e.`-m"foobar"` or `--message="foobar"`).
|
|
||||||
*/
|
|
||||||
if (starts_with(argv[i], "-m") ||
|
|
||||||
starts_with(argv[i], "--message="))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
usage_with_options(git_stash_usage, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argv_array_push(&args, "push");
|
argv_array_push(&args, "push");
|
||||||
argv_array_pushv(&args, argv);
|
argv_array_pushv(&args, argv);
|
||||||
return !!push_stash(args.argc, args.argv, prefix);
|
return !!push_stash(args.argc, args.argv, prefix, 1);
|
||||||
}
|
}
|
||||||
|
79
t/t3601-rm-pathspec-file.sh
Executable file
79
t/t3601-rm-pathspec-file.sh
Executable file
@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='rm --pathspec-from-file'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_tick
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
echo A >fileA.t &&
|
||||||
|
echo B >fileB.t &&
|
||||||
|
echo C >fileC.t &&
|
||||||
|
echo D >fileD.t &&
|
||||||
|
git add fileA.t fileB.t fileC.t fileD.t &&
|
||||||
|
git commit -m "files" &&
|
||||||
|
|
||||||
|
git tag checkpoint
|
||||||
|
'
|
||||||
|
|
||||||
|
restore_checkpoint () {
|
||||||
|
git reset --hard checkpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_expect () {
|
||||||
|
git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'simplest' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
D fileA.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo fileA.t | git rm --pathspec-from-file=- &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--pathspec-file-nul' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
D fileA.t
|
||||||
|
D fileB.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "fileA.t\0fileB.t\0" | git rm --pathspec-from-file=- --pathspec-file-nul &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'only touches what was listed' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
D fileB.t
|
||||||
|
D fileC.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "fileB.t\nfileC.t\n" | git rm --pathspec-from-file=- &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'error conditions' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
echo fileA.t >list &&
|
||||||
|
|
||||||
|
test_must_fail git rm --pathspec-from-file=list -- fileA.t 2>err &&
|
||||||
|
test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
|
||||||
|
|
||||||
|
test_must_fail git rm --pathspec-file-nul 2>err &&
|
||||||
|
test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err &&
|
||||||
|
|
||||||
|
>empty_list &&
|
||||||
|
test_must_fail git rm --pathspec-from-file=empty_list 2>err &&
|
||||||
|
test_i18ngrep -e "No pathspec was given. Which files should I remove?" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
@ -285,6 +285,11 @@ test_expect_success 'stash --no-keep-index' '
|
|||||||
test bar,bar2 = $(cat file),$(cat file2)
|
test bar,bar2 = $(cat file),$(cat file2)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'dont assume push with non-option args' '
|
||||||
|
test_must_fail git stash -q drop 2>err &&
|
||||||
|
test_i18ngrep -e "subcommand wasn'\''t specified; '\''push'\'' can'\''t be assumed due to unexpected token '\''drop'\''" err
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'stash --invalid-option' '
|
test_expect_success 'stash --invalid-option' '
|
||||||
echo bar5 >file &&
|
echo bar5 >file &&
|
||||||
echo bar6 >file2 &&
|
echo bar6 >file2 &&
|
||||||
|
100
t/t3909-stash-pathspec-file.sh
Executable file
100
t/t3909-stash-pathspec-file.sh
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='stash --pathspec-from-file'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_tick
|
||||||
|
|
||||||
|
test_expect_success setup '
|
||||||
|
>fileA.t &&
|
||||||
|
>fileB.t &&
|
||||||
|
>fileC.t &&
|
||||||
|
>fileD.t &&
|
||||||
|
git add fileA.t fileB.t fileC.t fileD.t &&
|
||||||
|
git commit -m "Files" &&
|
||||||
|
|
||||||
|
git tag checkpoint
|
||||||
|
'
|
||||||
|
|
||||||
|
restore_checkpoint () {
|
||||||
|
git reset --hard checkpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_expect () {
|
||||||
|
git stash show --name-status >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expect_success 'simplest' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
# More files are written to make sure that git didnt ignore
|
||||||
|
# --pathspec-from-file, stashing everything
|
||||||
|
echo A >fileA.t &&
|
||||||
|
echo B >fileB.t &&
|
||||||
|
echo C >fileC.t &&
|
||||||
|
echo D >fileD.t &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
M fileA.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo fileA.t | git stash push --pathspec-from-file=- &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--pathspec-file-nul' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
# More files are written to make sure that git didnt ignore
|
||||||
|
# --pathspec-from-file, stashing everything
|
||||||
|
echo A >fileA.t &&
|
||||||
|
echo B >fileB.t &&
|
||||||
|
echo C >fileC.t &&
|
||||||
|
echo D >fileD.t &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
M fileA.t
|
||||||
|
M fileB.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "fileA.t\0fileB.t\0" | git stash push --pathspec-from-file=- --pathspec-file-nul &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'only touches what was listed' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
|
||||||
|
# More files are written to make sure that git didnt ignore
|
||||||
|
# --pathspec-from-file, stashing everything
|
||||||
|
echo A >fileA.t &&
|
||||||
|
echo B >fileB.t &&
|
||||||
|
echo C >fileC.t &&
|
||||||
|
echo D >fileD.t &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
M fileB.t
|
||||||
|
M fileC.t
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "fileB.t\nfileC.t\n" | git stash push --pathspec-from-file=- &&
|
||||||
|
verify_expect
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'error conditions' '
|
||||||
|
restore_checkpoint &&
|
||||||
|
echo A >fileA.t &&
|
||||||
|
echo fileA.t >list &&
|
||||||
|
|
||||||
|
test_must_fail git stash push --pathspec-from-file=list --patch 2>err &&
|
||||||
|
test_i18ngrep -e "--pathspec-from-file is incompatible with --patch" err &&
|
||||||
|
|
||||||
|
test_must_fail git stash push --pathspec-from-file=list -- fileA.t 2>err &&
|
||||||
|
test_i18ngrep -e "--pathspec-from-file is incompatible with pathspec arguments" err &&
|
||||||
|
|
||||||
|
test_must_fail git stash push --pathspec-file-nul 2>err &&
|
||||||
|
test_i18ngrep -e "--pathspec-file-nul requires --pathspec-from-file" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
Loading…
Reference in New Issue
Block a user