merge-ort: let renormalization change modify/delete into clean delete
When we have a modify/delete conflict, but the only change to the modification is e.g. change of line endings, then if renormalization is requested then we should be able to recognize such a case as a not-modified/delete and resolve the conflict automatically. This fixes t6418.10 under GIT_TEST_MERGE_ALGORITHM=ort. 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
Mar 20, 2021 at 00:03 UTC
3860220bfa594a56daa801aaedbdf8ac75b62bb6
1 file changed
+62
-2
merge-ort.c
+62
-2
@@ -2549,6 +2549,61 @@ static int string_list_df_name_compare(const char *one, const char *two)
2549
return onelen - twolen;
2550
}
2551
2552
+static int read_oid_strbuf(struct merge_options *opt,
2553
+ const struct object_id *oid,
2554
+ struct strbuf *dst)
2555
+{
2556
+ void *buf;
2557
+ enum object_type type;
2558
+ unsigned long size;
2559
+ buf = read_object_file(oid, &type, &size);
2560
+ if (!buf)
2561
+ return err(opt, _("cannot read object %s"), oid_to_hex(oid));
2562
+ if (type != OBJ_BLOB) {
2563
+ free(buf);
2564
+ return err(opt, _("object %s is not a blob"), oid_to_hex(oid));
2565
+ }
2566
+ strbuf_attach(dst, buf, size, size + 1);
2567
+ return 0;
2568
+}
2569
+
2570
+static int blob_unchanged(struct merge_options *opt,
2571
+ const struct version_info *base,
2572
+ const struct version_info *side,
2573
+ const char *path)
2574
+{
2575
+ struct strbuf basebuf = STRBUF_INIT;
2576
+ struct strbuf sidebuf = STRBUF_INIT;
2577
+ int ret = 0; /* assume changed for safety */
2578
+ const struct index_state *idx = &opt->priv->attr_index;
2579
+
2580
+ if (!idx->initialized)
2581
+ initialize_attr_index(opt);
2582
+
2583
+ if (base->mode != side->mode)
2584
+ return 0;
2585
+ if (oideq(&base->oid, &side->oid))
2586
+ return 1;
2587
+
2588
+ if (read_oid_strbuf(opt, &base->oid, &basebuf) ||
2589
+ read_oid_strbuf(opt, &side->oid, &sidebuf))
2590
+ goto error_return;
2591
+ /*
2592
+ * Note: binary | is used so that both renormalizations are
2593
+ * performed. Comparison can be skipped if both files are
2594
+ * unchanged since their sha1s have already been compared.
2595
+ */
2596
+ if (renormalize_buffer(idx, path, basebuf.buf, basebuf.len, &basebuf) |
2597
+ renormalize_buffer(idx, path, sidebuf.buf, sidebuf.len, &sidebuf))
2598
+ ret = (basebuf.len == sidebuf.len &&
2599
+ !memcmp(basebuf.buf, sidebuf.buf, basebuf.len));
2600
+
2601
+error_return:
2602
+ strbuf_release(&basebuf);
2603
+ strbuf_release(&sidebuf);
2604
+ return ret;
2605
+}
2606
+
2607
struct directory_versions {
2608
/*
2609
* versions: list of (basename -> version_info)
@@ -3136,8 +3191,13 @@ static void process_entry(struct merge_options *opt,
3191
modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
3192
delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
3193
3139
- if (ci->path_conflict &&
3140
- oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
3194
+ if (opt->renormalize &&
3195
+ blob_unchanged(opt, &ci->stages[0], &ci->stages[side],
3196
+ path)) {
3197
+ ci->merged.is_null = 1;
3198
+ ci->merged.clean = 1;
3199
+ } else if (ci->path_conflict &&
3200
+ oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
3201
/*
3202
* This came from a rename/delete; no action to take,
3203
* but avoid printing "modify/delete" conflict notice