Support --pathspec-from-file in rm, stash
cover Support --pathspec-from-file in rm, stash
This series continues the effort to support --pathspec-from-file in various git commands. Series already in master: [1][2]
Cc'ing Paul-Sebastian Ungureanu because I touched his git stash code.
[1] https://public-inbox.org/git/[email protected]/
[2] https://lore.kernel.org/git/[email protected]/
Alexandr Miloslavskiy (8):
doc: rm: synchronize <pathspec> description
rm: support the --pathspec-from-file option
doc: stash: split options from description (1)
doc: stash: split options from description (2)
doc: stash: document more options
doc: stash: synchronize <pathspec> description
stash: eliminate crude option parsing
stash push: support the --pathspec-from-file option
Documentation/git-rm.txt | 61 ++++++++++-------- Documentation/git-stash.txt | 111 +++++++++++++++++++++------------ builtin/rm.c | 28 +++++++-- builtin/stash.c | 79 ++++++++++++----------- t/t3601-rm-pathspec-file.sh | 79 +++++++++++++++++++++++ t/t3903-stash.sh | 5 ++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++++++++ 7 files changed, 353 insertions(+), 110 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh create mode 100755 t/t3909-stash-pathspec-file.sh
base-commit: d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-530%2FSyntevoAlex%2F%230207(git)_pathspec_from_file_3-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-530/SyntevoAlex/#0207(git)_pathspec_from_file_3-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/530
Signature · 1 line
gitgitgadget
PATCH 1/8 doc: rm: synchronize <pathspec> description
From: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Changed outdated descriptions to mention pathspec instead.
2) Added reference to 'linkgit:gitglossary[7]'.
3) Removed content that merely repeated gitglossary.
4) Merged the remainder of "discussion" into <patchspec>.
--- Documentation/git-rm.txt | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-)
Documentation/git-rm.txt +21 -29
@@ -8,16 +8,16 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... DESCRIPTION ----------- -Remove files from the index, or from the working tree and the index. -`git rm` will not remove a file from just your working directory. -(There is no option to remove a file only from the working tree -and yet keep it in the index; use `/bin/rm` if you want to do that.) -The files being removed have to be identical to the tip of the branch, -and no updates to their contents can be staged in the index, +Remove files matching pathspec from the index, or from the working tree +and the index. `git rm` will not remove a file from just your working +directory. (There is no option to remove a file only from the working +tree and yet keep it in the index; use `/bin/rm` if you want to do +that.) The files being removed have to be identical to the tip of the +branch, and no updates to their contents can be staged in the index, though that default behavior can be overridden with the `-f` option. When `--cached` is given, the staged content has to match either the tip of the branch or the file on disk,
@@ -26,15 +26,20 @@ allowing the file to be removed from just the index. OPTIONS ------- -<file>...:: - Files to remove. Fileglobs (e.g. `*.c`) can be given to - remove all matching files. If you want Git to expand - file glob characters, you may need to shell-escape them. - A leading directory name - (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be - given to remove all files in the directory, and recursively - all sub-directories, - but this requires the `-r` option to be explicitly given. +<pathspec>...:: + Files to remove. A leading directory name (e.g. `dir` to remove + `dir/file1` and `dir/file2`) can be given to remove all files in + the directory, and recursively all sub-directories, but this + requires the `-r` option to be explicitly given. ++ +The command removes only the paths that are known to Git. ++ +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:: --force::
@@ -69,19 +74,6 @@ OPTIONS for each file removed. This option suppresses that output. -DISCUSSION ----------- - -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 -------------------------------------------------------- There is no option for `git rm` to remove from the index only
Signature · 1 line
gitgitgadget
Re: [PATCH 1/8] doc: rm: synchronize <pathspec> description
"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
Quoted 9 lines · writes:
From: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to
git commit,git reset,git checkoutetc.1) Changed outdated descriptions to mention pathspec instead.
2) Added reference to 'linkgit:gitglossary[7]'.
3) Removed content that merely repeated gitglossary.
4) Merged the remainder of "discussion" into<patchspec>.
Thanks. Will queue.
PATCH 2/8 rm: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
if (!argc) block was adapted to work with --pathspec-from-file. For that, I also had to parse pathspec earlier. Now it happens before read_cache() / hold_locked_index() / setup_work_tree(), which sounds fine to me.
In case of empty pathspec, there is now a clear error message instead of showing usage. As a consequence, exit code has also changed. Judging from [1] it doesn't seem that showing usage in this case was important (according to commit message, it was to avoid segfault), and it doesn't fit into how other commands react to empty pathspec. Finally, the new error message is easier to understand.
[1] Commit 7612a1ef ("git-rm: honor -n flag" 2006-06-09)
--- Documentation/git-rm.txt | 17 +++++++- builtin/rm.c | 28 ++++++++++--- t/t3601-rm-pathspec-file.sh | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 7 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh
Documentation/git-rm.txt +16 -1
@@ -8,7 +8,9 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] + [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]] + [--] [<pathspec>...] DESCRIPTION -----------
@@ -73,6 +75,19 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7]. `git rm` normally outputs one line (in the form of an `rm` command) 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`. + +--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). + REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM --------------------------------------------------------
builtin/rm.c +22 -6
@@ -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 ignore_unmatch =0 ; +static int ignore_unmatch =0 , pathspec_file_nul =0 ; +static char *pathspec_from_file =NULL ;static struct option builtin_rm_options[] = {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 (0 ,"ignore-unmatch" , &ignore_unmatch,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(), };
@@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, builtin_rm_options, 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 (_ ("Nothing specified, nothing removed" ));if (!index_only)setup_work_tree ();
@@ -270,9 +289,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)if (read_cache () <0 )die (_ ("index file corrupt" )); -parse_pathspec (&pathspec,0 , -PATHSPEC_PREFER_CWD , - prefix, argv);refresh_index (&the_index,REFRESH_QUIET |REFRESH_UNMERGED , &pathspec,NULL ,NULL ); seen =xcalloc (pathspec.nr,1 );
t/t3601-rm-pathspec-file.sh new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH 2/8] rm: support the --pathspec-from-file option
"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
Quoted 9 lines · writes:
From: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
if (!argc)block was adapted to work with --pathspec-from-file. For that, I also had to parse pathspec earlier. Now it happens beforeread_cache()/hold_locked_index()/setup_work_tree(), which sounds fine to me.
That is not an explanation nor justification.
Quoted 2 lines
In case of empty pathspec, there is now a clear error message instead of showing usage.
Hmph, "git rm --pathspec-from-file=/dev/null" would say "nothing specified, nothing removed" and it makes perfect sense, but I am not sure "git rm" that gives the same message is better than the output by usage_with_options(builtin_rm_usage, builtin_rm_options).
Documentation/git-rm.txt git-rm - Remove files from the working tree and from the index · line 13
Quoted 4 lines
-'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]
Documentation/git-rm.txt +2
-0+ [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]] + [--] [<pathspec>...]
OK.
Documentation/git-rm.txt For more details, see the 'pathspec' entry in linkgit:gitglossary[7]. · line 90
Quoted 13 lines
+--pathspec-from-file=<file>::
Documentation/git-rm.txt +12
-0+ 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:: + Only meaningful with `--pathspec-from-file`. Pathspec elements are + separated with NUL character and all other characters are taken + literally (including newlines and quotes). +
OK.
builtin/rm.c static int check_local_mod(struct object_id *head, int index_only) · line 239
Quoted 11 lines
builtin/rm.c +2
-1@@ -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 ignore_unmatch =0 ; +static int ignore_unmatch =0 , pathspec_file_nul =0 ; +static char *pathspec_from_file =NULL ;
We may want to clean these "explicitly initialize to 0/NULL" up at some point. The clean-up itself would not be in the scope of this patch, of course, but not making it worse is something this patch can do to help.
Quoted 14 lines
builtin/rm.c +8
-2@@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, builtin_rm_options, 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" ));
builtin/rm.c int cmd_rm(int argc, const char **argv, const char *prefix) · line 282
Quoted 10 lines
builtin/rm.c +10
-0+ +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 (_ ("Nothing specified, nothing removed" ));
I wonder if doing these in this order instead would make more sense without making unnecessary behaviour change.
- parse the options (which would make pathspec_f_f available to us)
- if pathspec_f_f is given, call parse_pathspec_file()
- otherwise complain if pathspec_file_nul is set
- otherwise check argc and give the usage_with_options()
I dunno.
Thanks.
Re: [PATCH 2/8] rm: support the --pathspec-from-file option
Sorry for late reply, I was on vacation. Now I'm back and ready to continue :)
Thanks for your review!
Quoted 9 lines · Junio C Hamano
Quoted 7 lines
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
if (!argc)block was adapted to work with --pathspec-from-file. For that, I also had to parse pathspec earlier. Now it happens beforeread_cache()/hold_locked_index()/setup_work_tree(), which sounds fine to me.That is not an explanation nor justification.
I'm not exactly sure what are you suggesting. My best guess is that you want to remove "if (!argc) block was adapted" paragraph from commit message? I thought about it and it feels wrong to leave this change unexplained. Or are you suggesting to reword it? If so, please give a hint.
Quoted 7 lines
Quoted 2 lines
In case of empty pathspec, there is now a clear error message instead of showing usage.
Hmph, "git rm --pathspec-from-file=/dev/null" would say "nothing specified, nothing removed" and it makes perfect sense, but I am not sure "git rm" that gives the same message is better than the output by
usage_with_options(builtin_rm_usage, builtin_rm_options).
What feels wrong to me is when I make a mistake and git just slams me with usage, and then it's up to me to figure what could be wrong. I myself struggled to find a mistake a couple times (in similar cases, not in this specific one) and didn't like the experience.
This could be a lot worse when there's no mistake, just the file was empty - but you already agreed that showing a new error message is reasonable with '--pathspec-from-file'.
Still, without '--pathspec-from-file', it should still be better to point to a specific error rather then "here's usage and try to find a difference". I have reworded the error message in V2 in hopes that it will be less controversial.
If you still don't like it, I will change it to only show the new error with '--pathspec-from-file'.
Quoted 7 lines
builtin/rm.c static int check_local_mod(struct object_id *head, int index_only) · line 239
Quoted 2 lines
builtin/rm.c +2
-0+static int ignore_unmatch =0 , pathspec_file_nul =0 ; +static char *pathspec_from_file =NULL ;We may want to clean these "explicitly initialize to 0/NULL" up at some point. The clean-up itself would not be in the scope of this patch, of course, but not making it worse is something this patch can do to help.
Changed in V2.
Re: [PATCH 2/8] rm: support the --pathspec-from-file option
Quoted 9 lines · Alexandr Miloslavskiy
Sorry for late reply, I was on vacation. Now I'm back and ready to continue :)
Thanks for your review!
Quoted 3 lines · Junio C Hamano
Quoted 3 lines
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
if (!argc)block was adapted to work with --pathspec-from-file. For that, I also had to parse pathspec earlier. Now it happens beforeread_cache()/hold_locked_index()/setup_work_tree(), which sounds fine to me.That is not an explanation nor justification.
I'm not exactly sure what are you suggesting.
I expected that the proposed log message to explain and justify why a change (in behaviour, in design, etc.) is made. "There is this limitation" is not a justification---"because of such and such reasons, there is this limitation, otherwise such and such bad things happen" is.
Re: [PATCH 2/8] rm: support the --pathspec-from-file option
Quoted 5 lines · Junio C Hamano
I expected that the proposed log message to explain and justify why a change (in behaviour, in design, etc.) is made. "There is this limitation" is not a justification---"because of such and such reasons, there is this limitation, otherwise such and such bad things happen" is.
I have rewritten the commit message in V3. Is that better?
PATCH 3/8 doc: stash: split options from description (1)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch moves blocks of text as-is to make it easier to review the next patch.
--- Documentation/git-stash.txt | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-)
Documentation/git-stash.txt +35 -33
@@ -58,31 +58,6 @@ non-option arguments are not allowed to prevent a misspelled 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, 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>]::
@@ -128,14 +103,6 @@ pop [--index] [-q|--quiet] [<stash>]:: 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 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>]::
@@ -185,6 +152,41 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. +If the `--all` option is used instead then the +ignored files are stashed and cleaned in addition to the untracked files. + +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 `--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). + +If the `--keep-index` option is used, all changes already added to the +index are left intact. + +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. + +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. + +When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must +be a reference of the form `stash@{<revision>}`. + DISCUSSION ----------
Signature · 1 line
gitgitgadget
PATCH 4/8 doc: stash: split options from description (2)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Together with the previous patch, this brings docs for git stash to the common layout used for most other commands (see for example docs for git add, git commit, git checkout, git reset) where all options are documented in a separate list.
I have decided to use alphabetical sorting in the list of options. Other docs often sort in order of appearance or order of importance, but in this case it wouldn't be easy to read the list where options from multiple sub-commands are mixed together.
There is some text editing done to make old descriptions better fit into the list-style format.
--- Documentation/git-stash.txt | 72 ++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 32 deletions(-)
Documentation/git-stash.txt +40 -32
@@ -43,9 +43,6 @@ 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 stash index (e.g. the integer `n` is equivalent to `stash@{n}`). -OPTIONS -------- - push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]:: Save your local modifications to a new 'stash entry' and roll them
@@ -152,40 +149,51 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. -If the `--all` option is used instead then the -ignored files are stashed and cleaned in addition to the untracked files. - -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 `--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). - -If the `--keep-index` option is used, all changes already added to the -index are left intact. - -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. +OPTIONS +------- +-a:: +--all:: + All ignored and untracked files are also stashed and then cleaned + up with `git clean`. + +-u:: +--include-untracked:: + All untracked files are also stashed and then cleaned up with + `git clean`. + +--index:: + 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:: + All changes already added to the index are left intact. + +-p:: +--patch:: + 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. -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. +<pathspec>...:: + 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. -When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must -be a reference of the form `stash@{<revision>}`. +<stash>:: + A reference of the form `stash@{<revision>}`. When no `<stash>` is + given, the latest stash is assumed (that is, `stash@{0}`). DISCUSSION ----------
Signature · 1 line
gitgitgadget
Re: [PATCH 4/8] doc: stash: split options from description (2)
Quoted 62 lines
Documentation/git-stash.txt +22
-25@@ -43,9 +43,6 @@ 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 stash index (e.g. the integer `n` is equivalent to `stash@{n}`). -OPTIONS -------- - push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]:: Save your local modifications to a new 'stash entry' and roll them@@ -152,40 +149,51 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. -If the `--all` option is used instead then the -ignored files are stashed and cleaned in addition to the untracked files. - -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 `--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). - -If the `--keep-index` option is used, all changes already added to the -index are left intact. - -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. +OPTIONS +------- +-a:: +--all:: + All ignored and untracked files are also stashed and then cleaned + up with `git clean`. + +-u:: +--include-untracked:: + All untracked files are also stashed and then cleaned up with + `git clean`. + +--index:: + 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:: + All changes already added to the index are left intact.
Documentation/git-stash.txt store:: · line 183
Quoted 10 lines
Documentation/git-stash.txt +10
-0+ +-p:: +--patch:: + 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.
I have a mixed feelings about this approach. While I am sympathetic to the "have a single place to describe all" approach this patch takes, the approach needs to be executed with care when subcommands do not share much of the options at all. Those readers who jump to the "OPTIONS" section and try to ignore anything outside the section may not easily notice that --keep-index only applies to subcommands that creates a new stash, and meaningless to subcommands that lets you inspect existing stashes, or apply one to the working tree (and optionally to the index), for example. If the orinal documentation did not use "OPTIONS" as the section header and instead said perhaps "SUBCOMMANDS", it would have been even better, but otherwise I would suspect that the original "the options understood by 'push' are all described under the part that begins with 'push [-p] [-k] ...' command line" arrangement was much easier to understand when reading them through for the first time to learn and also to find what the user is looking for after learning the "concept" (e.g. "with 'stash', there is a way to stash-away the changes made to the working tree") but before becoming familiar with exact set of options for each subcommand (e.g. "and there was an option that let me stash only partial changes piecemeal, but what was it spelled?").
If we were to make the result of "a single place to describe all" approach anything useful, I think at least
(1) the list itself should make it clear that it does not talk about options related to listing and showing at all, before enumerating dashed options.
(2) each item in the enumeration should identify which subcommand(s) accept(s) it.
So, I dunno.
Re: [PATCH 4/8] doc: stash: split options from description (2)
Quoted 24 lines · Junio C Hamano
I have a mixed feelings about this approach. While I am sympathetic to the "have a single place to describe all" approach this patch takes, the approach needs to be executed with care when subcommands do not share much of the options at all. Those readers who jump to the "OPTIONS" section and try to ignore anything outside the section may not easily notice that --keep-index only applies to subcommands that creates a new stash, and meaningless to subcommands that lets you inspect existing stashes, or apply one to the working tree (and optionally to the index), for example. If the orinal documentation did not use "OPTIONS" as the section header and instead said perhaps "SUBCOMMANDS", it would have been even better, but otherwise I would suspect that the original "the options understood by 'push' are all described under the part that begins with 'push [-p] [-k] ...' command line" arrangement was much easier to understand when reading them through for the first time to learn and also to find what the user is looking for after learning the "concept" (e.g. "with 'stash', there is a way to stash-away the changes made to the working tree") but before becoming familiar with exact set of options for each subcommand (e.g. "and there was an option that let me stash only partial changes piecemeal, but what was it spelled?").
If we were to make the result of "a single place to describe all" approach anything useful, I think at least
Quoted 8 lines
(1) the list itself should make it clear that it does not talk about options related to listing and showing at all, before enumerating dashed options.
(2) each item in the enumeration should identify which subcommand(s) accept(s) it.
So, I dunno.
I have updated the patch with (2). Sorry, I didn't understand what you mean in (1).
I have included my reasoning in commit message. If you feel against this change, I guess I'll just revert it. Afterall, my only goal was to describe new options. Tried to change things because I didn't like how this doc goes against the layout I have seen in all previous docs I edited.
PATCH 5/8 doc: stash: document more options
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
--- Documentation/git-stash.txt | 7 +++++++ 1 file changed, 7 insertions(+)
Documentation/git-stash.txt +7 -0
@@ -185,6 +185,13 @@ OPTIONS The `--patch` option implies `--keep-index`. You can use `--no-keep-index` to override this. +-q:: +--quiet:: + Quiet, suppress feedback messages. + +\--:: + Separates pathspec from options for disambiguation purposes. + <pathspec>...:: The new stash entry records the modified states only for the files that match the pathspec. The index entries and working tree files
Signature · 1 line
gitgitgadget
Re: [PATCH 5/8] doc: stash: document more options
"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
Documentation/git-stash.txt OPTIONS · line 197
Quoted 10 lines · writes:
+-q:: +--quiet::Documentation/git-stash.txt +5
-0+ Quiet, suppress feedback messages. + +\--:: + Separates pathspec from options for disambiguation purposes. + <pathspec>...:: The new stash entry records the modified states only for the files that match the pathspec. The index entries and working tree files
OK. Describing these in the documentation is a good thing. How they should be added depends on in what shape the patch 4/8 should settle, though.
Thanks.
PATCH 6/8 doc: stash: synchronize <pathspec> description
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Added reference to 'linkgit:gitglossary[7]'.
2) Fixed mentions of incorrectly plural "pathspecs".
--- Documentation/git-stash.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Documentation/git-stash.txt +4 -2
@@ -53,13 +53,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, non-option arguments are not allowed to prevent a misspelled 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. 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 - 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 message.
@@ -197,6 +197,8 @@ The `--patch` option implies `--keep-index`. You can use 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>:: A reference of the form `stash@{<revision>}`. When no `<stash>` is
Signature · 1 line
gitgitgadget
Re: [PATCH 6/8] doc: stash: synchronize <pathspec> description
"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
Quoted 4 lines · writes:
From: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to
git commit,git reset,git checkoutetc.
Makes sense.
PATCH 7/8 stash: eliminate crude option parsing
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Eliminate crude option parsing and rely on real parsing instead, because
1) Crude parsing is crude, for example it's not capable of handling things like git stash -m Message
2) Adding options in two places is inconvenient and prone to bugs
As a side result, the case of git stash -m Message gets fixed. Also give a good error message instead of just throwing usage at user.
----
Some review of what's been happening to this code:
Before [1], git-stash.sh only verified that all args begin with - :
# The default command is "push" if nothing but options are given seen_non_option= for opt do case "$opt" in --) break ;; -*) ;; *) seen_non_option=t; break ;; esac done
Later, [1] introduced the duplicate code I'm now removing, also making the previous test more strict by white-listing options.
----
[1] Commit 40af1468 ("stash: convert stash--helper.c into stash.c" 2019-02-26)
--- builtin/stash.c | 59 +++++++++++++++++------------------------------- t/t3903-stash.sh | 5 ++++ 2 files changed, 26 insertions(+), 38 deletions(-)
builtin/stash.c +21 -38
@@ -1448,8 +1448,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int qreturn 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 patch_mode =0 ;int include_untracked =0 ;
@@ -1471,10 +1473,22 @@ static int push_stash(int argc, const char **argv, const char *prefix) OPT_END() }; -if (argc) +if (argc) { + force_assume = !strcmp (argv[0 ],"-p" ); argc =parse_options (argc, argv, prefix, options, 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 , prefix, argv);
@@ -1547,7 +1561,6 @@ static int use_builtin_stash(void)int cmd_stash (int argc,const char **argv,const char *prefix) { -int i =-1 ;pid_t pid =getpid ();const char *index_file;struct argv_array args =ARGV_ARRAY_INIT ;
@@ -1580,7 +1593,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix) (uintmax_t)pid);if (!argc) -return !!push_stash (0 ,NULL , prefix); +return !!push_stash (0 ,NULL , prefix,0 );else if (!strcmp (argv[0 ],"apply" ))return !!apply_stash (argc, argv, prefix);else if (!strcmp (argv[0 ],"clear" ))
@@ -1600,45 +1613,15 @@ int cmd_stash(int argc, const char **argv, const char *prefix)else if (!strcmp (argv[0 ],"create" ))return !!create_stash (argc, argv, prefix);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" ))return !!save_stash (argc, argv, prefix);else if (*argv[0 ] !='-' )usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv[0 ]), git_stash_usage, options); -if (strcmp (argv[0 ],"-p" )) { -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); - } - } - +/* Assume 'stash push' */ argv_array_push (&args,"push" );argv_array_pushv (&args, argv); -return !!push_stash (args.argc, args.argv, prefix); +return !!push_stash (args.argc, args.argv, prefix,1 ); }
t/t3903-stash.sh +5 -0
@@ -285,6 +285,11 @@ test_expect_success 'stash --no-keep-index' ' 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' ' echo bar5 >file && echo bar6 >file2 &&
Signature · 1 line
gitgitgadget
PATCH 8/8 stash push: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) For now, --pathspec-from-file is declared incompatible with --patch, even when <file> is not -. Such use case is not really expected.
2) It is not allowed to pass pathspec in both args and file.
--- Documentation/git-stash.txt | 16 +++++- builtin/stash.c | 20 +++++++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100755 t/t3909-stash-pathspec-file.sh
Documentation/git-stash.txt +15 -1
@@ -15,6 +15,7 @@ SYNOPSIS 'git stash' branch <branchname> [<stash>] 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [-m|--message <message>] + [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]] 'git stash' clear 'git stash' create [<message>]
@@ -43,7 +44,7 @@ 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 stash index (e.g. the integer `n` is equivalent to `stash@{n}`). -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 back to HEAD (in the working tree and in the index).
@@ -185,6 +186,19 @@ OPTIONS The `--patch` option implies `--keep-index`. You can use `--no-keep-index` to override this. +--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`. + +--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). + -q:: --quiet:: Quiet, suppress feedback messages.
builtin/stash.c +20 -0
@@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {N_ ("git stash clear" ),N_ ("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n" +" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" " [--] [<pathspec>...]]" ),N_ ("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [<message>]"),
@@ -1456,7 +1457,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,int patch_mode =0 ;int include_untracked =0 ;int quiet =0 ; +int pathspec_file_nul =0 ;const char *stash_msg =NULL ; +const char *pathspec_from_file =NULL ;struct pathspec ps;struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index,
@@ -1470,6 +1473,8 @@ static int push_stash(int argc, const char **argv, const char *prefix, N_("include ignore files"), 2),OPT_STRING ('m' ,"message" , &stash_msg,N_ ("message" ),N_ ("stash message" )), +OPT_PATHSPEC_FROM_FILE (&pathspec_from_file), +OPT_PATHSPEC_FILE_NUL (&pathspec_file_nul), OPT_END() };
@@ -1492,6 +1497,21 @@ static int push_stash(int argc, const char **argv, const char *prefix,parse_pathspec (&ps,0 ,PATHSPEC_PREFER_FULL |PATHSPEC_PREFIX_ORIGIN , 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, include_untracked); }
t/t3909-stash-pathspec-file.sh new file +100 -0
100 lines not on this page · raw message
Signature · 1 line
gitgitgadget
v2 cover Support --pathspec-from-file in rm, stash
In reply to Alexandr Miloslavskiy via GitGitGadgetChanges since V1
------------------
Some polishing based on code review in V1
1) Improved error message for the case where pathspec is not given to git rm
2) Removed explicit variable initialization to 0 / NULL
3) Polishing in docs for git stash
------------------
This series continues the effort to support --pathspec-from-file in various git commands. Series already in master: [1][2]
Cc'ing Paul-Sebastian Ungureanu because I touched his git stash code.
[1] https://public-inbox.org/git/[email protected]/
[2] https://lore.kernel.org/git/[email protected]/
Alexandr Miloslavskiy (8):
doc: rm: synchronize <pathspec> description
rm: support the --pathspec-from-file option
doc: stash: split options from description (1)
doc: stash: split options from description (2)
doc: stash: document more options
doc: stash: synchronize <pathspec> description
stash: eliminate crude option parsing
stash push: support the --pathspec-from-file option
Documentation/git-rm.txt | 61 +++++++------- Documentation/git-stash.txt | 144 +++++++++++++++++++++++---------- builtin/rm.c | 28 +++++-- builtin/stash.c | 79 +++++++++--------- t/t3601-rm-pathspec-file.sh | 79 ++++++++++++++++++ t/t3903-stash.sh | 5 ++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++ 7 files changed, 381 insertions(+), 115 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh create mode 100755 t/t3909-stash-pathspec-file.sh
base-commit: de93cc14ab7e8db7645d8dbe4fd2603f76d5851f
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-530%2FSyntevoAlex%2F%230207(git)_pathspec_from_file_3-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-530/SyntevoAlex/#0207(git)_pathspec_from_file_3-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/530
Range-diff vs v1:
1: 23387f8391 = 1: 2e8c8ad815 doc: rm: synchronize <pathspec> description
2: 5611e3ae32 ! 2: 7ccbab52e5 rm: support the --pathspec-from-file option
@@ -64,8 +64,8 @@
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 = 0;
-+static char *pathspec_from_file = NULL;
++static int ignore_unmatch = 0, pathspec_file_nul;
++static char *pathspec_from_file;
static struct option builtin_rm_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
@@ -101,7 +101,7 @@
+ }
+
+ if (!pathspec.nr)
-+ die(_("Nothing specified, nothing removed"));
++ die(_("No pathspec was given. Which files should I remove?"));
if (!index_only)
setup_work_tree();
@@ -196,7 +196,7 @@
+
+ >empty_list &&
+ test_must_fail git rm --pathspec-from-file=empty_list 2>err &&
-+ test_i18ngrep -e "Nothing specified, nothing removed" err
++ test_i18ngrep -e "No pathspec was given. Which files should I remove?" err
+'
+
+test_done
3: 0824bba210 = 3: 8c212fc0ed doc: stash: split options from description (1)
4: 708363241f ! 4: db3a96720c doc: stash: split options from description (2) @@ -3,17 +3,28 @@
doc: stash: split options from description (2)
Together with the previous patch, this brings docs for git stash to
- the common layout used for most other commands (see for example docs for
- git add, git commit, git checkout, git reset) where all options
- are documented in a separate list.
+ the common layout used for most other commands (see for example docs
+ for git add, git commit, git checkout, git reset) where all
+ options are documented in a separate list.
- I have decided to use alphabetical sorting in the list of options. Other
- docs often sort in order of appearance or order of importance, but in
- this case it wouldn't be easy to read the list where options from
- multiple sub-commands are mixed together.
+ After some thinking and having a look at docs for git svn and
+ git submodule`, I have arrived at following conclusions:
+ * Options should be described in a list rather then text to
+ facilitate lookup for user.
+ * Single list is better then multiple lists because it avoids
+ copy&pasting descriptions between subcommands (or, without
+ copy&pasting, user will have to look up missing options in other
+ subcommands).
+ * As a consequence, commands section should only give brief info and
+ list possible options. Since options have good enough names, user
+ will only need to look up the "interesting" options.
+ * Every option should list which subcommands support it.
- There is some text editing done to make old descriptions better fit into
- the list-style format.
+ I have decided to use alphabetical sorting in the list of options to
+ facilitate lookup for user.
+
+ There is some text editing done to make old descriptions better fit
+ into the list-style format.
@@ -26,10 +37,40 @@
-OPTIONS
--------
--
++COMMANDS
++--------
+
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
- Save your local modifications to a new 'stash entry' and roll them
+@@
+
+ 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
+- created. When no <stash> is given, it shows the latest one.
++ created.
+ 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}
+ to view the second most recent entry in patch form).
+@@
+ the commit at which the <stash> was originally created, applies the
+ changes recorded in <stash> to the new working tree and index.
+ If that succeeds, and <stash> is a reference of the form
+- stash@{<revision>}, it then drops the <stash>. When no <stash>
+- is given, applies the latest one.
++ stash@{<revision>}, it then drops the <stash>.
+ +
+ 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 +@@
+ drop [-q|--quiet] [<stash>]::
+
+ 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::
+
@@
reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above.
@@ -40,15 +81,43 @@
-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.
--
++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.
+
-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).
--
++-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.
+
-If the --keep-index option is used, all changes already added to the -index are left intact.
--
++--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.
+
-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
@@ -56,38 +125,17 @@
-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.
-+OPTIONS
-+-------
-+-a::
-+--all::
-+ All ignored and untracked files are also stashed and then cleaned
-+ up with git clean.
-+
-+-u::
-+--include-untracked::
-+ All untracked files are also stashed and then cleaned up with
-+ git clean.
-+
-+--index::
-+ 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::
-+ All changes already added to the index are left intact.
-+
+-p::
+--patch::
-+ 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.
++ 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.
@@ -97,17 +145,23 @@
-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.
-+<pathspec>...::
-+ 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.
-
+-
-When no <stash> is given, stash@{0} is assumed, otherwise <stash> must -be a reference of the form stash@{<revision>}.
++<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.
++
+<stash>::
-+ A reference of the form stash@{<revision>}. When no <stash> is
-+ given, the latest stash is assumed (that is, stash@{0}).
++ 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
----------
5: 8a5f2dbe9e ! 5: f91ec08b47 doc: stash: document more options
@@ -13,11 +13,16 @@
+-q::
+--quiet::
-+ Quiet, suppress feedback messages.
++ This option is only valid for apply, drop, pop, push,
++ save, store commands.
+++
++Quiet, suppress feedback messages.
+
+\--::
-+ Separates pathspec from options for disambiguation purposes.
++ This option is only valid for push command.
+++
++Separates pathspec from options for disambiguation purposes.
+
<pathspec>...::
- The new stash entry records the modified states only for the files
- that match the pathspec. The index entries and working tree files
+ This option is only valid for push command.
+ +
6: 5e17a0c470 ! 6: 04e2fd5865 doc: stash: synchronize <pathspec> description
@@ -30,11 +30,11 @@
message.
@@
- 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.
+ 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>::
- A reference of the form stash@{<revision>}. When no <stash> is
+ This option is only valid for apply, branch, drop, pop,
7: 7a8d36d49f = 7: 0558cbbe38 stash: eliminate crude option parsing 8: 721410233b ! 8: 0c6f28dc68 stash push: support the --pathspec-from-file option
@@ -22,8 +22,8 @@
'git stash' clear
'git stash' create [<message>]
@@
- is also possible). Stashes may also be referenced by specifying just the
- stash index (e.g. the integer n is equivalent to stash@{n}).
+ 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>...]::
@@ -35,21 +35,25 @@
--no-keep-index to override this.
+--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.
++ 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::
-+ Only meaningful with --pathspec-from-file. Pathspec elements are
-+ separated with NUL character and all other characters are taken
-+ literally (including newlines and quotes).
++ 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::
- Quiet, suppress feedback messages.
+ This option is only valid for apply, drop, pop, push,
diff --git a/builtin/stash.c b/builtin/stash.c --- a/builtin/stash.c
Signature · 1 line
gitgitgadget
PATCH v2 1/8 doc: rm: synchronize <pathspec> description
From: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Changed outdated descriptions to mention pathspec instead.
2) Added reference to 'linkgit:gitglossary[7]'.
3) Removed content that merely repeated gitglossary.
4) Merged the remainder of "discussion" into <patchspec>.
--- Documentation/git-rm.txt | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-)
Documentation/git-rm.txt +21 -29
@@ -8,16 +8,16 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... DESCRIPTION ----------- -Remove files from the index, or from the working tree and the index. -`git rm` will not remove a file from just your working directory. -(There is no option to remove a file only from the working tree -and yet keep it in the index; use `/bin/rm` if you want to do that.) -The files being removed have to be identical to the tip of the branch, -and no updates to their contents can be staged in the index, +Remove files matching pathspec from the index, or from the working tree +and the index. `git rm` will not remove a file from just your working +directory. (There is no option to remove a file only from the working +tree and yet keep it in the index; use `/bin/rm` if you want to do +that.) The files being removed have to be identical to the tip of the +branch, and no updates to their contents can be staged in the index, though that default behavior can be overridden with the `-f` option. When `--cached` is given, the staged content has to match either the tip of the branch or the file on disk,
@@ -26,15 +26,20 @@ allowing the file to be removed from just the index. OPTIONS ------- -<file>...:: - Files to remove. Fileglobs (e.g. `*.c`) can be given to - remove all matching files. If you want Git to expand - file glob characters, you may need to shell-escape them. - A leading directory name - (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be - given to remove all files in the directory, and recursively - all sub-directories, - but this requires the `-r` option to be explicitly given. +<pathspec>...:: + Files to remove. A leading directory name (e.g. `dir` to remove + `dir/file1` and `dir/file2`) can be given to remove all files in + the directory, and recursively all sub-directories, but this + requires the `-r` option to be explicitly given. ++ +The command removes only the paths that are known to Git. ++ +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:: --force::
@@ -69,19 +74,6 @@ OPTIONS for each file removed. This option suppresses that output. -DISCUSSION ----------- - -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 -------------------------------------------------------- There is no option for `git rm` to remove from the index only
Signature · 1 line
gitgitgadget
PATCH v2 2/8 rm: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
if (!argc) block was adapted to work with --pathspec-from-file. For that, I also had to parse pathspec earlier. Now it happens before read_cache() / hold_locked_index() / setup_work_tree(), which sounds fine to me.
In case of empty pathspec, there is now a clear error message instead of showing usage. As a consequence, exit code has also changed. Judging from [1] it doesn't seem that showing usage in this case was important (according to commit message, it was to avoid segfault), and it doesn't fit into how other commands react to empty pathspec. Finally, the new error message is easier to understand.
[1] Commit 7612a1ef ("git-rm: honor -n flag" 2006-06-09)
--- Documentation/git-rm.txt | 17 +++++++- builtin/rm.c | 28 ++++++++++--- t/t3601-rm-pathspec-file.sh | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 7 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh
Documentation/git-rm.txt +16 -1
@@ -8,7 +8,9 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] + [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]] + [--] [<pathspec>...] DESCRIPTION -----------
@@ -73,6 +75,19 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7]. `git rm` normally outputs one line (in the form of an `rm` command) 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`. + +--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). + REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM --------------------------------------------------------
builtin/rm.c +22 -6
@@ -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 ignore_unmatch =0 ; +static int ignore_unmatch =0 , pathspec_file_nul; +static char *pathspec_from_file;static struct option builtin_rm_options[] = {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 (0 ,"ignore-unmatch" , &ignore_unmatch,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(), };
@@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, builtin_rm_options, 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)setup_work_tree ();
@@ -270,9 +289,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)if (read_cache () <0 )die (_ ("index file corrupt" )); -parse_pathspec (&pathspec,0 , -PATHSPEC_PREFER_CWD , - prefix, argv);refresh_index (&the_index,REFRESH_QUIET |REFRESH_UNMERGED , &pathspec,NULL ,NULL ); seen =xcalloc (pathspec.nr,1 );
t/t3601-rm-pathspec-file.sh new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH v2 2/8] rm: support the --pathspec-from-file option
"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
Quoted 12 lines · writes:
t/t3601-rm-pathspec-file.sh new file +6
-0@@ -0,0 +1,79 @@ +#!/bin/sh + +test_description='rm --pathspec-from-file' + +. ./test-lib.sh +
t/t3601-rm-pathspec-file.sh line 16
Quoted 10 lines
t/t3601-rm-pathspec-file.sh new file +10
-0+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" && +
Trailing whitespace on this line.
t/t3601-rm-pathspec-file.sh line 73
Quoted 13 lines
t/t3601-rm-pathspec-file.sh new file +13
-0+ git tag checkpoint +' + ... +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 && +
And here too.
Quoted 6 lines
t/t3601-rm-pathspec-file.sh new file +6
-0+ >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
Re: [PATCH v2 2/8] rm: support the --pathspec-from-file option
Quoted 1 line · Junio C Hamano
Trailing whitespace on this line.
Whitespaces fixed in V3; I have also activated pre-commit hook. Sorry!
Re: [PATCH v2 2/8] rm: support the --pathspec-from-file option
Quoted 4 lines · Alexandr Miloslavskiy
Quoted 1 line · Junio C Hamano
Trailing whitespace on this line.
Whitespaces fixed in V3; I have also activated pre-commit hook. Sorry!
I may not have time to read it over at least in a few days, but lack if v3 in the title will make it cumbersome to come back to the thread later X-<. Thanks for a heads-up, anyway, thoguh.
Re: [PATCH v2 2/8] rm: support the --pathspec-from-file option
Quoted 2 lines · Junio C Hamano
I may not have time to read it over at least in a few days, but lack if v3 in the title will make it cumbersome to come back ...
Oops, please disregard. I must have been looking at some wrong thread.
PATCH v2 3/8 doc: stash: split options from description (1)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch moves blocks of text as-is to make it easier to review the next patch.
--- Documentation/git-stash.txt | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-)
Documentation/git-stash.txt +35 -33
@@ -58,31 +58,6 @@ non-option arguments are not allowed to prevent a misspelled 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, 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>]::
@@ -128,14 +103,6 @@ pop [--index] [-q|--quiet] [<stash>]:: 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 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>]::
@@ -185,6 +152,41 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. +If the `--all` option is used instead then the +ignored files are stashed and cleaned in addition to the untracked files. + +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 `--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). + +If the `--keep-index` option is used, all changes already added to the +index are left intact. + +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. + +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. + +When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must +be a reference of the form `stash@{<revision>}`. + DISCUSSION ----------
Signature · 1 line
gitgitgadget
PATCH v2 4/8 doc: stash: split options from description (2)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Together with the previous patch, this brings docs for git stash to the common layout used for most other commands (see for example docs for git add, git commit, git checkout, git reset) where all options are documented in a separate list.
After some thinking and having a look at docs for git svn and git submodule`, I have arrived at following conclusions:
* Options should be described in a list rather then text to facilitate lookup for user.
* Single list is better then multiple lists because it avoids copy&pasting descriptions between subcommands (or, without copy&pasting, user will have to look up missing options in other subcommands).
* As a consequence, commands section should only give brief info and list possible options. Since options have good enough names, user will only need to look up the "interesting" options.
* Every option should list which subcommands support it.
I have decided to use alphabetical sorting in the list of options to facilitate lookup for user.
There is some text editing done to make old descriptions better fit into the list-style format.
--- Documentation/git-stash.txt | 92 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 35 deletions(-)
Documentation/git-stash.txt +57 -35
@@ -43,8 +43,8 @@ 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 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>...]::
@@ -86,7 +86,7 @@ show [<options>] [<stash>]:: 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 - created. When no `<stash>` is given, it shows the latest one. + created. 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}` to view the second most recent entry in patch form).
@@ -116,8 +116,7 @@ branch <branchname> [<stash>]:: the commit at which the `<stash>` was originally created, applies the changes recorded in `<stash>` to the new working tree and index. If that succeeds, and `<stash>` is a reference of the form - `stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>` - is given, applies the latest one. + `stash@{<revision>}`, it then drops the `<stash>`. + 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
@@ -133,9 +132,6 @@ clear:: drop [-q|--quiet] [<stash>]:: 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::
@@ -152,40 +148,66 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. -If the `--all` option is used instead then the -ignored files are stashed and cleaned in addition to the untracked files. - -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. +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`. -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). +-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`. -If the `--keep-index` option is used, all changes already added to the -index are left intact. +--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. -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. +-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. -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. - -When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must -be a reference of the form `stash@{<revision>}`. +<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. + +<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 ----------
Signature · 1 line
gitgitgadget
PATCH v2 5/8 doc: stash: document more options
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
--- Documentation/git-stash.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Documentation/git-stash.txt +12 -0
@@ -194,6 +194,18 @@ to learn how to operate the `--patch` mode. The `--patch` option implies `--keep-index`. You can use `--no-keep-index` to override this. +-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. +
Signature · 1 line
gitgitgadget
PATCH v2 6/8 doc: stash: synchronize <pathspec> description
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Added reference to 'linkgit:gitglossary[7]'.
2) Fixed mentions of incorrectly plural "pathspecs".
--- Documentation/git-stash.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Documentation/git-stash.txt +4 -2
@@ -56,13 +56,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, non-option arguments are not allowed to prevent a misspelled 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. 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 - 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 message.
@@ -213,6 +213,8 @@ 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`,
Signature · 1 line
gitgitgadget
PATCH v2 7/8 stash: eliminate crude option parsing
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Eliminate crude option parsing and rely on real parsing instead, because
1) Crude parsing is crude, for example it's not capable of handling things like git stash -m Message
2) Adding options in two places is inconvenient and prone to bugs
As a side result, the case of git stash -m Message gets fixed. Also give a good error message instead of just throwing usage at user.
----
Some review of what's been happening to this code:
Before [1], git-stash.sh only verified that all args begin with - :
# The default command is "push" if nothing but options are given seen_non_option= for opt do case "$opt" in --) break ;; -*) ;; *) seen_non_option=t; break ;; esac done
Later, [1] introduced the duplicate code I'm now removing, also making the previous test more strict by white-listing options.
----
[1] Commit 40af1468 ("stash: convert stash--helper.c into stash.c" 2019-02-26)
--- builtin/stash.c | 59 +++++++++++++++++------------------------------- t/t3903-stash.sh | 5 ++++ 2 files changed, 26 insertions(+), 38 deletions(-)
builtin/stash.c +21 -38
@@ -1451,8 +1451,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int qreturn 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 patch_mode =0 ;int include_untracked =0 ;
@@ -1474,10 +1476,22 @@ static int push_stash(int argc, const char **argv, const char *prefix) OPT_END() }; -if (argc) +if (argc) { + force_assume = !strcmp (argv[0 ],"-p" ); argc =parse_options (argc, argv, prefix, options, 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 , prefix, argv);
@@ -1550,7 +1564,6 @@ static int use_builtin_stash(void)int cmd_stash (int argc,const char **argv,const char *prefix) { -int i =-1 ;pid_t pid =getpid ();const char *index_file;struct argv_array args =ARGV_ARRAY_INIT ;
@@ -1583,7 +1596,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix) (uintmax_t)pid);if (!argc) -return !!push_stash (0 ,NULL , prefix); +return !!push_stash (0 ,NULL , prefix,0 );else if (!strcmp (argv[0 ],"apply" ))return !!apply_stash (argc, argv, prefix);else if (!strcmp (argv[0 ],"clear" ))
@@ -1603,45 +1616,15 @@ int cmd_stash(int argc, const char **argv, const char *prefix)else if (!strcmp (argv[0 ],"create" ))return !!create_stash (argc, argv, prefix);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" ))return !!save_stash (argc, argv, prefix);else if (*argv[0 ] !='-' )usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv[0 ]), git_stash_usage, options); -if (strcmp (argv[0 ],"-p" )) { -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); - } - } - +/* Assume 'stash push' */ argv_array_push (&args,"push" );argv_array_pushv (&args, argv); -return !!push_stash (args.argc, args.argv, prefix); +return !!push_stash (args.argc, args.argv, prefix,1 ); }
t/t3903-stash.sh +5 -0
@@ -285,6 +285,11 @@ test_expect_success 'stash --no-keep-index' ' 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' ' echo bar5 >file && echo bar6 >file2 &&
Signature · 1 line
gitgitgadget
PATCH v2 8/8 stash push: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) For now, --pathspec-from-file is declared incompatible with --patch, even when <file> is not -. Such use case is not really expected.
2) It is not allowed to pass pathspec in both args and file.
--- Documentation/git-stash.txt | 20 ++++++- builtin/stash.c | 20 +++++++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100755 t/t3909-stash-pathspec-file.sh
Documentation/git-stash.txt +19 -1
@@ -15,6 +15,7 @@ SYNOPSIS 'git stash' branch <branchname> [<stash>] 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [-m|--message <message>] + [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]] 'git stash' clear 'git stash' create [<message>]
@@ -46,7 +47,7 @@ stash index (e.g. the integer `n` is equivalent to `stash@{n}`). 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 back to HEAD (in the working tree and in the index).
@@ -194,6 +195,23 @@ 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`,
builtin/stash.c +20 -0
@@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {N_ ("git stash clear" ),N_ ("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n" +" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" " [--] [<pathspec>...]]" ),N_ ("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [<message>]"),
@@ -1459,7 +1460,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,int patch_mode =0 ;int include_untracked =0 ;int quiet =0 ; +int pathspec_file_nul =0 ;const char *stash_msg =NULL ; +const char *pathspec_from_file =NULL ;struct pathspec ps;struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index,
@@ -1473,6 +1476,8 @@ static int push_stash(int argc, const char **argv, const char *prefix, N_("include ignore files"), 2),OPT_STRING ('m' ,"message" , &stash_msg,N_ ("message" ),N_ ("stash message" )), +OPT_PATHSPEC_FROM_FILE (&pathspec_from_file), +OPT_PATHSPEC_FILE_NUL (&pathspec_file_nul), OPT_END() };
@@ -1495,6 +1500,21 @@ static int push_stash(int argc, const char **argv, const char *prefix,parse_pathspec (&ps,0 ,PATHSPEC_PREFER_FULL |PATHSPEC_PREFIX_ORIGIN , 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, include_untracked); }
t/t3909-stash-pathspec-file.sh new file +100 -0
100 lines not on this page · raw message
Signature · 1 line
gitgitgadget
v3 cover Support --pathspec-from-file in rm, stash
In reply to Alexandr Miloslavskiy via GitGitGadgetChanges since V1
------------------
Some polishing based on code review in V1
1) Improved error message for the case where pathspec is not given to git rm
2) Removed explicit variable initialization to 0 / NULL
3) Polishing in docs for git stash
------------------
This series continues the effort to support --pathspec-from-file in various git commands. Series already in master: [1][2]
Cc'ing Paul-Sebastian Ungureanu because I touched his git stash code.
[1] https://public-inbox.org/git/[email protected]/
[2] https://lore.kernel.org/git/[email protected]/
Alexandr Miloslavskiy (8):
doc: rm: synchronize <pathspec> description
rm: support the --pathspec-from-file option
doc: stash: split options from description (1)
doc: stash: split options from description (2)
doc: stash: document more options
doc: stash: synchronize <pathspec> description
stash: eliminate crude option parsing
stash push: support the --pathspec-from-file option
Documentation/git-rm.txt | 61 +++++++------- Documentation/git-stash.txt | 144 +++++++++++++++++++++++---------- builtin/rm.c | 28 +++++-- builtin/stash.c | 79 +++++++++--------- t/t3601-rm-pathspec-file.sh | 79 ++++++++++++++++++ t/t3903-stash.sh | 5 ++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++ 7 files changed, 381 insertions(+), 115 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh create mode 100755 t/t3909-stash-pathspec-file.sh
base-commit: de93cc14ab7e8db7645d8dbe4fd2603f76d5851f
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-530%2FSyntevoAlex%2F%230207(git)_pathspec_from_file_3-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-530/SyntevoAlex/#0207(git)_pathspec_from_file_3-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/530
Range-diff vs v2:
1: 2e8c8ad8158 = 1: cf065e905dc doc: rm: synchronize <pathspec> description 2: 7ccbab52e51 ! 2: 7c657dea89e rm: support the --pathspec-from-file option
@@ -5,17 +5,36 @@
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
- if (!argc) block was adapted to work with --pathspec-from-file. For
- that, I also had to parse pathspec earlier. Now it happens before
- read_cache() / hold_locked_index() / setup_work_tree(), which
- sounds fine to me.
+ Adjustments were needed for if (!argc) block:
- In case of empty pathspec, there is now a clear error message instead
- of showing usage. As a consequence, exit code has also changed. Judging
- from [1] it doesn't seem that showing usage in this case was important
- (according to commit message, it was to avoid segfault), and it doesn't
- fit into how other commands react to empty pathspec. Finally, the new
- error message is easier to understand.
+ This code actually means "pathspec is not present". Previously, pathspec
+ could only come from commandline arguments, so testing for argc was a
+ valid way of testing for the presence of pathspec. But this is no longer
+ true with --pathspec-from-file.
+
+ During the entire --pathspec-from-file story, I tried to keep its
+ behavior very close to giving pathspec on commandline, so that switching
+ from one to another doesn't involve any surprises.
+
+ However, throwing usage at user in the case of empty
+ --pathspec-from-file would puzzle because there's nothing wrong with
+ "usage" (that is, argc/argv array).
+
+ On the other hand, throwing usage in the old case also feels bad to me.
+ While it's less of a puzzle, I (as user) never liked the experience of
+ comparing my commandline to "usage", trying to spot a difference. Since
+ it's already known what the error is, it feels a lot better to give that
+ specific error to user.
+
+ Judging from [1] it doesn't seem that showing usage in this case was
+ important (the patch was to avoid segfault), and it doesn't fit into how
+ other commands react to empty pathspec (see for example git add with a
+ custom message).
+
+ Therefore, I decided to show new error text in both cases. In order to
+ continue testing for error early, I moved parse_pathspec() higher. Now
+ it happens before read_cache() / hold_locked_index() /
+ setup_work_tree(), which shouldn't cause any issues.
[1] Commit 7612a1ef ("git-rm: honor -n flag" 2006-06-09)
@@ -136,7 +155,7 @@
+ echo D >fileD.t &&
+ git add fileA.t fileB.t fileC.t fileD.t &&
+ git commit -m "files" &&
-+
++
+ git tag checkpoint
+'
+
@@ -193,7 +212,7 @@
+
+ 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
3: 8c212fc0ed4 = 3: bb300215d49 doc: stash: split options from description (1) 4: db3a96720ce = 4: fdaf4532404 doc: stash: split options from description (2) 5: f91ec08b472 = 5: 764b8668d10 doc: stash: document more options 6: 04e2fd5865f = 6: 7353b06e30e doc: stash: synchronize <pathspec> description 7: 0558cbbe38e = 7: d34eaf4a272 stash: eliminate crude option parsing 8: 0c6f28dc68d = 8: 6465a292b55 stash push: support the --pathspec-from-file option
Signature · 1 line
gitgitgadget
PATCH v3 1/8 doc: rm: synchronize <pathspec> description
From: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Changed outdated descriptions to mention pathspec instead.
2) Added reference to 'linkgit:gitglossary[7]'.
3) Removed content that merely repeated gitglossary.
4) Merged the remainder of "discussion" into <patchspec>.
--- Documentation/git-rm.txt | 50 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 29 deletions(-)
Documentation/git-rm.txt +21 -29
@@ -8,16 +8,16 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... DESCRIPTION ----------- -Remove files from the index, or from the working tree and the index. -`git rm` will not remove a file from just your working directory. -(There is no option to remove a file only from the working tree -and yet keep it in the index; use `/bin/rm` if you want to do that.) -The files being removed have to be identical to the tip of the branch, -and no updates to their contents can be staged in the index, +Remove files matching pathspec from the index, or from the working tree +and the index. `git rm` will not remove a file from just your working +directory. (There is no option to remove a file only from the working +tree and yet keep it in the index; use `/bin/rm` if you want to do +that.) The files being removed have to be identical to the tip of the +branch, and no updates to their contents can be staged in the index, though that default behavior can be overridden with the `-f` option. When `--cached` is given, the staged content has to match either the tip of the branch or the file on disk,
@@ -26,15 +26,20 @@ allowing the file to be removed from just the index. OPTIONS ------- -<file>...:: - Files to remove. Fileglobs (e.g. `*.c`) can be given to - remove all matching files. If you want Git to expand - file glob characters, you may need to shell-escape them. - A leading directory name - (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be - given to remove all files in the directory, and recursively - all sub-directories, - but this requires the `-r` option to be explicitly given. +<pathspec>...:: + Files to remove. A leading directory name (e.g. `dir` to remove + `dir/file1` and `dir/file2`) can be given to remove all files in + the directory, and recursively all sub-directories, but this + requires the `-r` option to be explicitly given. ++ +The command removes only the paths that are known to Git. ++ +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:: --force::
@@ -69,19 +74,6 @@ OPTIONS for each file removed. This option suppresses that output. -DISCUSSION ----------- - -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 -------------------------------------------------------- There is no option for `git rm` to remove from the index only
Signature · 1 line
gitgitgadget
PATCH v3 2/8 rm: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) It is not allowed to pass pathspec in both args and file.
Adjustments were needed for if (!argc) block:
This code actually means "pathspec is not present". Previously, pathspec could only come from commandline arguments, so testing for argc was a valid way of testing for the presence of pathspec. But this is no longer true with --pathspec-from-file.
During the entire --pathspec-from-file story, I tried to keep its behavior very close to giving pathspec on commandline, so that switching from one to another doesn't involve any surprises.
However, throwing usage at user in the case of empty --pathspec-from-file would puzzle because there's nothing wrong with "usage" (that is, argc/argv array).
On the other hand, throwing usage in the old case also feels bad to me. While it's less of a puzzle, I (as user) never liked the experience of comparing my commandline to "usage", trying to spot a difference. Since it's already known what the error is, it feels a lot better to give that specific error to user.
Judging from [1] it doesn't seem that showing usage in this case was important (the patch was to avoid segfault), and it doesn't fit into how other commands react to empty pathspec (see for example git add with a custom message).
Therefore, I decided to show new error text in both cases. In order to continue testing for error early, I moved parse_pathspec() higher. Now it happens before read_cache() / hold_locked_index() / setup_work_tree(), which shouldn't cause any issues.
[1] Commit 7612a1ef ("git-rm: honor -n flag" 2006-06-09)
--- Documentation/git-rm.txt | 17 +++++++- builtin/rm.c | 28 ++++++++++--- t/t3601-rm-pathspec-file.sh | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 7 deletions(-) create mode 100755 t/t3601-rm-pathspec-file.sh
Documentation/git-rm.txt +16 -1
@@ -8,7 +8,9 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- [verse] -'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <pathspec>... +'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] + [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]] + [--] [<pathspec>...] DESCRIPTION -----------
@@ -73,6 +75,19 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7]. `git rm` normally outputs one line (in the form of an `rm` command) 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`. + +--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). + REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM --------------------------------------------------------
builtin/rm.c +22 -6
@@ -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 ignore_unmatch =0 ; +static int ignore_unmatch =0 , pathspec_file_nul; +static char *pathspec_from_file;static struct option builtin_rm_options[] = {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 (0 ,"ignore-unmatch" , &ignore_unmatch,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(), };
@@ -259,8 +262,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, builtin_rm_options, 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)setup_work_tree ();
@@ -270,9 +289,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)if (read_cache () <0 )die (_ ("index file corrupt" )); -parse_pathspec (&pathspec,0 , -PATHSPEC_PREFER_CWD , - prefix, argv);refresh_index (&the_index,REFRESH_QUIET |REFRESH_UNMERGED , &pathspec,NULL ,NULL ); seen =xcalloc (pathspec.nr,1 );
t/t3601-rm-pathspec-file.sh new file +79 -0
79 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH v3 2/8] rm: support the --pathspec-from-file option
Quoted 3 lines · Junio C Hamano
I may not have time to read it over at least in a few days, but lack if v3 in the title will make it cumbersome to come back to the thread later X-<. Thanks for a heads-up, anyway, thoguh.
Here's the V3 in title :)
PATCH v3 3/8 doc: stash: split options from description (1)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch moves blocks of text as-is to make it easier to review the next patch.
--- Documentation/git-stash.txt | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-)
Documentation/git-stash.txt +35 -33
@@ -58,31 +58,6 @@ non-option arguments are not allowed to prevent a misspelled 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, 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>]::
@@ -128,14 +103,6 @@ pop [--index] [-q|--quiet] [<stash>]:: 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 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>]::
@@ -185,6 +152,41 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. +If the `--all` option is used instead then the +ignored files are stashed and cleaned in addition to the untracked files. + +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 `--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). + +If the `--keep-index` option is used, all changes already added to the +index are left intact. + +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. + +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. + +When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must +be a reference of the form `stash@{<revision>}`. + DISCUSSION ----------
Signature · 1 line
gitgitgadget
PATCH v3 4/8 doc: stash: split options from description (2)
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Together with the previous patch, this brings docs for git stash to the common layout used for most other commands (see for example docs for git add, git commit, git checkout, git reset) where all options are documented in a separate list.
After some thinking and having a look at docs for git svn and git submodule`, I have arrived at following conclusions:
* Options should be described in a list rather then text to facilitate lookup for user.
* Single list is better then multiple lists because it avoids copy&pasting descriptions between subcommands (or, without copy&pasting, user will have to look up missing options in other subcommands).
* As a consequence, commands section should only give brief info and list possible options. Since options have good enough names, user will only need to look up the "interesting" options.
* Every option should list which subcommands support it.
I have decided to use alphabetical sorting in the list of options to facilitate lookup for user.
There is some text editing done to make old descriptions better fit into the list-style format.
--- Documentation/git-stash.txt | 92 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 35 deletions(-)
Documentation/git-stash.txt +57 -35
@@ -43,8 +43,8 @@ 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 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>...]::
@@ -86,7 +86,7 @@ show [<options>] [<stash>]:: 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 - created. When no `<stash>` is given, it shows the latest one. + created. 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}` to view the second most recent entry in patch form).
@@ -116,8 +116,7 @@ branch <branchname> [<stash>]:: the commit at which the `<stash>` was originally created, applies the changes recorded in `<stash>` to the new working tree and index. If that succeeds, and `<stash>` is a reference of the form - `stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>` - is given, applies the latest one. + `stash@{<revision>}`, it then drops the `<stash>`. + 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
@@ -133,9 +132,6 @@ clear:: drop [-q|--quiet] [<stash>]:: 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::
@@ -152,40 +148,66 @@ store:: reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "push" above. -If the `--all` option is used instead then the -ignored files are stashed and cleaned in addition to the untracked files. - -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. +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`. -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). +-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`. -If the `--keep-index` option is used, all changes already added to the -index are left intact. +--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. -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. +-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. -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. - -When no `<stash>` is given, `stash@{0}` is assumed, otherwise `<stash>` must -be a reference of the form `stash@{<revision>}`. +<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. + +<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 ----------
Signature · 1 line
gitgitgadget
PATCH v3 5/8 doc: stash: document more options
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
--- Documentation/git-stash.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Documentation/git-stash.txt +12 -0
@@ -194,6 +194,18 @@ to learn how to operate the `--patch` mode. The `--patch` option implies `--keep-index`. You can use `--no-keep-index` to override this. +-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. +
Signature · 1 line
gitgitgadget
PATCH v3 6/8 doc: stash: synchronize <pathspec> description
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
This patch continues the effort that is already applied to git commit, git reset, git checkout etc.
1) Added reference to 'linkgit:gitglossary[7]'.
2) Fixed mentions of incorrectly plural "pathspecs".
--- Documentation/git-stash.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Documentation/git-stash.txt +4 -2
@@ -56,13 +56,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, non-option arguments are not allowed to prevent a misspelled 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. 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 - 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 message.
@@ -213,6 +213,8 @@ 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`,
Signature · 1 line
gitgitgadget
PATCH v3 7/8 stash: eliminate crude option parsing
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Eliminate crude option parsing and rely on real parsing instead, because
1) Crude parsing is crude, for example it's not capable of handling things like git stash -m Message
2) Adding options in two places is inconvenient and prone to bugs
As a side result, the case of git stash -m Message gets fixed. Also give a good error message instead of just throwing usage at user.
----
Some review of what's been happening to this code:
Before [1], git-stash.sh only verified that all args begin with - :
# The default command is "push" if nothing but options are given seen_non_option= for opt do case "$opt" in --) break ;; -*) ;; *) seen_non_option=t; break ;; esac done
Later, [1] introduced the duplicate code I'm now removing, also making the previous test more strict by white-listing options.
----
[1] Commit 40af1468 ("stash: convert stash--helper.c into stash.c" 2019-02-26)
--- builtin/stash.c | 59 +++++++++++++++++------------------------------- t/t3903-stash.sh | 5 ++++ 2 files changed, 26 insertions(+), 38 deletions(-)
builtin/stash.c +21 -38
@@ -1451,8 +1451,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int qreturn 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 patch_mode =0 ;int include_untracked =0 ;
@@ -1474,10 +1476,22 @@ static int push_stash(int argc, const char **argv, const char *prefix) OPT_END() }; -if (argc) +if (argc) { + force_assume = !strcmp (argv[0 ],"-p" ); argc =parse_options (argc, argv, prefix, options, 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 , prefix, argv);
@@ -1550,7 +1564,6 @@ static int use_builtin_stash(void)int cmd_stash (int argc,const char **argv,const char *prefix) { -int i =-1 ;pid_t pid =getpid ();const char *index_file;struct argv_array args =ARGV_ARRAY_INIT ;
@@ -1583,7 +1596,7 @@ int cmd_stash(int argc, const char **argv, const char *prefix) (uintmax_t)pid);if (!argc) -return !!push_stash (0 ,NULL , prefix); +return !!push_stash (0 ,NULL , prefix,0 );else if (!strcmp (argv[0 ],"apply" ))return !!apply_stash (argc, argv, prefix);else if (!strcmp (argv[0 ],"clear" ))
@@ -1603,45 +1616,15 @@ int cmd_stash(int argc, const char **argv, const char *prefix)else if (!strcmp (argv[0 ],"create" ))return !!create_stash (argc, argv, prefix);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" ))return !!save_stash (argc, argv, prefix);else if (*argv[0 ] !='-' )usage_msg_opt (xstrfmt (_ ("unknown subcommand: %s" ), argv[0 ]), git_stash_usage, options); -if (strcmp (argv[0 ],"-p" )) { -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); - } - } - +/* Assume 'stash push' */ argv_array_push (&args,"push" );argv_array_pushv (&args, argv); -return !!push_stash (args.argc, args.argv, prefix); +return !!push_stash (args.argc, args.argv, prefix,1 ); }
t/t3903-stash.sh +5 -0
@@ -285,6 +285,11 @@ test_expect_success 'stash --no-keep-index' ' 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' ' echo bar5 >file && echo bar6 >file2 &&
Signature · 1 line
gitgitgadget
PATCH v3 8/8 stash push: support the --pathspec-from-file option
In reply to Alexandr Miloslavskiy via GitGitGadgetFrom: Alexandr Miloslavskiy <[email protected]>
Decisions taken for simplicity:
1) For now, --pathspec-from-file is declared incompatible with --patch, even when <file> is not -. Such use case is not really expected.
2) It is not allowed to pass pathspec in both args and file.
--- Documentation/git-stash.txt | 20 ++++++- builtin/stash.c | 20 +++++++ t/t3909-stash-pathspec-file.sh | 100 +++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100755 t/t3909-stash-pathspec-file.sh
Documentation/git-stash.txt +19 -1
@@ -15,6 +15,7 @@ SYNOPSIS 'git stash' branch <branchname> [<stash>] 'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [-m|--message <message>] + [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]] 'git stash' clear 'git stash' create [<message>]
@@ -46,7 +47,7 @@ stash index (e.g. the integer `n` is equivalent to `stash@{n}`). 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 back to HEAD (in the working tree and in the index).
@@ -194,6 +195,23 @@ 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`,
builtin/stash.c +20 -0
@@ -27,6 +27,7 @@ static const char * const git_stash_usage[] = {N_ ("git stash clear" ),N_ ("git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n" +" [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" " [--] [<pathspec>...]]" ),N_ ("git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n" " [-u|--include-untracked] [-a|--all] [<message>]"),
@@ -1459,7 +1460,9 @@ static int push_stash(int argc, const char **argv, const char *prefix,int patch_mode =0 ;int include_untracked =0 ;int quiet =0 ; +int pathspec_file_nul =0 ;const char *stash_msg =NULL ; +const char *pathspec_from_file =NULL ;struct pathspec ps;struct option options[] = { OPT_BOOL('k', "keep-index", &keep_index,
@@ -1473,6 +1476,8 @@ static int push_stash(int argc, const char **argv, const char *prefix, N_("include ignore files"), 2),OPT_STRING ('m' ,"message" , &stash_msg,N_ ("message" ),N_ ("stash message" )), +OPT_PATHSPEC_FROM_FILE (&pathspec_from_file), +OPT_PATHSPEC_FILE_NUL (&pathspec_file_nul), OPT_END() };
@@ -1495,6 +1500,21 @@ static int push_stash(int argc, const char **argv, const char *prefix,parse_pathspec (&ps,0 ,PATHSPEC_PREFER_FULL |PATHSPEC_PREFIX_ORIGIN , 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, include_untracked); }
t/t3909-stash-pathspec-file.sh new file +100 -0
100 lines not on this page · raw message
Signature · 1 line
gitgitgadget