From: Jerry Zhang <hidden> Date: 2021-12-17 22:43:35
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 prints
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. Added a
test for this case too.
Signed-off-by: Jerry Zhang <redacted>
(test provided by [off-list ref])
---
V2->V3:
- Updated commit title and message to be more
general, and indicate that it also fixes the
delete-then-new bug. Added test.
apply.c | 4 +++-
t/t4108-apply-threeway.sh | 14 ++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
@@ -3580,11 +3580,13 @@ static int try_threeway(struct apply_state *state,char*img;structimagetmp_image;/* 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 */if(patch->is_new)write_object_file("",0,blob_type,&pre_oid);
@@ -273,6 +273,20 @@ test_expect_success 'apply full-index patch with 3way' '# Apply must succeed.gitapply--3way--indexbin.diff'+test_expect_success'apply delete then new patch with 3way''+gitreset--hardmain&&+test_write_lines1>delnew&&+gitadddelnew&&+gitcommit-m"delnew"&&+rmdelnew&&+gitdiff>>delete-then-new.patch&&+gitdiffHEAD~HEAD>>delete-then-new.patch&&++gitcheckout--.&&+# Apply must succeed.+gitapply--3waydelete-then-new.patch+'+ test_done
From: Jerry Zhang <hidden> Date: 2021-12-17 23:29:08
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 prints
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. Added a
test for this case too.
(test provided by [off-list ref])
Signed-off-by: Jerry Zhang <redacted>
---
V3->V4:
- Fix test bug where it wasn't actually
exercising the correct failure mode.
apply.c | 4 +++-
t/t4108-apply-threeway.sh | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
@@ -3580,11 +3580,13 @@ static int try_threeway(struct apply_state *state,char*img;structimagetmp_image;/* 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 */if(patch->is_new)write_object_file("",0,blob_type,&pre_oid);
@@ -273,6 +273,24 @@ test_expect_success 'apply full-index patch with 3way' '# Apply must succeed.gitapply--3way--indexbin.diff'+test_expect_success'apply delete then new patch with 3way''+gitreset--hardmain&&+test_write_lines2>delnew&&+gitadddelnew&&+gitdiff--cached>>new.patch&&+gitreset--hard&&+test_write_lines1>delnew&&+gitadddelnew&&+gitcommit-m"delnew"&&+rmdelnew&&+gitdiff>>delete-then-new.patch&&+catnew.patch>>delete-then-new.patch&&++gitcheckout--.&&+# Apply must succeed.+gitapply--3waydelete-then-new.patch+'+ test_done
On Fri, Dec 17, 2021 at 03:29:02PM -0800, Jerry Zhang wrote:
quoted hunk
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 prints
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. Added a
test for this case too.
(test provided by [off-list ref])
Signed-off-by: Jerry Zhang <redacted>
---
V3->V4:
- Fix test bug where it wasn't actually
exercising the correct failure mode.
apply.c | 4 +++-
t/t4108-apply-threeway.sh | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
@@ -3580,11 +3580,13 @@ static int try_threeway(struct apply_state *state,char*img;structimagetmp_image;/* 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 */if(patch->is_new)write_object_file("",0,blob_type,&pre_oid);
@@ -273,6 +273,24 @@ test_expect_success 'apply full-index patch with 3way' '# Apply must succeed.gitapply--3way--indexbin.diff'+test_expect_success'apply delete then new patch with 3way''+gitreset--hardmain&&+test_write_lines2>delnew&&+gitadddelnew&&+gitdiff--cached>>new.patch&&+gitreset--hard&&+test_write_lines1>delnew&&+gitadddelnew&&+gitcommit-m"delnew"&&+rmdelnew&&+gitdiff>>delete-then-new.patch&&+catnew.patch>>delete-then-new.patch&&++gitcheckout--.&&+# Apply must succeed.+gitapply--3waydelete-then-new.patch+'+ test_done
--
2.32.0.1314.g6ed4fcc4cc
This fully resolved the issue I mentioned in
https://lore.kernel.org/git/YVmTKWlOFr+IwzzI@Sun/
Tested-by: Hongren (Zenithal) Zheng <i@zenithal.me>
Also, I would prefer a
Reported-by: Hongren (Zenithal) Zheng <i@zenithal.me>
tag or even
Co-authored-by: Hongren (Zenithal) Zheng [off-list ref]
if you deem it appropriate.
From: Jerry Zhang <hidden> Date: 2022-01-05 23:30:51
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 prints
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. Added a
test for this case too.
Reported-by: Hongren (Zenithal) Zheng <i@zenithal.me>
Signed-off-by: Jerry Zhang <redacted>
---
V5: updated reported-by
apply.c | 4 +++-
t/t4108-apply-threeway.sh | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
@@ -3580,11 +3580,13 @@ static int try_threeway(struct apply_state *state,char*img;structimagetmp_image;/* 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 */if(patch->is_new)write_object_file("",0,blob_type,&pre_oid);
@@ -273,6 +273,24 @@ test_expect_success 'apply full-index patch with 3way' '# Apply must succeed.gitapply--3way--indexbin.diff'+test_expect_success'apply delete then new patch with 3way''+gitreset--hardmain&&+test_write_lines2>delnew&&+gitadddelnew&&+gitdiff--cached>>new.patch&&+gitreset--hard&&+test_write_lines1>delnew&&+gitadddelnew&&+gitcommit-m"delnew"&&+rmdelnew&&+gitdiff>>delete-then-new.patch&&+catnew.patch>>delete-then-new.patch&&++gitcheckout--.&&+# Apply must succeed.+gitapply--3waydelete-then-new.patch+'+ test_done