Skip to content

Commit c58ae96

Browse files
committed
Merge branch 'am/pathspec-from-file'
A few commands learned to take the pathspec from the standard input or a named file, instead of taking it as the command line arguments. * am/pathspec-from-file: commit: support the --pathspec-from-file option doc: commit: synchronize <pathspec> description reset: support the `--pathspec-from-file` option doc: reset: synchronize <pathspec> description pathspec: add new function to parse file parse-options.h: add new options `--pathspec-from-file`, `--pathspec-file-nul`
2 parents 7034cd0 + e440fc5 commit c58ae96

File tree

9 files changed

+434
-28
lines changed

9 files changed

+434
-28
lines changed

Documentation/git-commit.txt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ SYNOPSIS
1313
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
1414
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
1515
[--date=<date>] [--cleanup=<mode>] [--[no-]status]
16-
[-i | -o] [-S[<keyid>]] [--] [<file>...]
16+
[-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
17+
[-S[<keyid>]] [--] [<pathspec>...]
1718

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

282+
--pathspec-from-file=<file>::
283+
Pathspec is passed in `<file>` instead of commandline args. If
284+
`<file>` is exactly `-` then standard input is used. Pathspec
285+
elements are separated by LF or CR/LF. Pathspec elements can be
286+
quoted as explained for the configuration variable `core.quotePath`
287+
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
288+
global `--literal-pathspecs`.
289+
290+
--pathspec-file-nul::
291+
Only meaningful with `--pathspec-from-file`. Pathspec elements are
292+
separated with NUL character and all other characters are taken
293+
literally (including newlines and quotes).
294+
281295
-u[<mode>]::
282296
--untracked-files[=<mode>]::
283297
Show untracked files.
@@ -345,12 +359,13 @@ changes to tracked files.
345359
\--::
346360
Do not interpret any more arguments as options.
347361

348-
<file>...::
349-
When files are given on the command line, the command
350-
commits the contents of the named files, without
351-
recording the changes already staged. The contents of
352-
these files are also staged for the next commit on top
353-
of what have been staged before.
362+
<pathspec>...::
363+
When pathspec is given on the command line, commit the contents of
364+
the files that match the pathspec without recording the changes
365+
already added to the index. The contents of these files are also
366+
staged for the next commit on top of what have been staged before.
367+
+
368+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
354369

355370
:git-commit: 1
356371
include::date-formats.txt[]

Documentation/git-reset.txt

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,36 @@ git-reset - Reset current HEAD to the specified state
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git reset' [-q] [<tree-ish>] [--] <paths>...
12-
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
11+
'git reset' [-q] [<tree-ish>] [--] <pathspec>...
12+
'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
13+
'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
1314
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
1415

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

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

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

106+
--pathspec-from-file=<file>::
107+
Pathspec is passed in `<file>` instead of commandline args. If
108+
`<file>` is exactly `-` then standard input is used. Pathspec
109+
elements are separated by LF or CR/LF. Pathspec elements can be
110+
quoted as explained for the configuration variable `core.quotePath`
111+
(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
112+
global `--literal-pathspecs`.
113+
114+
--pathspec-file-nul::
115+
Only meaningful with `--pathspec-from-file`. Pathspec elements are
116+
separated with NUL character and all other characters are taken
117+
literally (including newlines and quotes).
118+
119+
\--::
120+
Do not interpret any more arguments as options.
121+
122+
<pathspec>...::
123+
Limits the paths affected by the operation.
124+
+
125+
For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
104126

105127
EXAMPLES
106128
--------

builtin/commit.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ static int all, also, interactive, patch_interactive, only, amend, signoff;
107107
static int edit_flag = -1; /* unspecified */
108108
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
109109
static int config_commit_verbose = -1; /* unspecified */
110-
static int no_post_rewrite, allow_empty_message;
110+
static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
111111
static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
112-
static char *sign_commit;
112+
static char *sign_commit, *pathspec_from_file;
113113

114114
/*
115115
* The default commit message cleanup mode will remove the lines
@@ -343,6 +343,23 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
343343
PATHSPEC_PREFER_FULL,
344344
prefix, argv);
345345

346+
if (pathspec_from_file) {
347+
if (interactive)
348+
die(_("--pathspec-from-file is incompatible with --interactive/--patch"));
349+
350+
if (pathspec.nr)
351+
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
352+
353+
parse_pathspec_file(&pathspec, 0,
354+
PATHSPEC_PREFER_FULL,
355+
prefix, pathspec_from_file, pathspec_file_nul);
356+
} else if (pathspec_file_nul) {
357+
die(_("--pathspec-file-nul requires --pathspec-from-file"));
358+
}
359+
360+
if (!pathspec.nr && (also || (only && !amend && !allow_empty)))
361+
die(_("No paths with --include/--only does not make sense."));
362+
346363
if (read_cache_preload(&pathspec) < 0)
347364
die(_("index file corrupt"));
348365

@@ -1198,8 +1215,6 @@ static int parse_and_validate_options(int argc, const char *argv[],
11981215

11991216
if (also + only + all + interactive > 1)
12001217
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
1201-
if (argc == 0 && (also || (only && !amend && !allow_empty)))
1202-
die(_("No paths with --include/--only does not make sense."));
12031218
cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
12041219

12051220
handle_untracked_files_arg(s);
@@ -1513,6 +1528,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
15131528
OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
15141529
OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
15151530
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
1531+
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
1532+
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
15161533
/* end commit contents options */
15171534

15181535
OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,

builtin/reset.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030

3131
static const char * const git_reset_usage[] = {
3232
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
33-
N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
34-
N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
33+
N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
34+
N_("git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"),
35+
N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
3536
NULL
3637
};
3738

@@ -284,8 +285,8 @@ static int git_reset_config(const char *var, const char *value, void *cb)
284285
int cmd_reset(int argc, const char **argv, const char *prefix)
285286
{
286287
int reset_type = NONE, update_ref_status = 0, quiet = 0;
287-
int patch_mode = 0, unborn;
288-
const char *rev;
288+
int patch_mode = 0, pathspec_file_nul = 0, unborn;
289+
const char *rev, *pathspec_from_file = NULL;
289290
struct object_id oid;
290291
struct pathspec pathspec;
291292
int intent_to_add = 0;
@@ -306,6 +307,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
306307
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
307308
OPT_BOOL('N', "intent-to-add", &intent_to_add,
308309
N_("record only the fact that removed paths will be added later")),
310+
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
311+
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
309312
OPT_END()
310313
};
311314

@@ -316,6 +319,20 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
316319
PARSE_OPT_KEEP_DASHDASH);
317320
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
318321

322+
if (pathspec_from_file) {
323+
if (patch_mode)
324+
die(_("--pathspec-from-file is incompatible with --patch"));
325+
326+
if (pathspec.nr)
327+
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
328+
329+
parse_pathspec_file(&pathspec, 0,
330+
PATHSPEC_PREFER_FULL,
331+
prefix, pathspec_from_file, pathspec_file_nul);
332+
} else if (pathspec_file_nul) {
333+
die(_("--pathspec-file-nul requires --pathspec-from-file"));
334+
}
335+
319336
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
320337
if (unborn) {
321338
/* reset on unborn branch: treat as reset to empty tree */

parse-options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,5 +330,7 @@ int parse_opt_passthru_argv(const struct option *, const char *, int);
330330
#define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
331331
#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN | PARSE_OPT_NONEG)
332332
#define OPT_CLEANUP(v) OPT_STRING(0, "cleanup", v, N_("mode"), N_("how to strip spaces and #comments from message"))
333+
#define OPT_PATHSPEC_FROM_FILE(v) OPT_FILENAME(0, "pathspec-from-file", v, N_("read pathspec from file"))
334+
#define OPT_PATHSPEC_FILE_NUL(v) OPT_BOOL(0, "pathspec-file-nul", v, N_("with --pathspec-from-file, pathspec elements are separated with NUL character"))
333335

334336
#endif

pathspec.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "dir.h"
44
#include "pathspec.h"
55
#include "attr.h"
6+
#include "argv-array.h"
7+
#include "quote.h"
68

79
/*
810
* Finds which of the given pathspecs match items in the index.
@@ -613,6 +615,42 @@ void parse_pathspec(struct pathspec *pathspec,
613615
}
614616
}
615617

618+
void parse_pathspec_file(struct pathspec *pathspec, unsigned magic_mask,
619+
unsigned flags, const char *prefix,
620+
const char *file, int nul_term_line)
621+
{
622+
struct argv_array parsed_file = ARGV_ARRAY_INIT;
623+
strbuf_getline_fn getline_fn = nul_term_line ? strbuf_getline_nul :
624+
strbuf_getline;
625+
struct strbuf buf = STRBUF_INIT;
626+
struct strbuf unquoted = STRBUF_INIT;
627+
FILE *in;
628+
629+
if (!strcmp(file, "-"))
630+
in = stdin;
631+
else
632+
in = xfopen(file, "r");
633+
634+
while (getline_fn(&buf, in) != EOF) {
635+
if (!nul_term_line && buf.buf[0] == '"') {
636+
strbuf_reset(&unquoted);
637+
if (unquote_c_style(&unquoted, buf.buf, NULL))
638+
die(_("line is badly quoted: %s"), buf.buf);
639+
strbuf_swap(&buf, &unquoted);
640+
}
641+
argv_array_push(&parsed_file, buf.buf);
642+
strbuf_reset(&buf);
643+
}
644+
645+
strbuf_release(&unquoted);
646+
strbuf_release(&buf);
647+
if (in != stdin)
648+
fclose(in);
649+
650+
parse_pathspec(pathspec, magic_mask, flags, prefix, parsed_file.argv);
651+
argv_array_clear(&parsed_file);
652+
}
653+
616654
void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
617655
{
618656
int i, j;

pathspec.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ void parse_pathspec(struct pathspec *pathspec,
8585
unsigned flags,
8686
const char *prefix,
8787
const char **args);
88+
/*
89+
* Same as parse_pathspec() but uses file as input.
90+
* When 'file' is exactly "-" it uses 'stdin' instead.
91+
*/
92+
void parse_pathspec_file(struct pathspec *pathspec,
93+
unsigned magic_mask,
94+
unsigned flags,
95+
const char *prefix,
96+
const char *file,
97+
int nul_term_line);
8898
void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
8999
void clear_pathspec(struct pathspec *);
90100

0 commit comments

Comments
 (0)