change hard-coded perl path to variable
[platform/upstream/git.git] / merge-recursive.c
index 680937c..cab16fa 100644 (file)
@@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
        else {
                printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
                if (parse_commit(commit) != 0)
-                       printf("(bad commit)\n");
+                       printf(_("(bad commit)\n"));
                else {
                        const char *title;
                        int len = find_commit_subject(commit->buffer, &title);
@@ -201,9 +201,11 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
                const char *path, int stage, int refresh, int options)
 {
        struct cache_entry *ce;
-       ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
+       ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,
+                             (refresh ? (CE_MATCH_REFRESH |
+                                         CE_MATCH_IGNORE_MISSING) : 0 ));
        if (!ce)
-               return error("addinfo_cache failed for path '%s'", path);
+               return error(_("addinfo_cache failed for path '%s'"), path);
        return add_cache_entry(ce, options);
 }
 
@@ -251,7 +253,7 @@ struct tree *write_tree_from_memory(struct merge_options *o)
                int i;
                fprintf(stderr, "BUG: There are unmerged index entries:\n");
                for (i = 0; i < active_nr; i++) {
-                       struct cache_entry *ce = active_cache[i];
+                       const struct cache_entry *ce = active_cache[i];
                        if (ce_stage(ce))
                                fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce),
                                        (int)ce_namelen(ce), ce->name);
@@ -264,8 +266,9 @@ struct tree *write_tree_from_memory(struct merge_options *o)
 
        if (!cache_tree_fully_valid(active_cache_tree) &&
            cache_tree_update(active_cache_tree,
-                             active_cache, active_nr, 0) < 0)
-               die("error building trees");
+                             (const struct cache_entry * const *)active_cache,
+                             active_nr, 0) < 0)
+               die(_("error building trees"));
 
        result = lookup_tree(active_cache_tree->sha1);
 
@@ -297,7 +300,7 @@ static int get_files_dirs(struct merge_options *o, struct tree *tree)
 {
        int n;
        struct pathspec match_all;
-       init_pathspec(&match_all, NULL);
+       memset(&match_all, 0, sizeof(match_all));
        if (read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o))
                return 0;
        n = o->current_file_set.nr + o->current_directory_set.nr;
@@ -339,7 +342,7 @@ static struct string_list *get_unmerged(void)
        for (i = 0; i < active_nr; i++) {
                struct string_list_item *item;
                struct stage_data *e;
-               struct cache_entry *ce = active_cache[i];
+               const struct cache_entry *ce = active_cache[i];
                if (!ce_stage(ce))
                        continue;
 
@@ -493,8 +496,7 @@ static struct string_list *get_renames(struct merge_options *o,
        opts.rename_score = o->rename_score;
        opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opts) < 0)
-               die("diff setup failed");
+       diff_setup_done(&opts);
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
        if (opts.needed_rename_limit > o->needed_rename_limit)
@@ -587,6 +589,12 @@ static int remove_file(struct merge_options *o, int clean,
                        return -1;
        }
        if (update_working_directory) {
+               if (ignore_case) {
+                       struct cache_entry *ce;
+                       ce = cache_file_exists(path, strlen(path), ignore_case);
+                       if (ce && ce_stage(ce) == 0)
+                               return 0;
+               }
                if (remove_path(path))
                        return -1;
        }
@@ -614,23 +622,6 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
        return newpath;
 }
 
-static void flush_buffer(int fd, const char *buf, unsigned long size)
-{
-       while (size > 0) {
-               long ret = write_in_full(fd, buf, size);
-               if (ret < 0) {
-                       /* Ignore epipe */
-                       if (errno == EPIPE)
-                               break;
-                       die_errno("merge-recursive");
-               } else if (!ret) {
-                       die("merge-recursive: disk full?");
-               }
-               size -= ret;
-               buf += ret;
-       }
-}
-
 static int dir_in_way(const char *path, int check_working_copy)
 {
        int pos, pathlen = strlen(path);
@@ -687,7 +678,7 @@ static int would_lose_untracked(const char *path)
 static int make_room_for_path(struct merge_options *o, const char *path)
 {
        int status, i;
-       const char *msg = "failed to create path '%s'%s";
+       const char *msg = _("failed to create path '%s'%s");
 
        /* Unlink any D/F conflict files that are in the way */
        for (i = 0; i < o->df_conflict_file_set.nr; i++) {
@@ -698,7 +689,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
                    path[df_pathlen] == '/' &&
                    strncmp(path, df_path, df_pathlen) == 0) {
                        output(o, 3,
-                              "Removing %s to make room for subdirectory\n",
+                              _("Removing %s to make room for subdirectory\n"),
                               df_path);
                        unlink(df_path);
                        unsorted_string_list_delete_item(&o->df_conflict_file_set,
@@ -710,9 +701,9 @@ static int make_room_for_path(struct merge_options *o, const char *path)
        /* Make sure leading directories are created */
        status = safe_create_leading_directories_const(path);
        if (status) {
-               if (status == -3) {
+               if (status == SCLD_EXISTS) {
                        /* something else exists */
-                       error(msg, path, ": perhaps a D/F conflict?");
+                       error(msg, path, _(": perhaps a D/F conflict?"));
                        return -1;
                }
                die(msg, path, "");
@@ -723,7 +714,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 error(_("refusing to lose untracked file at '%s'"),
                             path);
 
        /* Successful unlink is good.. */
@@ -733,7 +724,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 error(msg, path, _(": perhaps a D/F conflict?"));
 }
 
 static void update_file_flags(struct merge_options *o,
@@ -763,9 +754,9 @@ static void update_file_flags(struct merge_options *o,
 
                buf = read_sha1_file(sha, &type, &size);
                if (!buf)
-                       die("cannot read object %s '%s'", sha1_to_hex(sha), path);
+                       die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path);
                if (type != OBJ_BLOB)
-                       die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+                       die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path);
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
                        if (convert_to_working_tree(path, buf, size, &strbuf)) {
@@ -788,18 +779,18 @@ static void update_file_flags(struct merge_options *o,
                                mode = 0666;
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
-                               die_errno("failed to open '%s'", path);
-                       flush_buffer(fd, buf, size);
+                               die_errno(_("failed to open '%s'"), path);
+                       write_in_full(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
                        char *lnk = xmemdupz(buf, size);
                        safe_create_leading_directories_const(path);
                        unlink(path);
                        if (symlink(lnk, path))
-                               die_errno("failed to symlink '%s'", path);
+                               die_errno(_("failed to symlink '%s'"), path);
                        free(lnk);
                } else
-                       die("do not know what to do with %06o %s '%s'",
+                       die(_("do not know what to do with %06o %s '%s'"),
                            mode, sha1_to_hex(sha), path);
                free(buf);
        }
@@ -862,14 +853,14 @@ static int merge_3way(struct merge_options *o,
        if (strcmp(a->path, b->path) ||
            (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
                base_name = o->ancestor == NULL ? NULL :
-                       xstrdup(mkpath("%s:%s", o->ancestor, one->path));
-               name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
-               name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
+                       mkpathdup("%s:%s", o->ancestor, one->path);
+               name1 = mkpathdup("%s:%s", branch1, a->path);
+               name2 = mkpathdup("%s:%s", branch2, b->path);
        } else {
                base_name = o->ancestor == NULL ? NULL :
-                       xstrdup(mkpath("%s", o->ancestor));
-               name1 = xstrdup(mkpath("%s", branch1));
-               name2 = xstrdup(mkpath("%s", branch2));
+                       mkpathdup("%s", o->ancestor);
+               name1 = mkpathdup("%s", branch1);
+               name2 = mkpathdup("%s", branch2);
        }
 
        read_mmblob(&orig, one->sha1);
@@ -879,6 +870,7 @@ static int merge_3way(struct merge_options *o,
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
                                &src1, name1, &src2, name2, &ll_opts);
 
+       free(base_name);
        free(name1);
        free(name2);
        free(orig.ptr);
@@ -936,11 +928,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
                                                  branch1, branch2);
 
                        if ((merge_status < 0) || !result_buf.ptr)
-                               die("Failed to execute internal merge");
+                               die(_("Failed to execute internal merge"));
 
                        if (write_sha1_file(result_buf.ptr, result_buf.size,
                                            blob_type, result.sha))
-                               die("Unable to add %s to database",
+                               die(_("Unable to add %s to database"),
                                    a->path);
 
                        free(result_buf.ptr);
@@ -956,7 +948,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o,
                        if (!sha_eq(a->sha1, b->sha1))
                                result.clean = 0;
                } else {
-                       die("unsupported object type in the tree");
+                       die(_("unsupported object type in the tree"));
                }
        }
 
@@ -993,7 +985,7 @@ merge_file_special_markers(struct merge_options *o,
        return mfi;
 }
 
-static struct merge_file_info merge_file(struct merge_options *o,
+static struct merge_file_info merge_file_one(struct merge_options *o,
                                         const char *path,
                                         const unsigned char *o_sha, int o_mode,
                                         const unsigned char *a_sha, int a_mode,
@@ -1034,22 +1026,32 @@ static void handle_change_delete(struct merge_options *o,
                remove_file_from_cache(path);
                update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
        } else if (!a_sha) {
-               output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-                      "and %s in %s. Version %s of %s left in tree%s%s.",
-                      change, path, o->branch1,
-                      change_past, o->branch2, o->branch2, path,
-                      NULL == renamed ? "" : " at ",
-                      NULL == renamed ? "" : renamed);
-               update_file(o, 0, b_sha, b_mode, renamed ? renamed : path);
+               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);
+                       update_file(o, 0, b_sha, 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);
+                       update_file(o, 0, b_sha, b_mode, renamed);
+               }
        } else {
-               output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
-                      "and %s in %s. Version %s of %s left in tree%s%s.",
-                      change, path, o->branch2,
-                      change_past, o->branch1, o->branch1, path,
-                      NULL == renamed ? "" : " at ",
-                      NULL == renamed ? "" : renamed);
-               if (renamed)
+               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);
+               } 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);
                        update_file(o, 0, a_sha, a_mode, renamed);
+               }
                /*
                 * No need to call update_file() on path when !renamed, since
                 * that would needlessly touch path.  We could call
@@ -1085,7 +1087,7 @@ static void conflict_rename_delete(struct merge_options *o,
                             orig->sha1, orig->mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
-                            "rename", "renamed");
+                            _("rename"), _("renamed"));
 
        if (o->call_depth) {
                remove_file_from_cache(dest->path);
@@ -1141,7 +1143,7 @@ static void handle_file(struct merge_options *o,
        } else {
                if (dir_in_way(rename->path, !o->call_depth)) {
                        dst_name = unique_path(o, rename->path, cur_branch);
-                       output(o, 1, "%s is a directory in %s adding as %s instead",
+                       output(o, 1, _("%s is a directory in %s adding as %s instead"),
                               rename->path, other_branch, dst_name);
                }
        }
@@ -1163,17 +1165,17 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
        struct diff_filespec *a = ci->pair1->two;
        struct diff_filespec *b = ci->pair2->two;
 
-       output(o, 1, "CONFLICT (rename/rename): "
+       output(o, 1, _("CONFLICT (rename/rename): "
               "Rename \"%s\"->\"%s\" in branch \"%s\" "
-              "rename \"%s\"->\"%s\" in \"%s\"%s",
+              "rename \"%s\"->\"%s\" in \"%s\"%s"),
               one->path, a->path, ci->branch1,
               one->path, b->path, ci->branch2,
-              o->call_depth ? " (left unresolved)" : "");
+              o->call_depth ? _(" (left unresolved)") : "");
        if (o->call_depth) {
                struct merge_file_info mfi;
                struct diff_filespec other;
                struct diff_filespec *add;
-               mfi = merge_file(o, one->path,
+               mfi = merge_file_one(o, one->path,
                                 one->sha1, one->mode,
                                 a->sha1, a->mode,
                                 b->sha1, b->mode,
@@ -1222,9 +1224,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
        struct merge_file_info mfi_c1;
        struct merge_file_info mfi_c2;
 
-       output(o, 1, "CONFLICT (rename/rename): "
+       output(o, 1, _("CONFLICT (rename/rename): "
               "Rename %s->%s in %s. "
-              "Rename %s->%s in %s",
+              "Rename %s->%s in %s"),
               a->path, c1->path, ci->branch1,
               b->path, c2->path, ci->branch2);
 
@@ -1252,7 +1254,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
        } else {
                char *new_path1 = unique_path(o, path, ci->branch1);
                char *new_path2 = unique_path(o, path, ci->branch2);
-               output(o, 1, "Renaming %s to %s and %s to %s instead",
+               output(o, 1, _("Renaming %s to %s and %s to %s instead"),
                       a->path, new_path1, b->path, new_path2);
                remove_file(o, 0, path, 0);
                update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
@@ -1451,22 +1453,22 @@ static int process_renames(struct merge_options *o,
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                clean_merge = 0;
                                try_merge = 1;
-                               output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. "
-                                      "%s added in %s",
+                               output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
+                                      "%s added in %s"),
                                       ren1_src, ren1_dst, branch1,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                        struct merge_file_info mfi;
-                                       mfi = merge_file(o, ren1_dst, null_sha1, 0,
+                                       mfi = merge_file_one(o, ren1_dst, null_sha1, 0,
                                                         ren1->pair->two->sha1, ren1->pair->two->mode,
                                                         dst_other.sha1, dst_other.mode,
                                                         branch1, branch2);
-                                       output(o, 1, "Adding merged %s", ren1_dst);
+                                       output(o, 1, _("Adding merged %s"), ren1_dst);
                                        update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
                                        try_merge = 0;
                                } else {
                                        char *new_path = unique_path(o, ren1_dst, branch2);
-                                       output(o, 1, "Adding as %s instead", new_path);
+                                       output(o, 1, _("Adding as %s instead"), new_path);
                                        update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
                                        free(new_path);
                                }
@@ -1517,10 +1519,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst)
        unsigned long size;
        buf = read_sha1_file(sha1, &type, &size);
        if (!buf)
-               return error("cannot read object %s", sha1_to_hex(sha1));
+               return error(_("cannot read object %s"), sha1_to_hex(sha1));
        if (type != OBJ_BLOB) {
                free(buf);
-               return error("object %s is not a blob", sha1_to_hex(sha1));
+               return error(_("object %s is not a blob"), sha1_to_hex(sha1));
        }
        strbuf_attach(dst, buf, size, size + 1);
        return 0;
@@ -1568,7 +1570,7 @@ static void handle_modify_delete(struct merge_options *o,
                             o_sha, o_mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
-                            "modify", "modified");
+                            _("modify"), _("modified"));
 }
 
 static int merge_content(struct merge_options *o,
@@ -1578,14 +1580,14 @@ static int merge_content(struct merge_options *o,
                         unsigned char *b_sha, int b_mode,
                         struct rename_conflict_info *rename_conflict_info)
 {
-       const char *reason = "content";
+       const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
        struct merge_file_info mfi;
        struct diff_filespec one, a, b;
        unsigned df_conflict_remains = 0;
 
        if (!o_sha) {
-               reason = "add/add";
+               reason = _("add/add");
                o_sha = (unsigned char *)null_sha1;
        }
        one.path = a.path = b.path = (char *)path;
@@ -1619,7 +1621,7 @@ static int merge_content(struct merge_options *o,
        if (mfi.clean && !df_conflict_remains &&
            sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) {
                int path_renamed_outside_HEAD;
-               output(o, 3, "Skipped %s (merged same as existing)", path);
+               output(o, 3, _("Skipped %s (merged same as existing)"), path);
                /*
                 * The content merge resulted in the same file contents we
                 * already had.  We can return early if those file contents
@@ -1633,12 +1635,12 @@ static int merge_content(struct merge_options *o,
                        return mfi.clean;
                }
        } else
-               output(o, 2, "Auto-merging %s", path);
+               output(o, 2, _("Auto-merging %s"), path);
 
        if (!mfi.clean) {
                if (S_ISGITLINK(mfi.mode))
-                       reason = "submodule";
-               output(o, 1, "CONFLICT (%s): Merge conflict in %s",
+                       reason = _("submodule");
+               output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
                                reason, path);
                if (rename_conflict_info && !df_conflict_remains)
                        update_stages(path, &one, &a, &b);
@@ -1664,7 +1666,7 @@ static int merge_content(struct merge_options *o,
 
                }
                new_path = unique_path(o, path, rename_conflict_info->branch1);
-               output(o, 1, "Adding as %s instead", new_path);
+               output(o, 1, _("Adding as %s instead"), new_path);
                update_file(o, 0, mfi.sha, mfi.mode, new_path);
                free(new_path);
                mfi.clean = 0;
@@ -1728,7 +1730,7 @@ static int process_entry(struct merge_options *o,
                        /* Deleted in both or deleted in one and
                         * unchanged in the other */
                        if (a_sha)
-                               output(o, 2, "Removing %s", path);
+                               output(o, 2, _("Removing %s"), path);
                        /* do not touch working file if it did not exist */
                        remove_file(o, 1, path, !a_sha);
                } else {
@@ -1753,19 +1755,19 @@ static int process_entry(struct merge_options *o,
                        other_branch = o->branch2;
                        mode = a_mode;
                        sha = a_sha;
-                       conf = "file/directory";
+                       conf = _("file/directory");
                } else {
                        add_branch = o->branch2;
                        other_branch = o->branch1;
                        mode = b_mode;
                        sha = b_sha;
-                       conf = "directory/file";
+                       conf = _("directory/file");
                }
                if (dir_in_way(path, !o->call_depth)) {
                        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. "
-                              "Adding %s as %s",
+                       output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
+                              "Adding %s as %s"),
                               conf, path, other_branch, path, new_path);
                        if (o->call_depth)
                                remove_file_from_cache(path);
@@ -1774,7 +1776,7 @@ static int process_entry(struct merge_options *o,
                                remove_file_from_cache(path);
                        free(new_path);
                } else {
-                       output(o, 2, "Adding %s", path);
+                       output(o, 2, _("Adding %s"), path);
                        /* do not overwrite file if already present */
                        update_file_flags(o, sha, mode, path, 1, !a_sha);
                }
@@ -1791,7 +1793,7 @@ static int process_entry(struct merge_options *o,
                 */
                remove_file(o, 1, path, !a_mode);
        } else
-               die("Fatal merge failure, shouldn't happen.");
+               die(_("Fatal merge failure, shouldn't happen."));
 
        return clean_merge;
 }
@@ -1810,7 +1812,7 @@ int merge_trees(struct merge_options *o,
        }
 
        if (sha_eq(common->object.sha1, merge->object.sha1)) {
-               output(o, 0, "Already up-to-date!");
+               output(o, 0, _("Already up-to-date!"));
                *result = head;
                return 1;
        }
@@ -1819,7 +1821,7 @@ int merge_trees(struct merge_options *o,
 
        if (code != 0) {
                if (show(o, 4) || o->call_depth)
-                       die("merging of trees %s and %s failed",
+                       die(_("merging of trees %s and %s failed"),
                            sha1_to_hex(head->object.sha1),
                            sha1_to_hex(merge->object.sha1));
                else
@@ -1849,7 +1851,7 @@ int merge_trees(struct merge_options *o,
                for (i = 0; i < entries->nr; i++) {
                        struct stage_data *e = entries->items[i].util;
                        if (!e->processed)
-                               die("Unprocessed path??? %s",
+                               die(_("Unprocessed path??? %s"),
                                    entries->items[i].string);
                }
 
@@ -1894,7 +1896,7 @@ int merge_recursive(struct merge_options *o,
        int clean;
 
        if (show(o, 4)) {
-               output(o, 4, "Merging:");
+               output(o, 4, _("Merging:"));
                output_commit_title(o, h1);
                output_commit_title(o, h2);
        }
@@ -1905,7 +1907,10 @@ int merge_recursive(struct merge_options *o,
        }
 
        if (show(o, 5)) {
-               output(o, 5, "found %u common ancestor(s):", commit_list_count(ca));
+               unsigned cnt = commit_list_count(ca);
+
+               output(o, 5, Q_("found %u common ancestor:",
+                               "found %u common ancestors:", cnt), cnt);
                for (iter = ca; iter; iter = iter->next)
                        output_commit_title(o, iter->item);
        }
@@ -1941,7 +1946,7 @@ int merge_recursive(struct merge_options *o,
                o->call_depth--;
 
                if (!merged_common_ancestors)
-                       die("merge returned no commit");
+                       die(_("merge returned no commit"));
        }
 
        discard_cache();
@@ -1998,7 +2003,7 @@ 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], sha1_to_hex(base_list[i]))))
-                               return error("Could not parse object '%s'",
+                               return error(_("Could not parse object '%s'"),
                                        sha1_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
@@ -2010,7 +2015,7 @@ int merge_recursive_generic(struct merge_options *o,
        if (active_cache_changed &&
                        (write_cache(index_fd, active_cache, active_nr) ||
                         commit_locked_index(lock)))
-               return error("Unable to write index.");
+               return error(_("Unable to write index."));
 
        return clean ? 0 : 1;
 }
@@ -2066,12 +2071,21 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->recursive_variant = MERGE_RECURSIVE_THEIRS;
        else if (!strcmp(s, "subtree"))
                o->subtree_shift = "";
-       else if (!prefixcmp(s, "subtree="))
+       else if (starts_with(s, "subtree="))
                o->subtree_shift = s + strlen("subtree=");
        else if (!strcmp(s, "patience"))
                o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
                o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
+       else if (starts_with(s, "diff-algorithm=")) {
+               long value = parse_algorithm_value(s + strlen("diff-algorithm="));
+               if (value < 0)
+                       return -1;
+               /* clear out previous settings */
+               DIFF_XDL_CLR(o, NEED_MINIMAL);
+               o->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+               o->xdl_opts |= value;
+       }
        else if (!strcmp(s, "ignore-space-change"))
                o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(s, "ignore-all-space"))
@@ -2082,7 +2096,7 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->renormalize = 1;
        else if (!strcmp(s, "no-renormalize"))
                o->renormalize = 0;
-       else if (!prefixcmp(s, "rename-threshold=")) {
+       else if (starts_with(s, "rename-threshold=")) {
                const char *score = s + strlen("rename-threshold=");
                if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0)
                        return -1;