Re: [PATCH] apply: fix delete-then-new patch fail with 3way

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Oct 03, 2021 at 07:25:29PM +0800, Hongren (Zenithal) Zheng wrote:
> For one single patch FILE containing both deletion and creation
> of the same file, applying with three way would fail, which should not.
> 
> When git-apply processes one single patch FILE, patches inside it
> would be applied before write_out_results(), thus it may occur
> that one file being deleted but it is still in the index when
> applying a new patch, in this case, try_threeway() would find
> an old file thus causing merge conflict.
> 
> To avoid this, git-apply should fall back to directly apply
> when it turns out to be such cases.
> 
> Signed-off-by: Hongren (Zenithal) Zheng <i@xxxxxxxxxxx>
> ---
>  apply.c                   | 13 ++++++++++++-
>  t/t4108-apply-threeway.sh | 20 ++++++++++++++++++++
>  2 files changed, 32 insertions(+), 1 deletion(-)
> 
> More notes below:
> 
> This patch is a bugfix hence it is based on branch `maint`.
> 
> This bug is caused by a behavior change since 2.32 where
> git apply --3way would try 3-way first before directly apply.
> 
> Interestingly, if the deletion patch and the addition patch are in
> two patch files, applying with three way would go on cleanly.
> 
> As indicated in commit msg, if these two patches are in different
> patch files, write_out_results() would be called twice, unlike when
> they are in the same file, write_out_results() would be called altogether
> after all patches being applied.
> 
> One way to fix this is to check for this kind of conditions, which
> is presented in this patch.
> 
> A side note though, this kind of checks and fixes already exist
> as indicated by variable ok_if_exists in function check_patch().
> See the comment around this variable for more info.
> 
> This kind of fixes is really dark magic.
> 
> Another way, which I do not adopt because it requires major refactor
> but it is more clean and understandable, is to change the way
> write_out_resultes() is called, namely instead of calling it
> after all patches being applied in one patch FILE, after each patch
> being applied, we write_out_result immediately thus deleting one file
> would immediately delete the file from the index.
> 
> The man page of `patch` says: If the patch file contains more than
> one patch, patch tries to apply each of them as if they came
> from separate patch files. So I think this way is more standardized.
> 
> However, as also indicated by comments around variable
> ok_if_exists in function check_patch(), consequtive patches in one
> file have special meanings as endowed by diff.c::run_diff()
> 
> I do not know how to handle this, so I just send it as notes.
> 
> More comment: this problem or this kind of fix may be related to 
> https://lore.kernel.org/git/YR1OszUm08BMAE1N@xxxxxxxxxxxxxxxxxxxxxxx/
> 
> diff --git a/apply.c b/apply.c
> index 44bc31d6eb5b42d4077eff458246cde376cb6785..3fa96fcc781bdc27f66a35442f27972a0e84ea77 100644
> --- a/apply.c
> +++ b/apply.c
> @@ -3558,8 +3558,19 @@ static int try_threeway(struct apply_state *state,
>  	char *img;
>  	struct image tmp_image;
>  
> -	/* No point falling back to 3-way merge in these cases */
> +	/*
> +	 * No point using 3-way merge in these cases
> +	 *
> +	 * For patch->is_new, if new_name does not exist in the index,
> +	 * we can directly apply; if new_name exists,
> +	 * according to ok_if_exists in check_patch(),
> +	 * there are cases where new_name gets deleted in previous patches
> +	 * BUT still exists in index, in this case, we can directly apply.
> +	 */
>  	if (patch->is_delete ||
> +	      (patch->is_new &&
> +	       (index_name_pos(state->repo->index, patch->new_name, strlen(patch->new_name)) < 0 ||
> +		was_deleted(in_fn_table(state, patch->new_name)))) ||
>  	    S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
>  		return -1;
>  
> diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
> index 65147efdea9a00e30d156e6f4d5d72a3987f230d..14bbb393430ed57a236d25aa568a0fdc6d221a6d 100755
> --- a/t/t4108-apply-threeway.sh
> +++ b/t/t4108-apply-threeway.sh
> @@ -230,4 +230,24 @@ test_expect_success 'apply with --3way --cached and conflicts' '
>  	test_cmp expect.diff actual.diff
>  '
>  
> +test_expect_success 'apply delete then new patch with 3way' '
> +	git reset --hard main &&
> +	test_write_lines 1 > delnew &&
> +	git add delnew &&
> +	git commit -m "delnew" &&
> +	cat >delete-then-new.patch <<-\EOF &&
> +	--- a/delnew
> +	+++ /dev/null
> +	@@ -1 +0,0 @@
> +	-1
> +	--- /dev/null
> +	+++ b/delnew
> +	@@ -0,0 +1 @@
> +	+2
> +	EOF
> +
> +	# Apply must succeed.
> +	git apply --3way delete-then-new.patch
> +'
> +
>  test_done
> -- 
> 2.32.0
> 

Is there any updates regarding this patch?



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux