From: Denton Liu <liu.denton@gmail.com>
To: Git Mailing List <git@vger.kernel.org>
Subject: [PATCH 1/2] builtin/checkout: fix `git checkout -p HEAD...` bug
Date: Sun, 4 Oct 2020 05:30:33 -0700 [thread overview]
Message-ID: <54f221411f4ec60a88521c376a1c77fa0a3e7553.1601814601.git.liu.denton@gmail.com> (raw)
In-Reply-To: <cover.1601814601.git.liu.denton@gmail.com>
Running `git checkout -p` with a merge-base rev results in an error:
$ git checkout -p HEAD...
usage: git diff-index [-m] [--cached] [<common-diff-options>] <tree-ish> [<path>...]
common diff options:
-z output diff-raw with lines terminated with NUL.
-p output patch format.
-u synonym for -p.
--patch-with-raw
output both a patch and the diff-raw format.
--stat show diffstat instead of patch.
--numstat show numeric diffstat instead of patch.
--patch-with-stat
output a patch and prepend its diffstat.
--name-only show only names of changed files.
--name-status show names and status of changed files.
--full-index show full object name on index lines.
--abbrev=<n> abbreviate object names in diff-tree header and diff-raw.
-R swap input file pairs.
-B detect complete rewrites.
-M detect renames.
-C detect copies.
--find-copies-harder
try unchanged files as candidate for copy detection.
-l<n> limit rename attempts up to <n> paths.
-O<file> reorder diffs according to the <file>.
-S<string> find filepair whose only one side contains the string.
--pickaxe-all
show all files diff when -S is used and hit is found.
-a --text treat all files as text.
Cannot close git diff-index --cached --numstat --summary HEAD... -- () at <redacted>/libexec/git-core/git-add--interactive line 183.
This happens because checkout passes the literal argument (in the
example, `HEAD...`) to diff-index which does not recognise merge-base
revs.
Fix this by using the hex of the found commit instead of the given name.
Note that "HEAD" is handled specially in run_add_interactive() so it's
explicitly not changed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
builtin/checkout.c | 14 +++++++++++++-
t/t2016-checkout-patch.sh | 7 +++++++
t/t2071-restore-patch.sh | 8 ++++++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0951f8fee5..95122e16ed 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -471,6 +471,18 @@ static int checkout_paths(const struct checkout_opts *opts,
if (opts->patch_mode) {
const char *patch_mode;
+ const char *rev = new_branch_info->name;
+ char rev_oid[GIT_MAX_HEXSZ + 1];
+
+ /*
+ * Since rev can be in the form of `<a>...<b>`, we must replace
+ * the name with the hex of the commit for the
+ * run_add_interactive() machinery to work properly. However,
+ * there is special logic for the HEAD case so we mustn't
+ * replace that.
+ */
+ if (rev && strcmp(rev, "HEAD"))
+ rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
if (opts->checkout_index && opts->checkout_worktree)
patch_mode = "--patch=checkout";
@@ -481,7 +493,7 @@ static int checkout_paths(const struct checkout_opts *opts,
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return run_add_interactive(new_branch_info->name, patch_mode, &opts->pathspec);
+ return run_add_interactive(rev, patch_mode, &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh
index 47aeb0b167..999620e507 100755
--- a/t/t2016-checkout-patch.sh
+++ b/t/t2016-checkout-patch.sh
@@ -59,6 +59,13 @@ test_expect_success PERL 'git checkout -p HEAD with change already staged' '
verify_state dir/foo head head
'
+test_expect_success PERL 'git checkout -p HEAD^...' '
+ # 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 parent parent
+'
+
test_expect_success PERL 'git checkout -p HEAD^' '
# the third n is to get out in case it mistakenly does not apply
test_write_lines n y n | git checkout -p HEAD^ &&
diff --git a/t/t2071-restore-patch.sh b/t/t2071-restore-patch.sh
index 98b2476e7c..b5c5c0ff7e 100755
--- a/t/t2071-restore-patch.sh
+++ b/t/t2071-restore-patch.sh
@@ -60,6 +60,14 @@ test_expect_success PERL 'git restore -p --source=HEAD^' '
verify_state dir/foo parent 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 parent index
+'
+
test_expect_success PERL 'git restore -p handles deletion' '
set_state dir/foo work index &&
rm dir/foo &&
--
2.28.0.942.g77c4c6094c
next prev parent reply other threads:[~2020-10-04 12:30 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-04 12:30 [PATCH 0/2] checkout/restore: fix `git checkout -p HEAD...` bug Denton Liu
2020-10-04 12:30 ` Denton Liu [this message]
2020-10-04 18:02 ` [PATCH 1/2] builtin/checkout: " Junio C Hamano
2020-10-04 12:30 ` [PATCH 2/2] Doc: document "A...B" form for <tree-ish> in checkout and switch Denton Liu
2020-10-07 7:56 ` [PATCH v2 0/4] checkout/restore: fix `git checkout -p HEAD...` bug Denton Liu
2020-10-07 7:56 ` [PATCH v2 1/4] builtin/checkout: " Denton Liu
2020-10-07 7:56 ` [PATCH v2 2/4] Doc: document "A...B" form for <tree-ish> in checkout and switch Denton Liu
2020-10-07 7:56 ` [PATCH v2 3/4] add-patch: add NEEDSWORK about comparing commits Denton Liu
2020-10-07 7:56 ` [PATCH v2 4/4] t2016: add a NEEDSWORK about the PERL prerequisite Denton Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54f221411f4ec60a88521c376a1c77fa0a3e7553.1601814601.git.liu.denton@gmail.com \
--to=liu.denton@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).