Code

merge-recursive: handle file mode changes
[git.git] / merge-recursive.c
index 6c6f595fbc7da09a41228e09cd2c5ef48b91f3f0..d97cbf7d16cd1770229d259a1bfeb179033e5cd8 100644 (file)
@@ -289,7 +289,7 @@ static int get_files_dirs(struct tree *tree)
 }
 
 /*
- * Returns a index_entry instance which doesn't have to correspond to
+ * Returns an index_entry instance which doesn't have to correspond to
  * a real cache entry in Git's index.
  */
 static struct stage_data *insert_stage_data(const char *path,
@@ -366,7 +366,7 @@ static struct path_list *get_renames(struct tree *tree,
 
        renames = xcalloc(1, sizeof(struct path_list));
        diff_setup(&opts);
-       opts.recursive = 1;
+       DIFF_OPT_SET(&opts, RECURSIVE);
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = rename_limit;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -549,6 +549,10 @@ static void update_file_flags(const unsigned char *sha,
                void *buf;
                unsigned long size;
 
+               if (S_ISGITLINK(mode))
+                       die("cannot read object %s '%s': It is a submodule!",
+                           sha1_to_hex(sha), path);
+
                buf = read_sha1_file(sha, &type, &size);
                if (!buf)
                        die("cannot read object %s '%s'", sha1_to_hex(sha), path);
@@ -840,8 +844,9 @@ static int read_merge_config(const char *var, const char *value)
        int namelen;
 
        if (!strcmp(var, "merge.default")) {
-               if (value)
-                       default_ll_merge = strdup(value);
+               if (!value)
+                       return config_error_nonbool(var);
+               default_ll_merge = strdup(value);
                return 0;
        }
 
@@ -874,14 +879,14 @@ static int read_merge_config(const char *var, const char *value)
 
        if (!strcmp("name", ep)) {
                if (!value)
-                       return error("%s: lacks value", var);
+                       return config_error_nonbool(var);
                fn->description = strdup(value);
                return 0;
        }
 
        if (!strcmp("driver", ep)) {
                if (!value)
-                       return error("%s: lacks value", var);
+                       return config_error_nonbool(var);
                /*
                 * merge.<name>.driver specifies the command line:
                 *
@@ -904,7 +909,7 @@ static int read_merge_config(const char *var, const char *value)
 
        if (!strcmp("recursive", ep)) {
                if (!value)
-                       return error("%s: lacks value", var);
+                       return config_error_nonbool(var);
                fn->recursive = strdup(value);
                return 0;
        }
@@ -1023,9 +1028,20 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
                if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
                        result.merge = 1;
 
-               result.mode = a->mode == o->mode ? b->mode: a->mode;
+               /*
+                * Merge modes
+                */
+               if (a->mode == b->mode || a->mode == o->mode)
+                       result.mode = b->mode;
+               else {
+                       result.mode = a->mode;
+                       if (b->mode != o->mode) {
+                               result.clean = 0;
+                               result.merge = 1;
+                       }
+               }
 
-               if (sha_eq(a->sha1, o->sha1))
+               if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1))
                        hashcpy(result.sha, b->sha1);
                else if (sha_eq(b->sha1, o->sha1))
                        hashcpy(result.sha, a->sha1);
@@ -1046,14 +1062,16 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 
                        free(result_buf.ptr);
                        result.clean = (merge_status == 0);
-               } else {
-                       if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode)))
-                               die("cannot merge modes?");
-
+               } else if (S_ISGITLINK(a->mode)) {
+                       result.clean = 0;
+                       hashcpy(result.sha, a->sha1);
+               } else if (S_ISLNK(a->mode)) {
                        hashcpy(result.sha, a->sha1);
 
                        if (!sha_eq(a->sha1, b->sha1))
                                result.clean = 0;
+               } else {
+                       die("unsupported object type in the tree");
                }
        }
 
@@ -1461,10 +1479,13 @@ static int process_entry(const char *path, struct stage_data *entry,
                mfi = merge_file(&o, &a, &b,
                                 branch1, branch2);
 
+               clean_merge = mfi.clean;
                if (mfi.clean)
                        update_file(1, mfi.sha, mfi.mode, path);
+               else if (S_ISGITLINK(mfi.mode))
+                       output(1, "CONFLICT (submodule): Merge conflict in %s "
+                              "- needs %s", path, sha1_to_hex(b.sha1));
                else {
-                       clean_merge = 0;
                        output(1, "CONFLICT (%s): Merge conflict in %s",
                                        reason, path);
 
@@ -1744,7 +1765,7 @@ int main(int argc, char *argv[])
 
        if (active_cache_changed &&
            (write_cache(index_fd, active_cache, active_nr) ||
-            close(index_fd) || commit_locked_index(lock)))
+            commit_locked_index(lock)))
                        die ("unable to write %s", get_index_file());
 
        return clean ? 0: 1;