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:

committed by
Junio C Hamano

parent
d137b50756
commit
64bac8df97
@ -9,18 +9,20 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git reset' [-q] [<tree-ish>] [--] <pathspec>...
|
'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' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
|
||||||
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
|
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
In the first and second form, copy entries from `<tree-ish>` to the index.
|
In the first three forms, copy entries from `<tree-ish>` to the index.
|
||||||
In the third form, set the current branch head (`HEAD`) to `<commit>`,
|
In the last form, set the current branch head (`HEAD`) to `<commit>`,
|
||||||
optionally modifying index and working tree to match.
|
optionally modifying index and working tree to match.
|
||||||
The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
|
The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
|
||||||
|
|
||||||
'git reset' [-q] [<tree-ish>] [--] <pathspec>...::
|
'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
|
`<pathspec>` to their state at `<tree-ish>`. (It does not affect
|
||||||
the working tree or the current branch.)
|
the working tree or the current branch.)
|
||||||
+
|
+
|
||||||
@ -101,6 +103,19 @@ OPTIONS
|
|||||||
`reset.quiet` config option. `--quiet` and `--no-quiet` will
|
`reset.quiet` config option. `--quiet` and `--no-quiet` will
|
||||||
override the default behavior.
|
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.
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
static const char * const git_reset_usage[] = {
|
static const char * const git_reset_usage[] = {
|
||||||
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
||||||
N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
|
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>...]"),
|
N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
|
||||||
NULL
|
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 cmd_reset(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int reset_type = NONE, update_ref_status = 0, quiet = 0;
|
int reset_type = NONE, update_ref_status = 0, quiet = 0;
|
||||||
int patch_mode = 0, unborn;
|
int patch_mode = 0, pathspec_file_nul = 0, unborn;
|
||||||
const char *rev;
|
const char *rev, *pathspec_from_file = NULL;
|
||||||
struct object_id oid;
|
struct object_id oid;
|
||||||
struct pathspec pathspec;
|
struct pathspec pathspec;
|
||||||
int intent_to_add = 0;
|
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('p', "patch", &patch_mode, N_("select hunks interactively")),
|
||||||
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
||||||
N_("record only the fact that removed paths will be added later")),
|
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()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -316,6 +319,20 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
|||||||
PARSE_OPT_KEEP_DASHDASH);
|
PARSE_OPT_KEEP_DASHDASH);
|
||||||
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
|
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);
|
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
|
||||||
if (unborn) {
|
if (unborn) {
|
||||||
/* reset on unborn branch: treat as reset to empty tree */
|
/* 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
|
Reference in New Issue
Block a user