reset: support the --pathspec-from-file
option
Decisions taken for simplicity: 1) For now, `--pathspec-from-file` is declared incompatible with `--patch`, even when <file> is not `stdin`. Such use case it not really expected. Also, it is harder to support in `git commit`, so I decided to make it incompatible in all places. 2) It is not allowed to pass pathspec in both args and file. Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
d137b50756
commit
64bac8df97
@ -9,18 +9,20 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'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>] [--] <pathspec>...::
|
||||
This form resets the index entries for all paths that match the
|
||||
'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.)
|
||||
+
|
||||
@ -101,6 +103,19 @@ 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.
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
static const char * const git_reset_usage[] = {
|
||||
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
||||
N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
|
||||
N_("git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"),
|
||||
N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
|
||||
NULL
|
||||
};
|
||||
@ -284,8 +285,8 @@ static int git_reset_config(const char *var, const char *value, void *cb)
|
||||
int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int reset_type = NONE, update_ref_status = 0, quiet = 0;
|
||||
int patch_mode = 0, unborn;
|
||||
const char *rev;
|
||||
int patch_mode = 0, pathspec_file_nul = 0, unborn;
|
||||
const char *rev, *pathspec_from_file = NULL;
|
||||
struct object_id oid;
|
||||
struct pathspec pathspec;
|
||||
int intent_to_add = 0;
|
||||
@ -306,6 +307,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
|
||||
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
||||
N_("record only the fact that removed paths will be added later")),
|
||||
OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
|
||||
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -316,6 +319,20 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
|
||||
|
||||
if (pathspec_from_file) {
|
||||
if (patch_mode)
|
||||
die(_("--pathspec-from-file is incompatible with --patch"));
|
||||
|
||||
if (pathspec.nr)
|
||||
die(_("--pathspec-from-file is incompatible with pathspec arguments"));
|
||||
|
||||
parse_pathspec_file(&pathspec, 0,
|
||||
PATHSPEC_PREFER_FULL,
|
||||
prefix, pathspec_from_file, pathspec_file_nul);
|
||||
} else if (pathspec_file_nul) {
|
||||
die(_("--pathspec-file-nul requires --pathspec-from-file"));
|
||||
}
|
||||
|
||||
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
|
||||
if (unborn) {
|
||||
/* reset on unborn branch: treat as reset to empty tree */
|
||||
|
155
t/t7107-reset-pathspec-file.sh
Executable file
155
t/t7107-reset-pathspec-file.sh
Executable file
@ -0,0 +1,155 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='reset --pathspec-from-file'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_tick
|
||||
|
||||
test_expect_success setup '
|
||||
echo A >fileA.t &&
|
||||
echo B >fileB.t &&
|
||||
echo C >fileC.t &&
|
||||
echo D >fileD.t &&
|
||||
git add . &&
|
||||
git commit --include . -m "Commit" &&
|
||||
git tag checkpoint
|
||||
'
|
||||
|
||||
restore_checkpoint () {
|
||||
git reset --hard checkpoint
|
||||
}
|
||||
|
||||
verify_expect () {
|
||||
git status --porcelain -- fileA.t fileB.t fileC.t fileD.t >actual &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
|
||||
test_expect_success '--pathspec-from-file from stdin' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t &&
|
||||
echo fileA.t | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success '--pathspec-from-file from file' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t &&
|
||||
echo fileA.t >list &&
|
||||
git reset --pathspec-from-file=list &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'NUL delimiters' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t fileB.t &&
|
||||
printf "fileA.t\0fileB.t\0" | git reset --pathspec-from-file=- --pathspec-file-nul &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
D fileB.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'LF delimiters' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t fileB.t &&
|
||||
printf "fileA.t\nfileB.t\n" | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
D fileB.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'no trailing delimiter' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t fileB.t &&
|
||||
printf "fileA.t\nfileB.t" | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
D fileB.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'CRLF delimiters' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t fileB.t &&
|
||||
printf "fileA.t\r\nfileB.t\r\n" | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
D fileB.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'quotes' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t &&
|
||||
printf "\"file\\101.t\"" | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_expect_success 'quotes not compatible with --pathspec-file-nul' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t &&
|
||||
printf "\"file\\101.t\"" >list &&
|
||||
# Note: "git reset" has not yet learned to fail on wrong pathspecs
|
||||
git reset --pathspec-from-file=list --pathspec-file-nul &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
EOF
|
||||
test_must_fail verify_expect
|
||||
'
|
||||
|
||||
test_expect_success '--pathspec-from-file is not compatible with --soft or --hard' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t &&
|
||||
echo fileA.t >list &&
|
||||
test_must_fail git reset --soft --pathspec-from-file=list &&
|
||||
test_must_fail git reset --hard --pathspec-from-file=list
|
||||
'
|
||||
|
||||
test_expect_success 'only touches what was listed' '
|
||||
restore_checkpoint &&
|
||||
|
||||
git rm fileA.t fileB.t fileC.t fileD.t &&
|
||||
printf "fileB.t\nfileC.t\n" | git reset --pathspec-from-file=- &&
|
||||
|
||||
cat >expect <<-\EOF &&
|
||||
D fileA.t
|
||||
D fileB.t
|
||||
D fileC.t
|
||||
D fileD.t
|
||||
EOF
|
||||
verify_expect
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user