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>
/* 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 */
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