Traditionally, all of Git's operations were intended as single
executables to be run once and exit, not as library functions with
careful error code paths. Therefore, it was okay for those operations
to simply die() with an error.

However, this assumption no longer holds true: builtin `am` calls
merge_recursive_generic() as a regular library function whose return
value indicates whether there was a problem.

Throughout Git's source code, that paradigm (to return an error instead
of die()ing) is called "gentle".

Let's introduce this flag and heed it in as many places as is easily
done.

Signed-off-by: Johannes Schindelin <johannes.schinde...@gmx.de>
---
 merge-recursive.c | 44 +++++++++++++++++++++++++++++++++++---------
 merge-recursive.h |  1 +
 2 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index 44d85be..37528c9 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -266,8 +266,12 @@ struct tree *write_tree_from_memory(struct merge_options 
*o)
                active_cache_tree = cache_tree();
 
        if (!cache_tree_fully_valid(active_cache_tree) &&
-           cache_tree_update(&the_index, 0) < 0)
-               die(_("error building trees"));
+           cache_tree_update(&the_index, 0) < 0) {
+               if (!o->gentle)
+                       die(_("error building trees"));
+               error(_("error building trees"));
+               return NULL;
+       }
 
        result = lookup_tree(active_cache_tree->sha1);
 
@@ -712,6 +716,8 @@ static int make_room_for_path(struct merge_options *o, 
const char *path)
                        error(msg, path, _(": perhaps a D/F conflict?"));
                        return -1;
                }
+               if (o->gentle)
+                       return error(msg, path, "");
                die(msg, path, "");
        }
 
@@ -1340,8 +1346,11 @@ static int process_renames(struct merge_options *o,
                        const char *ren2_src = ren2->pair->one->path;
                        const char *ren2_dst = ren2->pair->two->path;
                        enum rename_type rename_type;
-                       if (strcmp(ren1_src, ren2_src) != 0)
+                       if (strcmp(ren1_src, ren2_src) != 0) {
+                               if (o->gentle)
+                                       return error("ren1_src != ren2_src");
                                die("ren1_src != ren2_src");
+                       }
                        ren2->dst_entry->processed = 1;
                        ren2->processed = 1;
                        if (strcmp(ren1_dst, ren2_dst) != 0) {
@@ -1374,8 +1383,11 @@ static int process_renames(struct merge_options *o,
                        char *ren2_dst;
                        ren2 = lookup->util;
                        ren2_dst = ren2->pair->two->path;
-                       if (strcmp(ren1_dst, ren2_dst) != 0)
+                       if (strcmp(ren1_dst, ren2_dst) != 0) {
+                               if (o->gentle)
+                                       return error("ren1_dst != ren2_dst");
                                die("ren1_dst != ren2_dst");
+                       }
 
                        clean_merge = 0;
                        ren2->processed = 1;
@@ -1818,6 +1830,11 @@ int merge_trees(struct merge_options *o,
        code = git_merge_trees(o->call_depth, common, head, merge);
 
        if (code != 0) {
+               if (o->gentle)
+                       return error(_("merging of trees %s and %s failed"),
+                           sha1_to_hex(head->object.sha1),
+                           sha1_to_hex(merge->object.sha1));
+
                if (show(o, 4) || o->call_depth)
                        die(_("merging of trees %s and %s failed"),
                            sha1_to_hex(head->object.sha1),
@@ -1864,8 +1881,8 @@ int merge_trees(struct merge_options *o,
        else
                clean = 1;
 
-       if (o->call_depth)
-               *result = write_tree_from_memory(o);
+       if (o->call_depth && !(*result = write_tree_from_memory(o)))
+               return -1;
 
        return clean;
 }
@@ -1940,14 +1957,18 @@ int merge_recursive(struct merge_options *o,
                saved_b2 = o->branch2;
                o->branch1 = "Temporary merge branch 1";
                o->branch2 = "Temporary merge branch 2";
-               merge_recursive(o, merged_common_ancestors, iter->item,
-                               NULL, &merged_common_ancestors);
+               if (merge_recursive(o, merged_common_ancestors, iter->item,
+                               NULL, &merged_common_ancestors) < 0)
+                       return -1;
                o->branch1 = saved_b1;
                o->branch2 = saved_b2;
                o->call_depth--;
 
-               if (!merged_common_ancestors)
+               if (!merged_common_ancestors) {
+                       if (o->gentle)
+                               return error(_("merge returned no commit"));
                        die(_("merge returned no commit"));
+               }
        }
 
        discard_cache();
@@ -1957,6 +1978,8 @@ 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)
+               return clean;
 
        if (o->call_depth) {
                *result = make_virtual_commit(mrtree, "merged tree");
@@ -2013,6 +2036,9 @@ int merge_recursive_generic(struct merge_options *o,
        hold_locked_index(lock, 1);
        clean = merge_recursive(o, head_commit, next_commit, ca,
                        result);
+       if (clean < 0)
+               return clean;
+
        if (active_cache_changed &&
            write_locked_index(&the_index, lock, COMMIT_LOCK))
                return error(_("Unable to write index."));
diff --git a/merge-recursive.h b/merge-recursive.h
index 9e090a3..06f9b7e 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -15,6 +15,7 @@ struct merge_options {
        const char *subtree_shift;
        unsigned buffer_output : 1;
        unsigned renormalize : 1;
+       unsigned gentle : 1;
        long xdl_opts;
        int verbosity;
        int diff_rename_limit;
-- 
2.6.1.windows.1



--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to