]> git.ipfire.org Git - thirdparty/git.git/commitdiff
merge-ort: let renormalization change modify/delete into clean delete
authorElijah Newren <newren@gmail.com>
Sat, 20 Mar 2021 00:03:47 +0000 (00:03 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sat, 20 Mar 2021 19:35:40 +0000 (12:35 -0700)
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>
merge-ort.c

index cdc1e2fe7a24b007d0d5233f0bbaa407d717dd5f..c7083e3769aa56b71526fca9596cedf7f55199fc 100644 (file)
@@ -2549,6 +2549,61 @@ static int string_list_df_name_compare(const char *one, const char *two)
        return onelen - twolen;
 }
 
+static int read_oid_strbuf(struct merge_options *opt,
+                          const struct object_id *oid,
+                          struct strbuf *dst)
+{
+       void *buf;
+       enum object_type type;
+       unsigned long size;
+       buf = read_object_file(oid, &type, &size);
+       if (!buf)
+               return err(opt, _("cannot read object %s"), oid_to_hex(oid));
+       if (type != OBJ_BLOB) {
+               free(buf);
+               return err(opt, _("object %s is not a blob"), oid_to_hex(oid));
+       }
+       strbuf_attach(dst, buf, size, size + 1);
+       return 0;
+}
+
+static int blob_unchanged(struct merge_options *opt,
+                         const struct version_info *base,
+                         const struct version_info *side,
+                         const char *path)
+{
+       struct strbuf basebuf = STRBUF_INIT;
+       struct strbuf sidebuf = STRBUF_INIT;
+       int ret = 0; /* assume changed for safety */
+       const struct index_state *idx = &opt->priv->attr_index;
+
+       if (!idx->initialized)
+               initialize_attr_index(opt);
+
+       if (base->mode != side->mode)
+               return 0;
+       if (oideq(&base->oid, &side->oid))
+               return 1;
+
+       if (read_oid_strbuf(opt, &base->oid, &basebuf) ||
+           read_oid_strbuf(opt, &side->oid, &sidebuf))
+               goto error_return;
+       /*
+        * Note: binary | is used so that both renormalizations are
+        * performed.  Comparison can be skipped if both files are
+        * unchanged since their sha1s have already been compared.
+        */
+       if (renormalize_buffer(idx, path, basebuf.buf, basebuf.len, &basebuf) |
+           renormalize_buffer(idx, path, sidebuf.buf, sidebuf.len, &sidebuf))
+               ret = (basebuf.len == sidebuf.len &&
+                      !memcmp(basebuf.buf, sidebuf.buf, basebuf.len));
+
+error_return:
+       strbuf_release(&basebuf);
+       strbuf_release(&sidebuf);
+       return ret;
+}
+
 struct directory_versions {
        /*
         * versions: list of (basename -> version_info)
@@ -3136,8 +3191,13 @@ static void process_entry(struct merge_options *opt,
                modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
                delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
 
-               if (ci->path_conflict &&
-                   oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
+               if (opt->renormalize &&
+                   blob_unchanged(opt, &ci->stages[0], &ci->stages[side],
+                                  path)) {
+                       ci->merged.is_null = 1;
+                       ci->merged.clean = 1;
+               } else if (ci->path_conflict &&
+                          oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
                        /*
                         * This came from a rename/delete; no action to take,
                         * but avoid printing "modify/delete" conflict notice