]> git.ipfire.org Git - thirdparty/git.git/commitdiff
git-apply: skip threeway in add / rename cases
authorJerry Zhang <jerry@skydio.com>
Fri, 17 Dec 2021 23:29:02 +0000 (15:29 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 Dec 2021 20:39:45 +0000 (12:39 -0800)
Certain invocations of "git apply --3way" will attempt threeway and
fail due to missing objects, even though git is able to fall back on
apply_fragments and apply the patch successfully with a return value
of 0. To fix, return early from try_threeway() in the following
cases:

 - When the patch is a rename and no lines have changed. In this
   case, "git diff" doesn't record the blob info, so 3way is neither
   possible nor necessary.

 - When the patch is an addition and there is no add/add conflict,
   i.e. direct_to_threeway is false. In this case, threeway will
   fail since the preimage is not in cache, but isn't necessary
   anyway since there is no conflict.

This fixes a few unecessary error messages when applying these kinds
of patches with --3way.

It also fixes a reported issue where applying a concatenation of
several git produced patches will fail when those patches involve a
deletion followed by creation of the same file.  Add a test for this
case too.  (test provided by <i@zenithal.me>)

Signed-off-by: Jerry Zhang <jerry@skydio.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
apply.c
t/t4108-apply-threeway.sh

diff --git a/apply.c b/apply.c
index 43a0aebf4eec85fa6b0a69f655c0224aa14f29e5..64b226acd9b6af6e15bfbe8f55ddb460c0984075 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -3582,7 +3582,9 @@ static int try_threeway(struct apply_state *state,
 
        /* No point falling back to 3-way merge in these cases */
        if (patch->is_delete ||
-           S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
+           S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode) ||
+           (patch->is_new && !patch->direct_to_threeway) ||
+           (patch->is_rename && !patch->lines_added && !patch->lines_deleted))
                return -1;
 
        /* Preimage the patch was prepared for */
index cc3aa3314a3448cd1d5c845ce9803f0877db83ce..c558282bc0947548760b0e0cfce68f29f8dc2835 100755 (executable)
@@ -275,4 +275,22 @@ test_expect_success 'apply full-index patch with 3way' '
        git apply --3way --index bin.diff
 '
 
+test_expect_success 'apply delete then new patch with 3way' '
+       git reset --hard main &&
+       test_write_lines 2 > delnew &&
+       git add delnew &&
+       git diff --cached >> new.patch &&
+       git reset --hard &&
+       test_write_lines 1 > delnew &&
+       git add delnew &&
+       git commit -m "delnew" &&
+       rm delnew &&
+       git diff >> delete-then-new.patch &&
+       cat new.patch >> delete-then-new.patch &&
+
+       git checkout -- . &&
+       # Apply must succeed.
+       git apply --3way delete-then-new.patch
+'
+
 test_done