Skip to content

Add --pathspec-from-file option #445

New issue

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

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

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion Documentation/git-add.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ SYNOPSIS
'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
[--chmod=(+|-)x] [--] [<pathspec>...]
[--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]

DESCRIPTION
-----------
Expand Down Expand Up @@ -187,6 +188,19 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
bit is only changed in the index, the files on disk are left
unchanged.

--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).

\--::
This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken
Expand Down
50 changes: 34 additions & 16 deletions Documentation/git-checkout.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ SYNOPSIS
'git checkout' [-q] [-f] [-m] --detach [<branch>]
'git checkout' [-q] [-f] [-m] [--detach] <commit>
'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
'git checkout' [<tree-ish>] [--] <pathspec>...
'git checkout' (-p|--patch) [<tree-ish>] [--] [<paths>...]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]
'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]

DESCRIPTION
-----------
Updates files in the working tree to match the version in the index
or the specified tree. If no paths are given, 'git checkout' will
or the specified tree. If no pathspec was given, 'git checkout' will
also update `HEAD` to set the specified branch as the current
branch.

Expand Down Expand Up @@ -79,13 +79,14 @@ be used to detach `HEAD` at the tip of the branch (`git checkout
+
Omitting `<branch>` detaches `HEAD` at the tip of the current branch.

'git checkout' [<tree-ish>] [--] <pathspec>...::
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...::
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]::

Overwrite paths in the working tree by replacing with the
contents in the index or in the `<tree-ish>` (most often a
commit). When a `<tree-ish>` is given, the paths that
match the `<pathspec>` are updated both in the index and in
the working tree.
Overwrite the contents of the files that match the pathspec.
When the `<tree-ish>` (most often a commit) is not given,
overwrite working tree with the contents in the index.
When the `<tree-ish>` is given, overwrite both the index and
the working tree with the contents at the `<tree-ish>`.
+
The index may contain unmerged entries because of a previous failed merge.
By default, if you try to check out such an entry from the index, the
Expand All @@ -96,12 +97,10 @@ using `--ours` or `--theirs`. With `-m`, changes made to the working tree
file can be discarded to re-create the original conflicted merge result.

'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]::
This is similar to the "check out paths to the working tree
from either the index or from a tree-ish" mode described
above, but lets you use the interactive interface to show
the "diff" output and choose which hunks to use in the
result. See below for the description of `--patch` option.

This is similar to the previous mode, but lets you use the
interactive interface to show the "diff" output and choose which
hunks to use in the result. See below for the description of
`--patch` option.

OPTIONS
-------
Expand Down Expand Up @@ -309,6 +308,19 @@ Note that this option uses the no overlay mode by default (see also
working tree, but not in `<tree-ish>` are removed, to make them
match `<tree-ish>` exactly.

--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).

<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with "refs/heads/", is a valid ref), then that
Expand Down Expand Up @@ -339,7 +351,13 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
Tree to checkout from (when paths are given). If not specified,
the index will be used.

\--::
Do not interpret any more arguments as options.

<pathspec>...::
Limits the paths affected by the operation.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].

DETACHED HEAD
-------------
Expand Down
29 changes: 22 additions & 7 deletions Documentation/git-commit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ SYNOPSIS
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Alexandr Miloslavskiy via GitGitGadget" <[email protected]>
writes:

> From: Alexandr Miloslavskiy <[email protected]>
>
> Synchronize it to `git add`, which has a pretty good description.
> This also better disambiguates <file>... header.

"When files are given on..." is no longer true with this change (it
wasn't true with the code before this change anyway).

	When pathspec is given on the command line, commit the
	contents of the files that match the pathspec without
	recording the changes already added to the index. ...

The second sentence also says "these files", but that can be left
as-is, since it would refer to "the files that match ..." explained
in the above sentence.

> +For more details about the <pathspec> syntax, see the 'pathspec' entry
> +in linkgit:gitglossary[7].

I am not sure if we want to repeat this all over the place.

We do not say "For details about the <commit> syntax, see the
'SPECIFYING REVISIONS' section of linkgit:git-rev-parse[1]" for
every command that takes <commit> from the command line.

Is your urge to suggest adding this sentence coming from that you
are much more familiar with <commit> than <pathspec>?  In other
words, if you were more familiar with Git, would you still be adding
this (and not corresponding one for <commit>)?

Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Alexandr Miloslavskiy wrote (reply to this):

I think I have implemented most suggestions in PatchV2. Thanks!

> I am not sure if we want to repeat this all over the place.
> 
> We do not say "For details about the <commit> syntax, see the
> 'SPECIFYING REVISIONS' section of linkgit:git-rev-parse[1]" for
> every command that takes <commit> from the command line.
> 
> Is your urge to suggest adding this sentence coming from that you
> are much more familiar with <commit> than <pathspec>?  In other
> words, if you were more familiar with Git, would you still be adding
> this (and not corresponding one for <commit>)?

Commit is a well known term, dating from ancient times like CVS or even 
older.

Pathspec, however, is something new. When I pretend to be someone new to 
git, I see it this way:
1) Let's read "git commit" documentation
2) Where on this commandline do I put my filename?!

So yes, I would repeat it in every location that could be popular for 
new users.

Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Junio C Hamano wrote (reply to this):

Alexandr Miloslavskiy <[email protected]> writes:

> I think I have implemented most suggestions in PatchV2. Thanks!
>
>> I am not sure if we want to repeat this all over the place.
>>
>> We do not say "For details about the <commit> syntax, see the
>> 'SPECIFYING REVISIONS' section of linkgit:git-rev-parse[1]" for
>> every command that takes <commit> from the command line.
>>
>> Is your urge to suggest adding this sentence coming from that you
>> are much more familiar with <commit> than <pathspec>?  In other
>> words, if you were more familiar with Git, would you still be adding
>> this (and not corresponding one for <commit>)?
>
> Commit is a well known term, dating from ancient times like CVS or
> even older.

That's more or less irrelevant.  

I am reacting to this from your change that you omitted quoting in
your reply:

> +For more details about the <pathspec> syntax, see the 'pathspec' entry
> +in linkgit:gitglossary[7].

That sentence is for those who have some notion of <pathspec> but
does not know enough about its syntax.

CVS does not let you specify <commit> like "master^{/^fix frotz}~4";
A user a user who is familiar with CVS's commits would still want to
refer to the section "For details about the <commit> syntax".

I am not advocating to add the reference to SPECIFYING REVISIONS
section; instead we should let readers know that every time they see
<defined word>, they can refer to the glossary for more details.

> Pathspec, however, is something new.

Compared to CVS, everything in Git may be new, but that was a news
in 2010, not this year.

Copy link

Choose a reason for hiding this comment

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

On the Git mailing list, Alexandr Miloslavskiy wrote (reply to this):

On 07.11.2019 6:54, Junio C Hamano wrote:
> I am reacting to this from your change that you omitted quoting in
> your reply:
> 
>> +For more details about the <pathspec> syntax, see the 'pathspec' entry
>> +in linkgit:gitglossary[7].
> 
> That sentence is for those who have some notion of <pathspec> but
> does not know enough about its syntax.

In the perfect world, I would expect _every_ 'pathspec' word in text to 
be an HTML-style link to a dedicated article, not just a paragraph in 
glossary.

MSDN is in general a good example [1]: there, it's easy to read only a 
small portion of article, ignoring anything you're not interested in, 
and still have all links at hand.

Regarding dedicated page: the content of 'pathspec' in glossary is 
already long enough for a page, and it could benefit from additional 
examples. Also, having a dedicated page makes linking easier, so that 
user doesn't have to scroll glossary.

Regarding links: I don't really understand what git's doc format allows. 
Is it just pure text in worst (or even average) case?

If it's usually something with clickable links, it could be worth to 
just insert links everywhere.

If it's usually plaintext, then "see the 'pathspec' entry in 
linkgit:gitglossary[7]" is a bit too verbose to repeat on every 
occasion. Still, I'd like to see links everywhere. One big reason is to 
let reader know that the explanation actually exists!

A compromise solution is to give every article header like this:

     This article uses the following terms which are explained
     in linkgit:gitglossary[7]:
     * pathspec
     * tree-ish
     * refspec

If it's close to top of article, then chances are that everyone will 
notice it. Also, it will not require extra verbosity in plaintext.

> CVS does not let you specify <commit> like "master^{/^fix frotz}~4";
> A user a user who is familiar with CVS's commits would still want to
> refer to the section "For details about the <commit> syntax".
> 
> I am not advocating to add the reference to SPECIFYING REVISIONS
> section; instead we should let readers know that every time they see
> <defined word>, they can refer to the glossary for more details.

I now think that my arguments apply to <pathspec> AND <commit> in the 
same way. Indeed a user can't know complex <commit> variants until 
he/she reads it in git docs.

----

[1] 
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea

[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
[--date=<date>] [--cleanup=<mode>] [--[no-]status]
[-i | -o] [-S[<keyid>]] [--] [<file>...]
[-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
[-S[<keyid>]] [--] [<pathspec>...]

DESCRIPTION
-----------
Expand Down Expand Up @@ -278,6 +279,19 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
already been staged. If used together with `--allow-empty`
paths are also not required, and an empty commit will be created.

--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).

-u[<mode>]::
--untracked-files[=<mode>]::
Show untracked files.
Expand Down Expand Up @@ -345,12 +359,13 @@ changes to tracked files.
\--::
Do not interpret any more arguments as options.

<file>...::
When files are given on the command line, the command
commits the contents of the named files, without
recording the changes already staged. The contents of
these files are also staged for the next commit on top
of what have been staged before.
<pathspec>...::
When pathspec is given on the command line, commit the contents of
the files that match the pathspec without recording the changes
already added to the index. The contents of these files are also
staged for the next commit on top of what have been staged before.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].

:git-commit: 1
include::date-formats.txt[]
Expand Down
48 changes: 35 additions & 13 deletions Documentation/git-reset.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,36 @@ git-reset - Reset current HEAD to the specified state
SYNOPSIS
--------
[verse]
'git reset' [-q] [<tree-ish>] [--] <paths>...
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
'git reset' [-q] [<tree-ish>] [--] <pathspec>...
'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

DESCRIPTION
-----------
In the first and second form, copy entries from `<tree-ish>` to the index.
In the third form, set the current branch head (`HEAD`) to `<commit>`,
In the first three forms, copy entries from `<tree-ish>` to the index.
In the last form, set the current branch head (`HEAD`) to `<commit>`,
optionally modifying index and working tree to match.
The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.

'git reset' [-q] [<tree-ish>] [--] <paths>...::
This form resets the index entries for all `<paths>` to their
state at `<tree-ish>`. (It does not affect the working tree or
the current branch.)
'git reset' [-q] [<tree-ish>] [--] <pathspec>...::
'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]::
These forms reset the index entries for all paths that match the
`<pathspec>` to their state at `<tree-ish>`. (It does not affect
the working tree or the current branch.)
+
This means that `git reset <paths>` is the opposite of `git add
<paths>`. This command is equivalent to
`git restore [--source=<tree-ish>] --staged <paths>...`.
This means that `git reset <pathspec>` is the opposite of `git add
<pathspec>`. This command is equivalent to
`git restore [--source=<tree-ish>] --staged <pathspec>...`.
+
After running `git reset <paths>` to update the index entry, you can
After running `git reset <pathspec>` to update the index entry, you can
use linkgit:git-restore[1] to check the contents out of the index to
the working tree. Alternatively, using linkgit:git-restore[1]
and specifying a commit with `--source`, you
can copy the contents of a path out of a commit to the index and to the
working tree in one go.

'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]::
'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]::
Interactively select hunks in the difference between the index
and `<tree-ish>` (defaults to `HEAD`). The chosen hunks are applied
in reverse to the index.
Expand Down Expand Up @@ -101,6 +103,26 @@ OPTIONS
`reset.quiet` config option. `--quiet` and `--no-quiet` will
override the default behavior.

--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).

\--::
Do not interpret any more arguments as options.

<pathspec>...::
Limits the paths affected by the operation.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].

EXAMPLES
--------
Expand Down
26 changes: 24 additions & 2 deletions Documentation/git-restore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ git-restore - Restore working tree files
SYNOPSIS
--------
[verse]
'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] <pathspec>...
'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [<pathspec>...]
'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>...
'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] --pathspec-from-file=<file> [--pathspec-file-nul]
'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]

DESCRIPTION
-----------
Expand Down Expand Up @@ -113,6 +114,27 @@ in linkgit:git-checkout[1] for details.
appear in the `--source` tree are removed, to make them match
`<tree>` exactly. The default is no-overlay mode.

--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).

\--::
Do not interpret any more arguments as options.

<pathspec>...::
Limits the paths affected by the operation.
+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].

EXAMPLES
--------

Expand Down
60 changes: 41 additions & 19 deletions builtin/add.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ static const char * const builtin_add_usage[] = {
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
static int add_renormalize;
static int pathspec_file_nul;
static const char *pathspec_from_file;

struct update_callback_data {
int flags;
Expand Down Expand Up @@ -309,6 +311,8 @@ static struct option builtin_add_options[] = {
N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(),
};

Expand Down Expand Up @@ -402,11 +406,17 @@ int cmd_add(int argc, const char **argv, const char *prefix)
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
if (add_interactive) {
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
}

if (edit_interactive)
if (edit_interactive) {
if (pathspec_from_file)
die(_("--pathspec-from-file is incompatible with --edit"));
return(edit_patch(argc, argv, prefix));
}
argc--;
argv++;

Expand All @@ -418,10 +428,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible"));

if (!take_worktree_changes && addremove_explicit < 0 && argc)
/* Turn "git add pathspec..." to "git add -A pathspec..." */
addremove = 1;

if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));

Expand All @@ -434,19 +440,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)

hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);

flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
(intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));

if (require_pathspec && argc == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}

/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
Expand All @@ -456,6 +449,35 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv);

if (pathspec_from_file) {
if (pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));

parse_pathspec_file(&pathspec, PATHSPEC_ATTR,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH,
prefix, pathspec_from_file, pathspec_file_nul);
} else if (pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}

if (require_pathspec && pathspec.nr == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}

if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr)
/* Turn "git add pathspec..." to "git add -A pathspec..." */
addremove = 1;

flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
(intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));

if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt"));

Expand Down
Loading