add_reflog_for_walk: avoid memory leak
[gitweb.git] / merge-recursive.c
index bc59815416ce2d63860f38d12cf1835921030142..62decd51cc74a9197abbda28dc8efd6f83287a6b 100644 (file)
 #include "dir.h"
 #include "submodule.h"
 
+static void flush_output(struct merge_options *o)
+{
+       if (o->buffer_output < 2 && o->obuf.len) {
+               fputs(o->obuf.buf, stdout);
+               strbuf_reset(&o->obuf);
+       }
+}
+
+static int err(struct merge_options *o, const char *err, ...)
+{
+       va_list params;
+
+       if (o->buffer_output < 2)
+               flush_output(o);
+       else {
+               strbuf_complete(&o->obuf, '\n');
+               strbuf_addstr(&o->obuf, "error: ");
+       }
+       va_start(params, err);
+       strbuf_vaddf(&o->obuf, err, params);
+       va_end(params);
+       if (o->buffer_output > 1)
+               strbuf_addch(&o->obuf, '\n');
+       else {
+               error("%s", o->obuf.buf);
+               strbuf_reset(&o->obuf);
+       }
+
+       return -1;
+}
+
 static struct tree *shift_tree_object(struct tree *one, struct tree *two,
                                      const char *subtree_shift)
 {
@@ -42,12 +73,9 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
 static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
 {
        struct commit *commit = alloc_commit_node();
-       struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
 
-       desc->name = comment;
-       desc->obj = (struct object *)commit;
+       set_merge_remote_desc(commit, comment, (struct object *)commit);
        commit->tree = tree;
-       commit->util = desc;
        commit->object.parsed = 1;
        return commit;
 }
@@ -148,14 +176,6 @@ static int show(struct merge_options *o, int v)
        return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5;
 }
 
-static void flush_output(struct merge_options *o)
-{
-       if (o->obuf.len) {
-               fputs(o->obuf.buf, stdout);
-               strbuf_reset(&o->obuf);
-       }
-}
-
 __attribute__((format (printf, 3, 4)))
 static void output(struct merge_options *o, int v, const char *fmt, ...)
 {
@@ -177,28 +197,30 @@ static void output(struct merge_options *o, int v, const char *fmt, ...)
 
 static void output_commit_title(struct merge_options *o, struct commit *commit)
 {
-       int i;
-       flush_output(o);
-       for (i = o->call_depth; i--;)
-               fputs("  ", stdout);
+       strbuf_addchars(&o->obuf, ' ', o->call_depth * 2);
        if (commit->util)
-               printf("virtual %s\n", merge_remote_util(commit)->name);
+               strbuf_addf(&o->obuf, "virtual %s\n",
+                       merge_remote_util(commit)->name);
        else {
-               printf("%s ", find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
+               strbuf_add_unique_abbrev(&o->obuf, commit->object.oid.hash,
+                                        DEFAULT_ABBREV);
+               strbuf_addch(&o->obuf, ' ');
                if (parse_commit(commit) != 0)
-                       printf(_("(bad commit)\n"));
+                       strbuf_addstr(&o->obuf, _("(bad commit)\n"));
                else {
                        const char *title;
                        const char *msg = get_commit_buffer(commit, NULL);
                        int len = find_commit_subject(msg, &title);
                        if (len)
-                               printf("%.*s\n", len, title);
+                               strbuf_addf(&o->obuf, "%.*s\n", len, title);
                        unuse_commit_buffer(commit, msg);
                }
        }
+       flush_output(o);
 }
 
-static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
+static int add_cacheinfo(struct merge_options *o,
+               unsigned int mode, const struct object_id *oid,
                const char *path, int stage, int refresh, int options)
 {
        struct cache_entry *ce;
@@ -206,13 +228,15 @@ static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
 
        ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);
        if (!ce)
-               return error(_("addinfo_cache failed for path '%s'"), path);
+               return err(o, _("addinfo_cache failed for path '%s'"), path);
 
        ret = add_cache_entry(ce, options);
        if (refresh) {
                struct cache_entry *nce;
 
                nce = refresh_cache_entry(ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
+               if (!nce)
+                       return err(o, _("addinfo_cache failed for path '%s'"), path);
                if (nce != ce)
                        ret = add_cache_entry(nce, options);
        }
@@ -276,7 +300,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
 
        if (!cache_tree_fully_valid(active_cache_tree) &&
            cache_tree_update(&the_index, 0) < 0) {
-               error(_("error building trees"));
+               err(o, _("error building trees"));
                return NULL;
        }
 
@@ -360,18 +384,16 @@ static struct string_list *get_unmerged(void)
                }
                e = item->util;
                e->stages[ce_stage(ce)].mode = ce->ce_mode;
-               hashcpy(e->stages[ce_stage(ce)].oid.hash, ce->sha1);
+               oidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid);
        }
 
        return unmerged;
 }
 
-static int string_list_df_name_compare(const void *a, const void *b)
+static int string_list_df_name_compare(const char *one, const char *two)
 {
-       const struct string_list_item *one = a;
-       const struct string_list_item *two = b;
-       int onelen = strlen(one->string);
-       int twolen = strlen(two->string);
+       int onelen = strlen(one);
+       int twolen = strlen(two);
        /*
         * Here we only care that entries for D/F conflicts are
         * adjacent, in particular with the file of the D/F conflict
@@ -384,8 +406,8 @@ static int string_list_df_name_compare(const void *a, const void *b)
         * since in other cases any changes in their order due to
         * sorting cause no problems for us.
         */
-       int cmp = df_name_compare(one->string, onelen, S_IFDIR,
-                                 two->string, twolen, S_IFDIR);
+       int cmp = df_name_compare(one, onelen, S_IFDIR,
+                                 two, twolen, S_IFDIR);
        /*
         * Now that 'foo' and 'foo/bar' compare equal, we have to make sure
         * that 'foo' comes before 'foo/bar'.
@@ -411,7 +433,7 @@ static void record_df_conflict_files(struct merge_options *o,
         * and the file need to be present, then the D/F file will be
         * reinstated with a new unique name at the time it is processed.
         */
-       struct string_list df_sorted_entries;
+       struct string_list df_sorted_entries = STRING_LIST_INIT_NODUP;
        const char *last_file = NULL;
        int last_len = 0;
        int i;
@@ -424,14 +446,13 @@ static void record_df_conflict_files(struct merge_options *o,
                return;
 
        /* Ensure D/F conflicts are adjacent in the entries list. */
-       memset(&df_sorted_entries, 0, sizeof(struct string_list));
        for (i = 0; i < entries->nr; i++) {
                struct string_list_item *next = &entries->items[i];
                string_list_append(&df_sorted_entries, next->string)->util =
                                   next->util;
        }
-       qsort(df_sorted_entries.items, entries->nr, sizeof(*entries->items),
-             string_list_df_name_compare);
+       df_sorted_entries.cmp = string_list_df_name_compare;
+       string_list_sort(&df_sorted_entries);
 
        string_list_clear(&o->df_conflict_file_set, 1);
        for (i = 0; i < df_sorted_entries.nr; i++) {
@@ -544,7 +565,8 @@ static struct string_list *get_renames(struct merge_options *o,
        return renames;
 }
 
-static int update_stages(const char *path, const struct diff_filespec *o,
+static int update_stages(struct merge_options *opt, const char *path,
+                        const struct diff_filespec *o,
                         const struct diff_filespec *a,
                         const struct diff_filespec *b)
 {
@@ -563,13 +585,13 @@ static int update_stages(const char *path, const struct diff_filespec *o,
                if (remove_file_from_cache(path))
                        return -1;
        if (o)
-               if (add_cacheinfo(o->mode, &o->oid, path, 1, 0, options))
+               if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))
                        return -1;
        if (a)
-               if (add_cacheinfo(a->mode, &a->oid, path, 2, 0, options))
+               if (add_cacheinfo(opt, a->mode, &a->oid, path, 2, 0, options))
                        return -1;
        if (b)
-               if (add_cacheinfo(b->mode, &b->oid, path, 3, 0, options))
+               if (add_cacheinfo(opt, b->mode, &b->oid, path, 3, 0, options))
                        return -1;
        return 0;
 }
@@ -642,7 +664,13 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
        return strbuf_detach(&newpath, NULL);
 }
 
-static int dir_in_way(const char *path, int check_working_copy)
+/**
+ * Check whether a directory in the index is in the way of an incoming
+ * file.  Return 1 if so.  If check_working_copy is non-zero, also
+ * check the working directory.  If empty_ok is non-zero, also return
+ * 0 in the case where the working-tree dir exists but is empty.
+ */
+static int dir_in_way(const char *path, int check_working_copy, int empty_ok)
 {
        int pos;
        struct strbuf dirpath = STRBUF_INIT;
@@ -662,7 +690,8 @@ static int dir_in_way(const char *path, int check_working_copy)
        }
 
        strbuf_release(&dirpath);
-       return check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode);
+       return check_working_copy && !lstat(path, &st) && S_ISDIR(st.st_mode) &&
+               !(empty_ok && is_empty_dir(path));
 }
 
 static int was_tracked(const char *path)
@@ -720,8 +749,8 @@ static int make_room_for_path(struct merge_options *o, const char *path)
        if (status) {
                if (status == SCLD_EXISTS)
                        /* something else exists */
-                       return error(msg, path, _(": perhaps a D/F conflict?"));
-               return error(msg, path, "");
+                       return err(o, msg, path, _(": perhaps a D/F conflict?"));
+               return err(o, msg, path, "");
        }
 
        /*
@@ -729,7 +758,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
         * tracking it.
         */
        if (would_lose_untracked(path))
-               return error(_("refusing to lose untracked file at '%s'"),
+               return err(o, _("refusing to lose untracked file at '%s'"),
                             path);
 
        /* Successful unlink is good.. */
@@ -739,7 +768,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
        if (errno == ENOENT)
                return 0;
        /* .. but not some other error (who really cares what?) */
-       return error(msg, path, _(": perhaps a D/F conflict?"));
+       return err(o, msg, path, _(": perhaps a D/F conflict?"));
 }
 
 static int update_file_flags(struct merge_options *o,
@@ -771,9 +800,9 @@ static int update_file_flags(struct merge_options *o,
 
                buf = read_sha1_file(oid->hash, &type, &size);
                if (!buf)
-                       return error(_("cannot read object %s '%s'"), oid_to_hex(oid), path);
+                       return err(o, _("cannot read object %s '%s'"), oid_to_hex(oid), path);
                if (type != OBJ_BLOB) {
-                       ret = error(_("blob expected for %s '%s'"), oid_to_hex(oid), path);
+                       ret = err(o, _("blob expected for %s '%s'"), oid_to_hex(oid), path);
                        goto free_buf;
                }
                if (S_ISREG(mode)) {
@@ -797,8 +826,8 @@ static int update_file_flags(struct merge_options *o,
                                mode = 0666;
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0) {
-                               ret = error_errno(_("failed to open '%s'"),
-                                                 path);
+                               ret = err(o, _("failed to open '%s': %s"),
+                                         path, strerror(errno));
                                goto free_buf;
                        }
                        write_in_full(fd, buf, size);
@@ -808,17 +837,19 @@ static int update_file_flags(struct merge_options *o,
                        safe_create_leading_directories_const(path);
                        unlink(path);
                        if (symlink(lnk, path))
-                               ret = error_errno(_("failed to symlink '%s'"), path);
+                               ret = err(o, _("failed to symlink '%s': %s"),
+                                       path, strerror(errno));
                        free(lnk);
                } else
-                       ret = error(_("do not know what to do with %06o %s '%s'"),
-                                   mode, oid_to_hex(oid), path);
+                       ret = err(o,
+                                 _("do not know what to do with %06o %s '%s'"),
+                                 mode, oid_to_hex(oid), path);
  free_buf:
                free(buf);
        }
  update_index:
        if (!ret && update_cache)
-               add_cacheinfo(mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
+               add_cacheinfo(o, mode, oid, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
        return ret;
 }
 
@@ -886,9 +917,9 @@ static int merge_3way(struct merge_options *o,
                name2 = mkpathdup("%s", branch2);
        }
 
-       read_mmblob(&orig, one->oid.hash);
-       read_mmblob(&src1, a->oid.hash);
-       read_mmblob(&src2, b->oid.hash);
+       read_mmblob(&orig, &one->oid);
+       read_mmblob(&src1, &a->oid);
+       read_mmblob(&src2, &b->oid);
 
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2, &ll_opts);
@@ -951,12 +982,12 @@ static int merge_file_1(struct merge_options *o,
                                                  branch1, branch2);
 
                        if ((merge_status < 0) || !result_buf.ptr)
-                               ret = error(_("Failed to execute internal merge"));
+                               ret = err(o, _("Failed to execute internal merge"));
 
                        if (!ret && write_sha1_file(result_buf.ptr, result_buf.size,
                                                    blob_type, result->oid.hash))
-                               ret = error(_("Unable to add %s to database"),
-                                           a->path);
+                               ret = err(o, _("Unable to add %s to database"),
+                                         a->path);
 
                        free(result_buf.ptr);
                        if (ret)
@@ -1030,16 +1061,20 @@ static int merge_file_one(struct merge_options *o,
 }
 
 static int handle_change_delete(struct merge_options *o,
-                                const char *path,
+                                const char *path, const char *old_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 struct object_id *changed_oid,
+                                int changed_mode,
+                                const char *change_branch,
+                                const char *delete_branch,
                                 const char *change, const char *change_past)
 {
-       char *renamed = NULL;
+       char *alt_path = NULL;
+       const char *update_path = path;
        int ret = 0;
-       if (dir_in_way(path, !o->call_depth)) {
-               renamed = unique_path(o, path, a_oid ? o->branch1 : o->branch2);
+
+       if (dir_in_way(path, !o->call_depth, 0)) {
+               update_path = alt_path = unique_path(o, path, change_branch);
        }
 
        if (o->call_depth) {
@@ -1050,43 +1085,43 @@ static int handle_change_delete(struct merge_options *o,
                 */
                ret = remove_file_from_cache(path);
                if (!ret)
-                       ret = update_file(o, 0, o_oid, o_mode,
-                                         renamed ? renamed : path);
-       } else if (!a_oid) {
-               if (!renamed) {
-                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
-                              "and %s in %s. Version %s of %s left in tree."),
-                              change, path, o->branch1, change_past,
-                              o->branch2, o->branch2, path);
-                       ret = update_file(o, 0, b_oid, b_mode, path);
-               } else {
-                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
-                              "and %s in %s. Version %s of %s left in tree at %s."),
-                              change, path, o->branch1, change_past,
-                              o->branch2, o->branch2, path, renamed);
-                       ret = update_file(o, 0, b_oid, b_mode, renamed);
-               }
+                       ret = update_file(o, 0, o_oid, o_mode, update_path);
        } else {
-               if (!renamed) {
-                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
-                              "and %s in %s. Version %s of %s left in tree."),
-                              change, path, o->branch2, change_past,
-                              o->branch1, o->branch1, path);
+               if (!alt_path) {
+                       if (!old_path) {
+                               output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                                      "and %s in %s. Version %s of %s left in tree."),
+                                      change, path, delete_branch, change_past,
+                                      change_branch, change_branch, path);
+                       } else {
+                               output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                                      "and %s to %s in %s. Version %s of %s left in tree."),
+                                      change, old_path, delete_branch, change_past, path,
+                                      change_branch, change_branch, path);
+                       }
                } else {
-                       output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
-                              "and %s in %s. Version %s of %s left in tree at %s."),
-                              change, path, o->branch2, change_past,
-                              o->branch1, o->branch1, path, renamed);
-                       ret = update_file(o, 0, a_oid, a_mode, renamed);
+                       if (!old_path) {
+                               output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                                      "and %s in %s. Version %s of %s left in tree at %s."),
+                                      change, path, delete_branch, change_past,
+                                      change_branch, change_branch, path, alt_path);
+                       } else {
+                               output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
+                                      "and %s to %s in %s. Version %s of %s left in tree at %s."),
+                                      change, old_path, delete_branch, change_past, path,
+                                      change_branch, change_branch, path, alt_path);
+                       }
                }
                /*
-                * No need to call update_file() on path when !renamed, since
-                * that would needlessly touch path.  We could call
-                * update_file_flags() with update_cache=0 and update_wd=0,
-                * but that's a no-op.
+                * No need to call update_file() on path when change_branch ==
+                * o->branch1 && !alt_path, since that would needlessly touch
+                * path.  We could call update_file_flags() with update_cache=0
+                * and update_wd=0, but that's a no-op.
                 */
+               if (change_branch != o->branch1 || alt_path)
+                       ret = update_file(o, 0, changed_oid, changed_mode, update_path);
        }
-       free(renamed);
+       free(alt_path);
 
        return ret;
 }
@@ -1094,35 +1129,24 @@ static int handle_change_delete(struct merge_options *o,
 static int conflict_rename_delete(struct merge_options *o,
                                   struct diff_filepair *pair,
                                   const char *rename_branch,
-                                  const char *other_branch)
+                                  const char *delete_branch)
 {
        const struct diff_filespec *orig = pair->one;
        const struct diff_filespec *dest = pair->two;
-       const struct object_id *a_oid = NULL;
-       const struct object_id *b_oid = NULL;
-       int a_mode = 0;
-       int b_mode = 0;
-
-       if (rename_branch == o->branch1) {
-               a_oid = &dest->oid;
-               a_mode = dest->mode;
-       } else {
-               b_oid = &dest->oid;
-               b_mode = dest->mode;
-       }
 
        if (handle_change_delete(o,
                                 o->call_depth ? orig->path : dest->path,
+                                o->call_depth ? NULL : orig->path,
                                 &orig->oid, orig->mode,
-                                a_oid, a_mode,
-                                b_oid, b_mode,
+                                &dest->oid, dest->mode,
+                                rename_branch, delete_branch,
                                 _("rename"), _("renamed")))
                return -1;
 
        if (o->call_depth)
                return remove_file_from_cache(dest->path);
        else
-               return update_stages(dest->path, NULL,
+               return update_stages(o, dest->path, NULL,
                                     rename_branch == o->branch1 ? dest : NULL,
                                     rename_branch == o->branch1 ? NULL : dest);
 }
@@ -1171,7 +1195,7 @@ static int handle_file(struct merge_options *o,
                remove_file(o, 0, rename->path, 0);
                dst_name = unique_path(o, rename->path, cur_branch);
        } else {
-               if (dir_in_way(rename->path, !o->call_depth)) {
+               if (dir_in_way(rename->path, !o->call_depth, 0)) {
                        dst_name = unique_path(o, rename->path, cur_branch);
                        output(o, 1, _("%s is a directory in %s adding as %s instead"),
                               rename->path, other_branch, dst_name);
@@ -1180,9 +1204,9 @@ static int handle_file(struct merge_options *o,
        if ((ret = update_file(o, 0, &rename->oid, rename->mode, dst_name)))
                ; /* fall through, do allow dst_name to be released */
        else if (stage == 2)
-               ret = update_stages(rename->path, NULL, rename, add);
+               ret = update_stages(o, rename->path, NULL, rename, add);
        else
-               ret = update_stages(rename->path, NULL, add, rename);
+               ret = update_stages(o, rename->path, NULL, add, rename);
 
        if (dst_name != rename->path)
                free(dst_name);
@@ -1359,14 +1383,11 @@ static int process_renames(struct merge_options *o,
                        branch1 = o->branch1;
                        branch2 = o->branch2;
                } else {
-                       struct rename *tmp;
                        renames1 = b_renames;
                        renames2Dst = &a_by_dst;
                        branch1 = o->branch2;
                        branch2 = o->branch1;
-                       tmp = ren2;
-                       ren2 = ren1;
-                       ren1 = tmp;
+                       SWAP(ren2, ren1);
                }
 
                if (ren1->processed)
@@ -1575,23 +1596,25 @@ static struct object_id *stage_oid(const struct object_id *oid, unsigned mode)
        return (is_null_oid(oid) || mode == 0) ? NULL: (struct object_id *)oid;
 }
 
-static int read_oid_strbuf(const struct object_id *oid, struct strbuf *dst)
+static int read_oid_strbuf(struct merge_options *o,
+       const struct object_id *oid, struct strbuf *dst)
 {
        void *buf;
        enum object_type type;
        unsigned long size;
        buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
-               return error(_("cannot read object %s"), oid_to_hex(oid));
+               return err(o, _("cannot read object %s"), oid_to_hex(oid));
        if (type != OBJ_BLOB) {
                free(buf);
-               return error(_("object %s is not a blob"), oid_to_hex(oid));
+               return err(o, _("object %s is not a blob"), oid_to_hex(oid));
        }
        strbuf_attach(dst, buf, size, size + 1);
        return 0;
 }
 
-static int blob_unchanged(const struct object_id *o_oid,
+static int blob_unchanged(struct merge_options *opt,
+                         const struct object_id *o_oid,
                          unsigned o_mode,
                          const struct object_id *a_oid,
                          unsigned a_mode,
@@ -1609,7 +1632,7 @@ static int blob_unchanged(const struct object_id *o_oid,
                return 0;
 
        assert(o_oid && a_oid);
-       if (read_oid_strbuf(o_oid, &o) || read_oid_strbuf(a_oid, &a))
+       if (read_oid_strbuf(opt, o_oid, &o) || read_oid_strbuf(opt, a_oid, &a))
                goto error_return;
        /*
         * Note: binary | is used so that both renormalizations are
@@ -1632,11 +1655,27 @@ static int handle_modify_delete(struct merge_options *o,
                                 struct object_id *a_oid, int a_mode,
                                 struct object_id *b_oid, int b_mode)
 {
+       const char *modify_branch, *delete_branch;
+       struct object_id *changed_oid;
+       int changed_mode;
+
+       if (a_oid) {
+               modify_branch = o->branch1;
+               delete_branch = o->branch2;
+               changed_oid = a_oid;
+               changed_mode = a_mode;
+       } else {
+               modify_branch = o->branch2;
+               delete_branch = o->branch1;
+               changed_oid = b_oid;
+               changed_mode = b_mode;
+       }
+
        return handle_change_delete(o,
-                                   path,
+                                   path, NULL,
                                    o_oid, o_mode,
-                                   a_oid, a_mode,
-                                   b_oid, b_mode,
+                                   changed_oid, changed_mode,
+                                   modify_branch, delete_branch,
                                    _("modify"), _("modified"));
 }
 
@@ -1678,7 +1717,8 @@ static int merge_content(struct merge_options *o,
                         o->branch2 == rename_conflict_info->branch1) ?
                        pair1->two->path : pair1->one->path;
 
-               if (dir_in_way(path, !o->call_depth))
+               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,
@@ -1698,7 +1738,7 @@ static int merge_content(struct merge_options *o,
                 */
                path_renamed_outside_HEAD = !path2 || !strcmp(path, path2);
                if (!path_renamed_outside_HEAD) {
-                       add_cacheinfo(mfi.mode, &mfi.oid, path,
+                       add_cacheinfo(o, mfi.mode, &mfi.oid, path,
                                      0, (!o->call_depth), 0);
                        return mfi.clean;
                }
@@ -1711,7 +1751,7 @@ static int merge_content(struct merge_options *o,
                output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
                                reason, path);
                if (rename_conflict_info && !df_conflict_remains)
-                       if (update_stages(path, &one, &a, &b))
+                       if (update_stages(o, path, &one, &a, &b))
                                return -1;
        }
 
@@ -1721,7 +1761,7 @@ static int merge_content(struct merge_options *o,
                        remove_file_from_cache(path);
                } else {
                        if (!mfi.clean) {
-                               if (update_stages(path, &one, &a, &b))
+                               if (update_stages(o, path, &one, &a, &b))
                                        return -1;
                        } else {
                                int file_from_stage2 = was_tracked(path);
@@ -1729,7 +1769,7 @@ static int merge_content(struct merge_options *o,
                                oidcpy(&merged.oid, &mfi.oid);
                                merged.mode = mfi.mode;
 
-                               if (update_stages(path, NULL,
+                               if (update_stages(o, path, NULL,
                                                  file_from_stage2 ? &merged : NULL,
                                                  file_from_stage2 ? NULL : &merged))
                                        return -1;
@@ -1797,8 +1837,8 @@ static int process_entry(struct merge_options *o,
        } else if (o_oid && (!a_oid || !b_oid)) {
                /* Case A: Deleted in one */
                if ((!a_oid && !b_oid) ||
-                   (!b_oid && blob_unchanged(o_oid, o_mode, a_oid, a_mode, normalize, path)) ||
-                   (!a_oid && blob_unchanged(o_oid, o_mode, b_oid, b_mode, normalize, path))) {
+                   (!b_oid && blob_unchanged(o, o_oid, o_mode, a_oid, a_mode, normalize, path)) ||
+                   (!a_oid && blob_unchanged(o, o_oid, o_mode, b_oid, b_mode, normalize, path))) {
                        /* Deleted in both or deleted in one and
                         * unchanged in the other */
                        if (a_oid)
@@ -1836,7 +1876,8 @@ static int process_entry(struct merge_options *o,
                        oid = b_oid;
                        conf = _("directory/file");
                }
-               if (dir_in_way(path, !o->call_depth)) {
+               if (dir_in_way(path, !o->call_depth,
+                              S_ISGITLINK(a_mode))) {
                        char *new_path = unique_path(o, path, add_branch);
                        clean_merge = 0;
                        output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
@@ -1894,7 +1935,7 @@ int merge_trees(struct merge_options *o,
 
        if (code != 0) {
                if (show(o, 4) || o->call_depth)
-                       error(_("merging of trees %s and %s failed"),
+                       err(o, _("merging of trees %s and %s failed"),
                            oid_to_hex(&head->object.oid),
                            oid_to_hex(&merge->object.oid));
                return -1;
@@ -2029,7 +2070,7 @@ int merge_recursive(struct merge_options *o,
                o->call_depth--;
 
                if (!merged_common_ancestors)
-                       return error(_("merge returned no commit"));
+                       return err(o, _("merge returned no commit"));
        }
 
        discard_cache();
@@ -2039,8 +2080,10 @@ int merge_recursive(struct merge_options *o,
        o->ancestor = "merged common ancestors";
        clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
                            &mrtree);
-       if (clean < 0)
+       if (clean < 0) {
+               flush_output(o);
                return clean;
+       }
 
        if (o->call_depth) {
                *result = make_virtual_commit(mrtree, "merged tree");
@@ -2048,6 +2091,8 @@ int merge_recursive(struct merge_options *o,
                commit_list_insert(h2, &(*result)->parents->next);
        }
        flush_output(o);
+       if (!o->call_depth && o->buffer_output < 2)
+               strbuf_release(&o->obuf);
        if (show(o, 2))
                diff_warn_rename_limit("merge.renamelimit",
                                       o->needed_rename_limit, 0);
@@ -2088,13 +2133,13 @@ int merge_recursive_generic(struct merge_options *o,
                for (i = 0; i < num_base_list; ++i) {
                        struct commit *base;
                        if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
-                               return error(_("Could not parse object '%s'"),
+                               return err(o, _("Could not parse object '%s'"),
                                        oid_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
        }
 
-       hold_locked_index(lock, 1);
+       hold_locked_index(lock, LOCK_DIE_ON_ERROR);
        clean = merge_recursive(o, head_commit, next_commit, ca,
                        result);
        if (clean < 0)
@@ -2102,7 +2147,7 @@ int merge_recursive_generic(struct merge_options *o,
 
        if (active_cache_changed &&
            write_locked_index(&the_index, lock, COMMIT_LOCK))
-               return error(_("Unable to write index."));
+               return err(o, _("Unable to write index."));
 
        return clean ? 0 : 1;
 }