Fix random segfaults in pack-objects.
[gitweb.git] / merge-recursive.c
index 6e13b8ed5b7988f6379003242654a34b3ded6da6..ca4f19e34d4216fed7c8110ba8f75585c69f92c7 100644 (file)
@@ -3,13 +3,6 @@
  * Fredrik Kuivinen.
  * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006
  */
-#include <stdarg.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <time.h>
 #include "cache.h"
 #include "cache-tree.h"
 #include "commit.h"
@@ -610,6 +603,12 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
        unsigned long size;
        char type[20];
 
+       if (!hashcmp(sha1, null_sha1)) {
+               mm->ptr = xstrdup("");
+               mm->size = 0;
+               return;
+       }
+
        mm->ptr = read_sha1_file(sha1, type, &size);
        if (!mm->ptr || strcmp(type, blob_type))
                die("unable to read blob object %s", sha1_to_hex(sha1));
@@ -650,8 +649,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
                        char *name1, *name2;
                        int merge_status;
 
-                       name1 = xstrdup(mkpath("%s/%s", branch1, a->path));
-                       name2 = xstrdup(mkpath("%s/%s", branch2, b->path));
+                       name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
+                       name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
 
                        fill_mm(o->sha1, &orig);
                        fill_mm(a->sha1, &src1);
@@ -873,7 +872,7 @@ static int process_renames(struct path_list *a_renames,
                        struct diff_filespec src_other, dst_other;
                        int try_merge, stage = a_renames == renames1 ? 3: 2;
 
-                       remove_file(1, ren1_src, 1);
+                       remove_file(1, ren1_src, index_only);
 
                        hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha);
                        src_other.mode = ren1->src_entry->stages[stage].mode;
@@ -1045,38 +1044,17 @@ static int process_entry(const char *path, struct stage_data *entry,
                        output("Adding %s", path);
                        update_file(1, sha, mode, path);
                }
-       } else if (!o_sha && a_sha && b_sha) {
-               /* Case C: Added in both (check for same permissions). */
-               if (sha_eq(a_sha, b_sha)) {
-                       if (a_mode != b_mode) {
-                               clean_merge = 0;
-                               output("CONFLICT: File %s added identically in both branches, "
-                                      "but permissions conflict %06o->%06o",
-                                      path, a_mode, b_mode);
-                               output("CONFLICT: adding with permission: %06o", a_mode);
-                               update_file(0, a_sha, a_mode, path);
-                       } else {
-                               /* This case is handled by git-read-tree */
-                               assert(0 && "This case must be handled by git-read-tree");
-                       }
-               } else {
-                       const char *new_path1, *new_path2;
-                       clean_merge = 0;
-                       new_path1 = unique_path(path, branch1);
-                       new_path2 = unique_path(path, branch2);
-                       output("CONFLICT (add/add): File %s added non-identically "
-                              "in both branches. Adding as %s and %s instead.",
-                              path, new_path1, new_path2);
-                       remove_file(0, path, 0);
-                       update_file(0, a_sha, a_mode, new_path1);
-                       update_file(0, b_sha, b_mode, new_path2);
-               }
-
-       } else if (o_sha && a_sha && b_sha) {
+       } else if (a_sha && b_sha) {
+               /* Case C: Added in both (check for same permissions) and */
                /* case D: Modified in both, but differently. */
+               const char *reason = "content";
                struct merge_file_info mfi;
                struct diff_filespec o, a, b;
 
+               if (!o_sha) {
+                       reason = "add/add";
+                       o_sha = (unsigned char *)null_sha1;
+               }
                output("Auto-merging %s", path);
                o.path = a.path = b.path = (char *)path;
                hashcpy(o.sha1, o_sha);
@@ -1093,7 +1071,8 @@ static int process_entry(const char *path, struct stage_data *entry,
                        update_file(1, mfi.sha, mfi.mode, path);
                else {
                        clean_merge = 0;
-                       output("CONFLICT (content): Merge conflict in %s", path);
+                       output("CONFLICT (%s): Merge conflict in %s",
+                                       reason, path);
 
                        if (index_only)
                                update_file(0, mfi.sha, mfi.mode, path);
@@ -1222,7 +1201,7 @@ static int merge(struct commit *h1,
 
                tree->object.parsed = 1;
                tree->object.type = OBJ_TREE;
-               hash_sha1_file(NULL, 0, tree_type, tree->object.sha1);
+               write_sha1_file(NULL, 0, tree_type, tree->object.sha1);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
 
@@ -1284,6 +1263,18 @@ static struct commit *get_ref(const char *ref)
        return (struct commit *)object;
 }
 
+static const char *better_branch_name(const char *branch)
+{
+       static char githead_env[8 + 40 + 1];
+       char *name;
+
+       if (strlen(branch) != 40)
+               return branch;
+       sprintf(githead_env, "GITHEAD_%s", branch);
+       name = getenv(githead_env);
+       return name ? name : branch;
+}
+
 int main(int argc, char *argv[])
 {
        static const char *bases[2];
@@ -1293,7 +1284,7 @@ int main(int argc, char *argv[])
        struct commit *result, *h1, *h2;
 
        git_config(git_default_config); /* core.filemode */
-       original_index_file = getenv("GIT_INDEX_FILE");
+       original_index_file = getenv(INDEX_ENVIRONMENT);
 
        if (!original_index_file)
                original_index_file = xstrdup(git_path("index"));
@@ -1314,11 +1305,14 @@ int main(int argc, char *argv[])
 
        branch1 = argv[++i];
        branch2 = argv[++i];
-       printf("Merging %s with %s\n", branch1, branch2);
 
        h1 = get_ref(branch1);
        h2 = get_ref(branch2);
 
+       branch1 = better_branch_name(branch1);
+       branch2 = better_branch_name(branch2);
+       printf("Merging %s with %s\n", branch1, branch2);
+
        if (bases_count == 1) {
                struct commit *ancestor = get_ref(bases[0]);
                clean = merge(h1, h2, branch1, branch2, 0, ancestor, &result);