merge-ort: fix bug with renormalization and rename/delete conflicts

Ever since commit a492d5331c ("merge-ort: ensure we consult df_conflict and path_conflicts", 2021-06-30), when renormalization is active AND a file is involved in a rename/delete conflict BUT the file is unmodified (either before or after renormalization), merge-ort was running into an assertion failure. Prior to that commit (or if assertions were compiled out), merge-ort would mis-merge instead, ignoring the rename/delete conflict and just deleting the file. Remove the assertions, fix the code appropriately, leave some good comments in the code, and add a testcase for this situation. Reported-by: Ralf Thielow <ralf.thielow@gmail.com> Signed-off-by: Elijah Newren <newren@gmail.com> Reviewed-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Dec 28, 2021 at 00:20 UTC d30126c20d5899f128facbd33ecf27163efe1326
2 files changed +42 -3
merge-ort.c
+16 -3
@@ -3841,9 +3841,22 @@ static void process_entry(struct merge_options *opt,
3841 if (opt->renormalize &&
3842 blob_unchanged(opt, &ci->stages[0], &ci->stages[side],
3843 path)) {
3844 - ci->merged.is_null = 1;
3845 - ci->merged.clean = 1;
3846 - assert(!ci->df_conflict && !ci->path_conflict);
3844 + if (!ci->path_conflict) {
3845 + /*
3846 + * Blob unchanged after renormalization, so
3847 + * there's no modify/delete conflict after all;
3848 + * we can just remove the file.
3849 + */
3850 + ci->merged.is_null = 1;
3851 + ci->merged.clean = 1;
3852 + /*
3853 + * file goes away => even if there was a
3854 + * directory/file conflict there isn't one now.
3855 + */
3856 + ci->df_conflict = 0;
3857 + } else {
3858 + /* rename/delete, so conflict remains */
3859 + }
3860 } else if (ci->path_conflict &&
3861 oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
3862 /*
t/t6418-merge-text-auto.sh
+26
@@ -204,4 +204,30 @@ test_expect_success 'Test delete/normalize conflict' '
204 test_path_is_missing file
205 '
206
207 +test_expect_success 'rename/delete vs. renormalization' '
208 + git init subrepo &&
209 + (
210 + cd subrepo &&
211 + echo foo >oldfile &&
212 + git add oldfile &&
213 + git commit -m original &&
214 +
215 + git branch rename &&
216 + git branch nuke &&
217 +
218 + git checkout rename &&
219 + git mv oldfile newfile &&
220 + git commit -m renamed &&
221 +
222 + git checkout nuke &&
223 + git rm oldfile &&
224 + git commit -m deleted &&
225 +
226 + git checkout rename^0 &&
227 + test_must_fail git -c merge.renormalize=true merge nuke >out &&
228 +
229 + grep "rename/delete" out
230 + )
231 +'
232 +
233 test_done