Merge branch 'gt/at-is-synonym-for-head-in-add-patch'

Teach "git checkout -p" and friends that "@" is a synonym for
"HEAD".

* gt/at-is-synonym-for-head-in-add-patch:
  add -p tests: remove PERL prerequisites
  add-patch: classify '@' as a synonym for 'HEAD'
This commit is contained in:
Junio C Hamano 2024-02-26 18:10:25 -08:00
commit 65462776c2
11 changed files with 88 additions and 78 deletions

View file

@ -1729,14 +1729,6 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
if (mode == ADD_P_STASH)
s.mode = &patch_mode_stash;
else if (mode == ADD_P_RESET) {
/*
* NEEDSWORK: Instead of comparing to the literal "HEAD",
* compare the commit objects instead so that other ways of
* saying the same thing (such as "@") are also handled
* appropriately.
*
* This applies to the cases below too.
*/
if (!revision || !strcmp(revision, "HEAD"))
s.mode = &patch_mode_reset_head;
else

View file

@ -1224,7 +1224,9 @@ static void setup_new_branch_info_and_source_tree(
struct tree **source_tree = &opts->source_tree;
struct object_id branch_rev;
new_branch_info->name = xstrdup(arg);
/* treat '@' as a shortcut for 'HEAD' */
new_branch_info->name = !strcmp(arg, "@") ? xstrdup("HEAD") :
xstrdup(arg);
setup_branch_path(new_branch_info);
if (!check_refname_format(new_branch_info->path, 0) &&

View file

@ -281,7 +281,9 @@ static void parse_args(struct pathspec *pathspec,
verify_filename(prefix, argv[0], 1);
}
}
*rev_ret = rev;
/* treat '@' as a shortcut for 'HEAD' */
*rev_ret = !strcmp("@", rev) ? "HEAD" : rev;
parse_pathspec(pathspec, 0,
PATHSPEC_PREFER_FULL |

View file

@ -38,26 +38,32 @@ test_expect_success 'git checkout -p with staged changes' '
verify_state dir/foo index index
'
test_expect_success 'git checkout -p HEAD with NO staged changes: abort' '
set_and_save_state dir/foo work head &&
test_write_lines n y n | git checkout -p HEAD &&
verify_saved_state bar &&
verify_saved_state dir/foo
'
for opt in "HEAD" "@"
do
test_expect_success "git checkout -p $opt with NO staged changes: abort" '
set_and_save_state dir/foo work head &&
test_write_lines n y n | git checkout -p $opt >output &&
verify_saved_state bar &&
verify_saved_state dir/foo &&
test_grep "Discard" output
'
test_expect_success 'git checkout -p HEAD with NO staged changes: apply' '
test_write_lines n y y | git checkout -p HEAD &&
verify_saved_state bar &&
verify_state dir/foo head head
'
test_expect_success "git checkout -p $opt with NO staged changes: apply" '
test_write_lines n y y | git checkout -p $opt >output &&
verify_saved_state bar &&
verify_state dir/foo head head &&
test_grep "Discard" output
'
test_expect_success 'git checkout -p HEAD with change already staged' '
set_state dir/foo index index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git checkout -p HEAD &&
verify_saved_state bar &&
verify_state dir/foo head head
'
test_expect_success "git checkout -p $opt with change already staged" '
set_state dir/foo index index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git checkout -p $opt >output &&
verify_saved_state bar &&
verify_state dir/foo head head &&
test_grep "Discard" output
'
done
test_expect_success 'git checkout -p HEAD^...' '
# the third n is to get out in case it mistakenly does not apply

View file

@ -45,6 +45,18 @@ test_expect_success 'checkout branch does not detach' '
check_not_detached
'
for opt in "HEAD" "@"
do
test_expect_success "checkout $opt no-op/don't detach" '
reset &&
cat .git/HEAD >expect &&
git checkout $opt &&
cat .git/HEAD >actual &&
check_not_detached &&
test_cmp expect actual
'
done
test_expect_success 'checkout tag detaches' '
reset &&
git checkout tag &&

View file

@ -113,7 +113,7 @@ test_expect_success 'checkout of branch from multiple remotes fails with advice'
test_grep ! "^hint: " stderr
'
test_expect_success PERL 'checkout -p with multiple remotes does not print advice' '
test_expect_success 'checkout -p with multiple remotes does not print advice' '
git checkout -B main &&
test_might_fail git branch -D foo &&

View file

@ -4,7 +4,7 @@ test_description='git restore --patch'
. ./lib-patch-mode.sh
test_expect_success PERL 'setup' '
test_expect_success 'setup' '
mkdir dir &&
echo parent >dir/foo &&
echo dummy >bar &&
@ -16,43 +16,47 @@ test_expect_success PERL 'setup' '
save_head
'
test_expect_success PERL 'restore -p without pathspec is fine' '
test_expect_success 'restore -p without pathspec is fine' '
echo q >cmd &&
git restore -p <cmd
'
# note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
test_expect_success PERL 'saying "n" does nothing' '
test_expect_success 'saying "n" does nothing' '
set_and_save_state dir/foo work head &&
test_write_lines n n | git restore -p &&
verify_saved_state bar &&
verify_saved_state dir/foo
'
test_expect_success PERL 'git restore -p' '
test_expect_success 'git restore -p' '
set_and_save_state dir/foo work head &&
test_write_lines n y | git restore -p &&
verify_saved_state bar &&
verify_state dir/foo head head
'
test_expect_success PERL 'git restore -p with staged changes' '
test_expect_success 'git restore -p with staged changes' '
set_state dir/foo work index &&
test_write_lines n y | git restore -p &&
verify_saved_state bar &&
verify_state dir/foo index index
'
test_expect_success PERL 'git restore -p --source=HEAD' '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=HEAD &&
verify_saved_state bar &&
verify_state dir/foo head index
'
for opt in "HEAD" "@"
do
test_expect_success "git restore -p --source=$opt" '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=$opt >output &&
verify_saved_state bar &&
verify_state dir/foo head index &&
test_grep "Discard" output
'
done
test_expect_success PERL 'git restore -p --source=HEAD^' '
test_expect_success 'git restore -p --source=HEAD^' '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=HEAD^ &&
@ -60,7 +64,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^' '
verify_state dir/foo parent index
'
test_expect_success PERL 'git restore -p --source=HEAD^...' '
test_expect_success 'git restore -p --source=HEAD^...' '
set_state dir/foo work index &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git restore -p --source=HEAD^... &&
@ -68,7 +72,7 @@ test_expect_success PERL 'git restore -p --source=HEAD^...' '
verify_state dir/foo parent index
'
test_expect_success PERL 'git restore -p handles deletion' '
test_expect_success 'git restore -p handles deletion' '
set_state dir/foo work index &&
rm dir/foo &&
test_write_lines n y | git restore -p &&
@ -81,21 +85,21 @@ test_expect_success PERL 'git restore -p handles deletion' '
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
# the failure case (and thus get out of the loop).
test_expect_success PERL 'path limiting works: dir' '
test_expect_success 'path limiting works: dir' '
set_state dir/foo work head &&
test_write_lines y n | git restore -p dir &&
verify_saved_state bar &&
verify_state dir/foo head head
'
test_expect_success PERL 'path limiting works: -- dir' '
test_expect_success 'path limiting works: -- dir' '
set_state dir/foo work head &&
test_write_lines y n | git restore -p -- dir &&
verify_saved_state bar &&
verify_state dir/foo head head
'
test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
test_expect_success 'path limiting works: HEAD^ -- dir' '
set_state dir/foo work head &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines y n n | git restore -p --source=HEAD^ -- dir &&
@ -103,7 +107,7 @@ test_expect_success PERL 'path limiting works: HEAD^ -- dir' '
verify_state dir/foo parent head
'
test_expect_success PERL 'path limiting works: foo inside dir' '
test_expect_success 'path limiting works: foo inside dir' '
set_state dir/foo work head &&
# the third n is to get out in case it mistakenly does not apply
test_write_lines y n n | (cd dir && git restore -p foo) &&
@ -111,7 +115,7 @@ test_expect_success PERL 'path limiting works: foo inside dir' '
verify_state dir/foo head head
'
test_expect_success PERL 'none of this moved HEAD' '
test_expect_success 'none of this moved HEAD' '
verify_saved_head
'

View file

@ -3,12 +3,6 @@
test_description='stash -p'
. ./lib-patch-mode.sh
if ! test_have_prereq PERL
then
skip_all='skipping stash -p tests, perl not available'
test_done
fi
test_expect_success 'setup' '
mkdir dir &&
echo parent > dir/foo &&

View file

@ -5,7 +5,7 @@ test_description='git reset --patch'
TEST_PASSES_SANITIZE_LEAK=true
. ./lib-patch-mode.sh
test_expect_success PERL 'setup' '
test_expect_success 'setup' '
mkdir dir &&
echo parent > dir/foo &&
echo dummy > bar &&
@ -19,42 +19,46 @@ test_expect_success PERL 'setup' '
# note: bar sorts before foo, so the first 'n' is always to skip 'bar'
test_expect_success PERL 'saying "n" does nothing' '
test_expect_success 'saying "n" does nothing' '
set_and_save_state dir/foo work work &&
test_write_lines n n | git reset -p &&
verify_saved_state dir/foo &&
verify_saved_state bar
'
test_expect_success PERL 'git reset -p' '
test_write_lines n y | git reset -p >output &&
verify_state dir/foo work head &&
verify_saved_state bar &&
test_grep "Unstage" output
'
for opt in "HEAD" "@" ""
do
test_expect_success "git reset -p $opt" '
set_and_save_state dir/foo work work &&
test_write_lines n y | git reset -p $opt >output &&
verify_state dir/foo work head &&
verify_saved_state bar &&
test_grep "Unstage" output
'
done
test_expect_success PERL 'git reset -p HEAD^' '
test_expect_success 'git reset -p HEAD^' '
test_write_lines n y | git reset -p HEAD^ >output &&
verify_state dir/foo work parent &&
verify_saved_state bar &&
test_grep "Apply" output
'
test_expect_success PERL 'git reset -p HEAD^^{tree}' '
test_expect_success 'git reset -p HEAD^^{tree}' '
test_write_lines n y | git reset -p HEAD^^{tree} >output &&
verify_state dir/foo work parent &&
verify_saved_state bar &&
test_grep "Apply" output
'
test_expect_success PERL 'git reset -p HEAD^:dir/foo (blob fails)' '
test_expect_success 'git reset -p HEAD^:dir/foo (blob fails)' '
set_and_save_state dir/foo work work &&
test_must_fail git reset -p HEAD^:dir/foo &&
verify_saved_state dir/foo &&
verify_saved_state bar
'
test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' '
test_expect_success 'git reset -p aaaaaaaa (unknown fails)' '
set_and_save_state dir/foo work work &&
test_must_fail git reset -p aaaaaaaa &&
verify_saved_state dir/foo &&
@ -66,27 +70,27 @@ test_expect_success PERL 'git reset -p aaaaaaaa (unknown fails)' '
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
# the failure case (and thus get out of the loop).
test_expect_success PERL 'git reset -p dir' '
test_expect_success 'git reset -p dir' '
set_state dir/foo work work &&
test_write_lines y n | git reset -p dir &&
verify_state dir/foo work head &&
verify_saved_state bar
'
test_expect_success PERL 'git reset -p -- foo (inside dir)' '
test_expect_success 'git reset -p -- foo (inside dir)' '
set_state dir/foo work work &&
test_write_lines y n | (cd dir && git reset -p -- foo) &&
verify_state dir/foo work head &&
verify_saved_state bar
'
test_expect_success PERL 'git reset -p HEAD^ -- dir' '
test_expect_success 'git reset -p HEAD^ -- dir' '
test_write_lines y n | git reset -p HEAD^ -- dir &&
verify_state dir/foo work parent &&
verify_saved_state bar
'
test_expect_success PERL 'none of this moved HEAD' '
test_expect_success 'none of this moved HEAD' '
verify_saved_head
'

View file

@ -34,7 +34,7 @@ test_expect_success 'reset $file' '
test_cmp expect actual
'
test_expect_success PERL 'reset -p' '
test_expect_success 'reset -p' '
rm .git/index &&
git add a &&
echo y >yes &&

View file

@ -3,12 +3,6 @@
test_description='hunk edit with "commit -p -m"'
. ./test-lib.sh
if ! test_have_prereq PERL
then
skip_all="skipping '$test_description' tests, perl not available"
test_done
fi
test_expect_success 'setup (initial)' '
echo line1 >file &&
git add file &&