t2000: rename and combine checkout clash tests
[gitweb.git] / merge-recursive.c
index bd053c70dfc518b6265ec273aad2e61c05d60d18..c0fb83d2858c056633f306b2c3d49b9fd587b767 100644 (file)
@@ -27,6 +27,7 @@
 #include "dir.h"
 #include "submodule.h"
 #include "revision.h"
+#include "commit-reach.h"
 
 struct path_hashmap_entry {
        struct hashmap_entry e;
@@ -156,7 +157,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
                shift_tree_by(&one->object.oid, &two->object.oid, &shifted,
                              subtree_shift);
        }
-       if (!oidcmp(&two->object.oid, &shifted))
+       if (oideq(&two->object.oid, &shifted))
                return two;
        return lookup_tree(the_repository, &shifted);
 }
@@ -179,7 +180,7 @@ static int oid_eq(const struct object_id *a, const struct object_id *b)
 {
        if (!a && !b)
                return 2;
-       return a && b && oidcmp(a, b) == 0;
+       return a && b && oideq(a, b);
 }
 
 enum rename_type {
@@ -966,7 +967,7 @@ static int update_file_flags(struct merge_options *o,
                }
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
-                       if (convert_to_working_tree(path, buf, size, &strbuf)) {
+                       if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) {
                                free(buf);
                                size = strbuf.len;
                                buf = strbuf_detach(&strbuf, NULL);
@@ -1083,7 +1084,8 @@ static int merge_3way(struct merge_options *o,
        read_mmblob(&src2, &b->oid);
 
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
-                               &src1, name1, &src2, name2, &ll_opts);
+                               &src1, name1, &src2, name2,
+                               &the_index, &ll_opts);
 
        free(base_name);
        free(name1);
@@ -1114,7 +1116,7 @@ static int find_first_merges(struct object_array *result, const char *path,
        /* get all revisions that merge commit a */
        xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
                  oid_to_hex(&a->object.oid));
-       init_revisions(&revs, NULL);
+       repo_init_revisions(the_repository, &revs, NULL);
        rev_opts.submodule = path;
        /* FIXME: can't handle linked worktrees in submodules yet */
        revs.single_worktree = path != NULL;
@@ -1273,14 +1275,14 @@ static int merge_submodule(struct merge_options *o,
        return 0;
 }
 
-static int merge_file_1(struct merge_options *o,
-                       const struct diff_filespec *one,
-                       const struct diff_filespec *a,
-                       const struct diff_filespec *b,
-                       const char *filename,
-                       const char *branch1,
-                       const char *branch2,
-                       struct merge_file_info *result)
+static int merge_mode_and_contents(struct merge_options *o,
+                                  const struct diff_filespec *one,
+                                  const struct diff_filespec *a,
+                                  const struct diff_filespec *b,
+                                  const char *filename,
+                                  const char *branch1,
+                                  const char *branch2,
+                                  struct merge_file_info *result)
 {
        result->merge = 0;
        result->clean = 1;
@@ -1365,56 +1367,6 @@ static int merge_file_1(struct merge_options *o,
        return 0;
 }
 
-static int merge_file_special_markers(struct merge_options *o,
-                                     const struct diff_filespec *one,
-                                     const struct diff_filespec *a,
-                                     const struct diff_filespec *b,
-                                     const char *target_filename,
-                                     const char *branch1,
-                                     const char *filename1,
-                                     const char *branch2,
-                                     const char *filename2,
-                                     struct merge_file_info *mfi)
-{
-       char *side1 = NULL;
-       char *side2 = NULL;
-       int ret;
-
-       if (filename1)
-               side1 = xstrfmt("%s:%s", branch1, filename1);
-       if (filename2)
-               side2 = xstrfmt("%s:%s", branch2, filename2);
-
-       ret = merge_file_1(o, one, a, b, target_filename,
-                          side1 ? side1 : branch1,
-                          side2 ? side2 : branch2, mfi);
-
-       free(side1);
-       free(side2);
-       return ret;
-}
-
-static int merge_file_one(struct merge_options *o,
-                         const char *path,
-                         const struct object_id *o_oid, int o_mode,
-                         const struct object_id *a_oid, int a_mode,
-                         const struct object_id *b_oid, int b_mode,
-                         const char *branch1,
-                         const char *branch2,
-                         struct merge_file_info *mfi)
-{
-       struct diff_filespec one, a, b;
-
-       one.path = a.path = b.path = (char *)path;
-       oidcpy(&one.oid, o_oid);
-       one.mode = o_mode;
-       oidcpy(&a.oid, a_oid);
-       a.mode = a_mode;
-       oidcpy(&b.oid, b_oid);
-       b.mode = b_mode;
-       return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi);
-}
-
 static int handle_rename_via_dir(struct merge_options *o,
                                 struct diff_filepair *pair,
                                 const char *rename_branch,
@@ -1658,11 +1610,8 @@ static int handle_rename_rename_1to2(struct merge_options *o,
                struct merge_file_info mfi;
                struct diff_filespec other;
                struct diff_filespec *add;
-               if (merge_file_one(o, one->path,
-                                &one->oid, one->mode,
-                                &a->oid, a->mode,
-                                &b->oid, b->mode,
-                                ci->branch1, ci->branch2, &mfi))
+               if (merge_mode_and_contents(o, one, a, b, one->path,
+                                           ci->branch1, ci->branch2, &mfi))
                        return -1;
 
                /*
@@ -1728,14 +1677,10 @@ static int handle_rename_rename_2to1(struct merge_options *o,
 
        path_side_1_desc = xstrfmt("%s (was %s)", path, a->path);
        path_side_2_desc = xstrfmt("%s (was %s)", path, b->path);
-       if (merge_file_special_markers(o, a, c1, &ci->ren1_other,
-                                      path_side_1_desc,
-                                      o->branch1, c1->path,
-                                      o->branch2, ci->ren1_other.path, &mfi_c1) ||
-           merge_file_special_markers(o, b, &ci->ren2_other, c2,
-                                      path_side_2_desc,
-                                      o->branch1, ci->ren2_other.path,
-                                      o->branch2, c2->path, &mfi_c2))
+       if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc,
+                                   o->branch1, o->branch2, &mfi_c1) ||
+           merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc,
+                                   o->branch1, o->branch2, &mfi_c2))
                return -1;
        free(path_side_1_desc);
        free(path_side_2_desc);
@@ -1812,7 +1757,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o,
        struct diff_queue_struct *ret;
        struct diff_options opts;
 
-       diff_setup(&opts);
+       repo_diff_setup(the_repository, &opts);
        opts.flags.recursive = 1;
        opts.flags.rename_empty = 0;
        opts.detect_rename = merge_detect_rename(o);
@@ -2239,7 +2184,7 @@ static struct dir_rename_entry *check_dir_renamed(const char *path,
 {
        char *temp = xstrdup(path);
        char *end;
-       struct dir_rename_entry *entry = NULL;;
+       struct dir_rename_entry *entry = NULL;
 
        while ((end = strrchr(temp, '/'))) {
                *end = '\0';
@@ -2765,12 +2710,23 @@ static int process_renames(struct merge_options *o,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                        struct merge_file_info mfi;
-                                       if (merge_file_one(o, ren1_dst, &null_oid, 0,
-                                                          &ren1->pair->two->oid,
-                                                          ren1->pair->two->mode,
-                                                          &dst_other.oid,
-                                                          dst_other.mode,
-                                                          branch1, branch2, &mfi)) {
+                                       struct diff_filespec one, a, b;
+
+                                       oidcpy(&one.oid, &null_oid);
+                                       one.mode = 0;
+                                       one.path = ren1->pair->two->path;
+
+                                       oidcpy(&a.oid, &ren1->pair->two->oid);
+                                       a.mode = ren1->pair->two->mode;
+                                       a.path = one.path;
+
+                                       oidcpy(&b.oid, &dst_other.oid);
+                                       b.mode = dst_other.mode;
+                                       b.path = one.path;
+
+                                       if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst,
+                                                                   branch1, branch2,
+                                                                   &mfi)) {
                                                clean_merge = -1;
                                                goto cleanup_and_return;
                                        }
@@ -2869,12 +2825,19 @@ static int detect_and_process_renames(struct merge_options *o,
        head_pairs = get_diffpairs(o, common, head);
        merge_pairs = get_diffpairs(o, common, merge);
 
-       dir_re_head = get_directory_renames(head_pairs, head);
-       dir_re_merge = get_directory_renames(merge_pairs, merge);
+       if (o->detect_directory_renames) {
+               dir_re_head = get_directory_renames(head_pairs, head);
+               dir_re_merge = get_directory_renames(merge_pairs, merge);
 
-       handle_directory_level_conflicts(o,
-                                        dir_re_head, head,
-                                        dir_re_merge, merge);
+               handle_directory_level_conflicts(o,
+                                                dir_re_head, head,
+                                                dir_re_merge, merge);
+       } else {
+               dir_re_head  = xmalloc(sizeof(*dir_re_head));
+               dir_re_merge = xmalloc(sizeof(*dir_re_merge));
+               dir_rename_init(dir_re_head);
+               dir_rename_init(dir_re_merge);
+       }
 
        ri->head_renames  = get_renames(o, head_pairs,
                                        dir_re_merge, dir_re_head, head,
@@ -3013,13 +2976,13 @@ static int handle_modify_delete(struct merge_options *o,
                                    _("modify"), _("modified"));
 }
 
-static int merge_content(struct merge_options *o,
-                        const char *path,
-                        int is_dirty,
-                        struct object_id *o_oid, int o_mode,
-                        struct object_id *a_oid, int a_mode,
-                        struct object_id *b_oid, int b_mode,
-                        struct rename_conflict_info *rename_conflict_info)
+static int handle_content_merge(struct merge_options *o,
+                               const char *path,
+                               int is_dirty,
+                               struct object_id *o_oid, int o_mode,
+                               struct object_id *a_oid, int a_mode,
+                               struct object_id *b_oid, int b_mode,
+                               struct rename_conflict_info *rename_conflict_info)
 {
        const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
@@ -3051,14 +3014,16 @@ static int merge_content(struct merge_options *o,
                path2 = (rename_conflict_info->pair2 ||
                         o->branch2 == rename_conflict_info->branch1) ?
                        pair1->two->path : pair1->one->path;
+               one.path = pair1->one->path;
+               a.path = (char *)path1;
+               b.path = (char *)path2;
 
                if (dir_in_way(path, !o->call_depth,
                               S_ISGITLINK(pair1->two->mode)))
                        df_conflict_remains = 1;
        }
-       if (merge_file_special_markers(o, &one, &a, &b, path,
-                                      o->branch1, path1,
-                                      o->branch2, path2, &mfi))
+       if (merge_mode_and_contents(o, &one, &a, &b, path,
+                                   o->branch1, o->branch2, &mfi))
                return -1;
 
        /*
@@ -3149,9 +3114,9 @@ static int handle_rename_normal(struct merge_options *o,
                                struct rename_conflict_info *ci)
 {
        /* Merge the content and write it out */
-       return merge_content(o, path, was_dirty(o, path),
-                            o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
-                            ci);
+       return handle_content_merge(o, path, was_dirty(o, path),
+                                   o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
+                                   ci);
 }
 
 /* Per entry merge function */
@@ -3275,9 +3240,11 @@ static int process_entry(struct merge_options *o,
                /* Case C: Added in both (check for same permissions) and */
                /* case D: Modified in both, but differently. */
                int is_dirty = 0; /* unpack_trees would have bailed if dirty */
-               clean_merge = merge_content(o, path, is_dirty,
-                                           o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
-                                           NULL);
+               clean_merge = handle_content_merge(o, path, is_dirty,
+                                                  o_oid, o_mode,
+                                                  a_oid, a_mode,
+                                                  b_oid, b_mode,
+                                                  NULL);
        } else if (!o_oid && !a_oid && !b_oid) {
                /*
                 * this entry was deleted altogether. a_mode == 0 means
@@ -3586,6 +3553,7 @@ void init_merge_options(struct merge_options *o)
        o->renormalize = 0;
        o->diff_detect_rename = -1;
        o->merge_detect_rename = -1;
+       o->detect_directory_renames = 1;
        merge_recursive_config(o);
        merge_verbosity = getenv("GIT_MERGE_VERBOSITY");
        if (merge_verbosity)