1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-06-02 04:46:30 +02:00

Merge branch 'am/pathspec-f-f-checkout'

A few more commands learned the "--pathspec-from-file" command line
option.

* am/pathspec-f-f-checkout:
  checkout, restore: support the --pathspec-from-file option
  doc: restore: synchronize <pathspec> description
  doc: checkout: synchronize <pathspec> description
  doc: checkout: fix broken text reference
  doc: checkout: remove duplicate synopsis
  add: support the --pathspec-from-file option
  cmd_add: prepare for next patch
This commit is contained in:
Junio C Hamano 2019-12-25 11:21:57 -08:00
commit 135365dd99
9 changed files with 548 additions and 42 deletions

View File

@ -11,7 +11,8 @@ SYNOPSIS
'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p] 'git add' [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]] [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize] [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
[--chmod=(+|-)x] [--] [<pathspec>...] [--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]
DESCRIPTION DESCRIPTION
----------- -----------
@ -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 bit is only changed in the index, the files on disk are left
unchanged. 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 This option can be used to separate command-line options from
the list of files, (useful when filenames might be mistaken the list of files, (useful when filenames might be mistaken

View File

@ -12,14 +12,14 @@ SYNOPSIS
'git checkout' [-q] [-f] [-m] --detach [<branch>] 'git checkout' [-q] [-f] [-m] --detach [<branch>]
'git checkout' [-q] [-f] [-m] [--detach] <commit> 'git checkout' [-q] [-f] [-m] [--detach] <commit>
'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] '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' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...
'git checkout' [<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>] [--] [<paths>...] 'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]
DESCRIPTION DESCRIPTION
----------- -----------
Updates files in the working tree to match the version in the index 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 also update `HEAD` to set the specified branch as the current
branch. branch.
@ -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. 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 Overwrite the contents of the files that match the pathspec.
contents in the index or in the `<tree-ish>` (most often a When the `<tree-ish>` (most often a commit) is not given,
commit). When a `<tree-ish>` is given, the paths that overwrite working tree with the contents in the index.
match the `<pathspec>` are updated both in the index and in When the `<tree-ish>` is given, overwrite both the index and
the working tree. the working tree with the contents at the `<tree-ish>`.
+ +
The index may contain unmerged entries because of a previous failed merge. 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 By default, if you try to check out such an entry from the index, the
@ -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. file can be discarded to re-create the original conflicted merge result.
'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]:: 'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]::
This is similar to the "check out paths to the working tree This is similar to the previous mode, but lets you use the
from either the index or from a tree-ish" mode described interactive interface to show the "diff" output and choose which
above, but lets you use the interactive interface to show hunks to use in the result. See below for the description of
the "diff" output and choose which hunks to use in the `--patch` option.
result. See below for the description of `--patch` option.
OPTIONS OPTIONS
------- -------
@ -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 working tree, but not in `<tree-ish>` are removed, to make them
match `<tree-ish>` exactly. 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>::
Branch to checkout; if it refers to a branch (i.e., a name that, 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 when prepended with "refs/heads/", is a valid ref), then that
@ -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, Tree to checkout from (when paths are given). If not specified,
the index will be used. 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 DETACHED HEAD
------------- -------------

View File

@ -8,8 +8,9 @@ git-restore - Restore working tree files
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] <pathspec>... '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-from-file=<file> [--pathspec-file-nul]
'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]
DESCRIPTION DESCRIPTION
----------- -----------
@ -113,6 +114,27 @@ in linkgit:git-checkout[1] for details.
appear in the `--source` tree are removed, to make them match appear in the `--source` tree are removed, to make them match
`<tree>` exactly. The default is no-overlay mode. `<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 EXAMPLES
-------- --------

View File

@ -29,6 +29,8 @@ static const char * const builtin_add_usage[] = {
static int patch_interactive, add_interactive, edit_interactive; static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes; static int take_worktree_changes;
static int add_renormalize; static int add_renormalize;
static int pathspec_file_nul;
static const char *pathspec_from_file;
struct update_callback_data { struct update_callback_data {
int flags; int flags;
@ -320,6 +322,8 @@ static struct option builtin_add_options[] = {
N_("override the executable bit of the listed files")), N_("override the executable bit of the listed files")),
OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo, OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
N_("warn when adding an embedded repository")), N_("warn when adding an embedded repository")),
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END(), OPT_END(),
}; };
@ -414,11 +418,17 @@ int cmd_add(int argc, const char **argv, const char *prefix)
builtin_add_usage, PARSE_OPT_KEEP_ARGV0); builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive) if (patch_interactive)
add_interactive = 1; 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)); 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)); return(edit_patch(argc, argv, prefix));
}
argc--; argc--;
argv++; argv++;
@ -430,10 +440,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
if (addremove && take_worktree_changes) if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible")); 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) if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run")); die(_("Option --ignore-missing can only be used together with --dry-run"));
@ -446,19 +452,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); 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 * Check the "pathspec '%s' did not match any files" block
* below before enabling new magic. * below before enabling new magic.
@ -468,6 +461,35 @@ int cmd_add(int argc, const char **argv, const char *prefix)
PATHSPEC_SYMLINK_LEADING_PATH, PATHSPEC_SYMLINK_LEADING_PATH,
prefix, argv); 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) if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt")); die(_("index file corrupt"));

View File

@ -70,6 +70,8 @@ struct checkout_opts {
int checkout_worktree; int checkout_worktree;
const char *ignore_unmerged_opt; const char *ignore_unmerged_opt;
int ignore_unmerged; int ignore_unmerged;
int pathspec_file_nul;
const char *pathspec_from_file;
const char *new_branch; const char *new_branch;
const char *new_branch_force; const char *new_branch_force;
@ -1480,6 +1482,8 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")), OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree, OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")), N_("do not limit pathspecs to sparse entries only")),
OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
OPT_PATHSPEC_FILE_NUL(&opts->pathspec_file_nul),
OPT_END() OPT_END()
}; };
struct option *newopts = parse_options_concat(prevopts, options); struct option *newopts = parse_options_concat(prevopts, options);
@ -1618,10 +1622,6 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
die(_("reference is not a tree: %s"), opts->from_treeish); die(_("reference is not a tree: %s"), opts->from_treeish);
} }
if (opts->accept_pathspec && !opts->empty_pathspec_ok && !argc &&
!opts->patch_mode) /* patch mode is special */
die(_("you must specify path(s) to restore"));
if (argc) { if (argc) {
parse_pathspec(&opts->pathspec, 0, parse_pathspec(&opts->pathspec, 0,
opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0, opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
@ -1641,10 +1641,33 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->force_detach) if (opts->force_detach)
die(_("git checkout: --detach does not take a path argument '%s'"), die(_("git checkout: --detach does not take a path argument '%s'"),
argv[0]); argv[0]);
}
if (opts->pathspec_from_file) {
if (opts->pathspec.nr)
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
if (opts->force_detach)
die(_("--pathspec-from-file is incompatible with --detach"));
if (opts->patch_mode)
die(_("--pathspec-from-file is incompatible with --patch"));
parse_pathspec_file(&opts->pathspec, 0,
0,
prefix, opts->pathspec_from_file, opts->pathspec_file_nul);
} else if (opts->pathspec_file_nul) {
die(_("--pathspec-file-nul requires --pathspec-from-file"));
}
if (opts->pathspec.nr) {
if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge) if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n" die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index.")); "checking out of the index."));
} else {
if (opts->accept_pathspec && !opts->empty_pathspec_ok &&
!opts->patch_mode) /* patch mode is special */
die(_("you must specify path(s) to restore"));
} }
if (opts->new_branch) { if (opts->new_branch) {

139
t/t2026-checkout-pathspec-file.sh Executable file
View File

@ -0,0 +1,139 @@
#!/bin/sh
test_description='checkout --pathspec-from-file'
. ./test-lib.sh
test_tick
test_expect_success setup '
test_commit file0 &&
echo 1 >fileA.t &&
echo 1 >fileB.t &&
echo 1 >fileC.t &&
echo 1 >fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "files 1" &&
echo 2 >fileA.t &&
echo 2 >fileB.t &&
echo 2 >fileC.t &&
echo 2 >fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "files 2" &&
git tag checkpoint
'
restore_checkpoint () {
git reset --hard checkpoint
}
verify_expect () {
git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
test_cmp expect actual
}
test_expect_success '--pathspec-from-file from stdin' '
restore_checkpoint &&
echo fileA.t | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success '--pathspec-from-file from file' '
restore_checkpoint &&
echo fileA.t >list &&
git checkout --pathspec-from-file=list HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success 'NUL delimiters' '
restore_checkpoint &&
printf "fileA.t\0fileB.t\0" | git checkout --pathspec-from-file=- --pathspec-file-nul HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'LF delimiters' '
restore_checkpoint &&
printf "fileA.t\nfileB.t\n" | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'no trailing delimiter' '
restore_checkpoint &&
printf "fileA.t\nfileB.t" | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'CRLF delimiters' '
restore_checkpoint &&
printf "fileA.t\r\nfileB.t\r\n" | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'quotes' '
restore_checkpoint &&
printf "\"file\\101.t\"" | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success 'quotes not compatible with --pathspec-file-nul' '
restore_checkpoint &&
printf "\"file\\101.t\"" >list &&
test_must_fail git checkout --pathspec-from-file=list --pathspec-file-nul HEAD^1
'
test_expect_success 'only touches what was listed' '
restore_checkpoint &&
printf "fileB.t\nfileC.t\n" | git checkout --pathspec-from-file=- HEAD^1 &&
cat >expect <<-\EOF &&
M fileB.t
M fileC.t
EOF
verify_expect
'
test_done

139
t/t2072-restore-pathspec-file.sh Executable file
View File

@ -0,0 +1,139 @@
#!/bin/sh
test_description='restore --pathspec-from-file'
. ./test-lib.sh
test_tick
test_expect_success setup '
test_commit file0 &&
echo 1 >fileA.t &&
echo 1 >fileB.t &&
echo 1 >fileC.t &&
echo 1 >fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "files 1" &&
echo 2 >fileA.t &&
echo 2 >fileB.t &&
echo 2 >fileC.t &&
echo 2 >fileD.t &&
git add fileA.t fileB.t fileC.t fileD.t &&
git commit -m "files 2" &&
git tag checkpoint
'
restore_checkpoint () {
git reset --hard checkpoint
}
verify_expect () {
git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
test_cmp expect actual
}
test_expect_success '--pathspec-from-file from stdin' '
restore_checkpoint &&
echo fileA.t | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success '--pathspec-from-file from file' '
restore_checkpoint &&
echo fileA.t >list &&
git restore --pathspec-from-file=list --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success 'NUL delimiters' '
restore_checkpoint &&
printf "fileA.t\0fileB.t\0" | git restore --pathspec-from-file=- --pathspec-file-nul --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'LF delimiters' '
restore_checkpoint &&
printf "fileA.t\nfileB.t\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'no trailing delimiter' '
restore_checkpoint &&
printf "fileA.t\nfileB.t" | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'CRLF delimiters' '
restore_checkpoint &&
printf "fileA.t\r\nfileB.t\r\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
M fileB.t
EOF
verify_expect
'
test_expect_success 'quotes' '
restore_checkpoint &&
printf "\"file\\101.t\"" | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileA.t
EOF
verify_expect
'
test_expect_success 'quotes not compatible with --pathspec-file-nul' '
restore_checkpoint &&
printf "\"file\\101.t\"" >list &&
test_must_fail git restore --pathspec-from-file=list --pathspec-file-nul --source=HEAD^1
'
test_expect_success 'only touches what was listed' '
restore_checkpoint &&
printf "fileB.t\nfileC.t\n" | git restore --pathspec-from-file=- --source=HEAD^1 &&
cat >expect <<-\EOF &&
M fileB.t
M fileC.t
EOF
verify_expect
'
test_done

127
t/t3704-add-pathspec-file.sh Executable file
View File

@ -0,0 +1,127 @@
#!/bin/sh
test_description='add --pathspec-from-file'
. ./test-lib.sh
test_tick
test_expect_success setup '
test_commit file0 &&
echo A >fileA.t &&
echo B >fileB.t &&
echo C >fileC.t &&
echo D >fileD.t
'
restore_checkpoint () {
git reset
}
verify_expect () {
git status --porcelain --untracked-files=no -- fileA.t fileB.t fileC.t fileD.t >actual &&
test_cmp expect actual
}
test_expect_success '--pathspec-from-file from stdin' '
restore_checkpoint &&
echo fileA.t | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileA.t
EOF
verify_expect
'
test_expect_success '--pathspec-from-file from file' '
restore_checkpoint &&
echo fileA.t >list &&
git add --pathspec-from-file=list &&
cat >expect <<-\EOF &&
A fileA.t
EOF
verify_expect
'
test_expect_success 'NUL delimiters' '
restore_checkpoint &&
printf "fileA.t\0fileB.t\0" | git add --pathspec-from-file=- --pathspec-file-nul &&
cat >expect <<-\EOF &&
A fileA.t
A fileB.t
EOF
verify_expect
'
test_expect_success 'LF delimiters' '
restore_checkpoint &&
printf "fileA.t\nfileB.t\n" | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileA.t
A fileB.t
EOF
verify_expect
'
test_expect_success 'no trailing delimiter' '
restore_checkpoint &&
printf "fileA.t\nfileB.t" | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileA.t
A fileB.t
EOF
verify_expect
'
test_expect_success 'CRLF delimiters' '
restore_checkpoint &&
printf "fileA.t\r\nfileB.t\r\n" | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileA.t
A fileB.t
EOF
verify_expect
'
test_expect_success 'quotes' '
restore_checkpoint &&
printf "\"file\\101.t\"" | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileA.t
EOF
verify_expect
'
test_expect_success 'quotes not compatible with --pathspec-file-nul' '
restore_checkpoint &&
printf "\"file\\101.t\"" >list &&
test_must_fail git add --pathspec-from-file=list --pathspec-file-nul
'
test_expect_success 'only touches what was listed' '
restore_checkpoint &&
printf "fileB.t\nfileC.t\n" | git add --pathspec-from-file=- &&
cat >expect <<-\EOF &&
A fileB.t
A fileC.t
EOF
verify_expect
'
test_done

View File

@ -1438,6 +1438,8 @@ test_expect_success 'double dash "git checkout"' '
--no-guess Z --no-guess Z
--no-... Z --no-... Z
--overlay Z --overlay Z
--pathspec-file-nul Z
--pathspec-from-file=Z
EOF EOF
' '