Skip to content

Commit f3cfeb3

Browse files
committed
Merge branch 'dl/checkout-p-merge-base'
"git checkout -p A...B [-- <path>]" did not work, even though the same command without "-p" correctly used the merge-base between commits A and B. * dl/checkout-p-merge-base: t2016: add a NEEDSWORK about the PERL prerequisite add-patch: add NEEDSWORK about comparing commits Doc: document "A...B" form for <tree-ish> in checkout and switch builtin/checkout: fix `git checkout -p HEAD...` bug
2 parents 40696c6 + 35166b1 commit f3cfeb3

7 files changed

+56
-1
lines changed

Documentation/git-checkout.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
351351
<tree-ish>::
352352
Tree to checkout from (when paths are given). If not specified,
353353
the index will be used.
354+
+
355+
As a special case, you may use `"A...B"` as a shortcut for the
356+
merge base of `A` and `B` if there is exactly one merge base. You can
357+
leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
354358

355359
\--::
356360
Do not interpret any more arguments as options.

Documentation/git-restore.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ OPTIONS
4040
+
4141
If not specified, the contents are restored from `HEAD` if `--staged` is
4242
given, otherwise from the index.
43+
+
44+
As a special case, you may use `"A...B"` as a shortcut for the
45+
merge base of `A` and `B` if there is exactly one merge base. You can
46+
leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
4347

4448
-p::
4549
--patch::

add-patch.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,14 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
16951695
if (mode == ADD_P_STASH)
16961696
s.mode = &patch_mode_stash;
16971697
else if (mode == ADD_P_RESET) {
1698+
/*
1699+
* NEEDSWORK: Instead of comparing to the literal "HEAD",
1700+
* compare the commit objects instead so that other ways of
1701+
* saying the same thing (such as "@") are also handled
1702+
* appropriately.
1703+
*
1704+
* This applies to the cases below too.
1705+
*/
16981706
if (!revision || !strcmp(revision, "HEAD"))
16991707
s.mode = &patch_mode_reset_head;
17001708
else

builtin/checkout.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,19 @@ static int checkout_paths(const struct checkout_opts *opts,
471471

472472
if (opts->patch_mode) {
473473
const char *patch_mode;
474+
const char *rev = new_branch_info->name;
475+
char rev_oid[GIT_MAX_HEXSZ + 1];
476+
477+
/*
478+
* Since rev can be in the form of `<a>...<b>` (which is not
479+
* recognized by diff-index), we will always replace the name
480+
* with the hex of the commit (whether it's in `...` form or
481+
* not) for the run_add_interactive() machinery to work
482+
* properly. However, there is special logic for the HEAD case
483+
* so we mustn't replace that.
484+
*/
485+
if (rev && strcmp(rev, "HEAD"))
486+
rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
474487

475488
if (opts->checkout_index && opts->checkout_worktree)
476489
patch_mode = "--patch=checkout";
@@ -481,7 +494,7 @@ static int checkout_paths(const struct checkout_opts *opts,
481494
else
482495
BUG("either flag must have been set, worktree=%d, index=%d",
483496
opts->checkout_worktree, opts->checkout_index);
484-
return run_add_interactive(new_branch_info->name, patch_mode, &opts->pathspec);
497+
return run_add_interactive(rev, patch_mode, &opts->pathspec);
485498
}
486499

487500
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);

git-add--interactive.perl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,13 @@ sub process_args {
18301830
$arg = shift @ARGV or die __("missing --");
18311831
if ($arg ne '--') {
18321832
$patch_mode_revision = $arg;
1833+
1834+
# NEEDSWORK: Instead of comparing to the literal "HEAD",
1835+
# compare the commit objects instead so that other ways of
1836+
# saying the same thing (such as "@") are also handled
1837+
# appropriately.
1838+
#
1839+
# This applies to the cases below too.
18331840
$patch_mode = ($arg eq 'HEAD' ?
18341841
'reset_head' : 'reset_nothead');
18351842
$arg = shift @ARGV or die __("missing --");

t/t2016-checkout-patch.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ test_expect_success PERL 'setup' '
1818

1919
# note: bar sorts before dir/foo, so the first 'n' is always to skip 'bar'
2020

21+
# NEEDSWORK: Since the builtin add-p is used when $GIT_TEST_ADD_I_USE_BUILTIN
22+
# is given, we should replace the PERL prerequisite with an ADD_I prerequisite
23+
# which first checks if $GIT_TEST_ADD_I_USE_BUILTIN is defined before checking
24+
# PERL.
2125
test_expect_success PERL 'saying "n" does nothing' '
2226
set_and_save_state dir/foo work head &&
2327
test_write_lines n n | git checkout -p &&
@@ -59,6 +63,13 @@ test_expect_success PERL 'git checkout -p HEAD with change already staged' '
5963
verify_state dir/foo head head
6064
'
6165

66+
test_expect_success PERL 'git checkout -p HEAD^...' '
67+
# the third n is to get out in case it mistakenly does not apply
68+
test_write_lines n y n | git checkout -p HEAD^... &&
69+
verify_saved_state bar &&
70+
verify_state dir/foo parent parent
71+
'
72+
6273
test_expect_success PERL 'git checkout -p HEAD^' '
6374
# the third n is to get out in case it mistakenly does not apply
6475
test_write_lines n y n | git checkout -p HEAD^ &&

t/t2071-restore-patch.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ test_expect_success PERL 'git restore -p --source=HEAD^' '
6060
verify_state dir/foo parent index
6161
'
6262

63+
test_expect_success PERL 'git restore -p --source=HEAD^...' '
64+
set_state dir/foo work index &&
65+
# the third n is to get out in case it mistakenly does not apply
66+
test_write_lines n y n | git restore -p --source=HEAD^... &&
67+
verify_saved_state bar &&
68+
verify_state dir/foo parent index
69+
'
70+
6371
test_expect_success PERL 'git restore -p handles deletion' '
6472
set_state dir/foo work index &&
6573
rm dir/foo &&

0 commit comments

Comments
 (0)