Last October, we had to change this code to run `git merge-recursive`
in a child process: git-am wants to print some helpful advice when the
merge failed, but the code in question was not prepared to return, it
die()d instead.

We are finally at a point when the code *is* prepared to return errors,
and can avoid the child process again.

This reverts commit c63d4b2 (am -3: do not let failed merge from
completing the error codepath, 2015-10-09), with the necessary changes
to adjust for the fact that Git's source code changed in the meantime
(such as: using OIDs instead of hashes in the recursive merge, and a
removed gender bias).

Note: the code now calls merge_recursive_generic() again. Unlike
merge_trees() and merge_recursive(), this function returns 0 upon success,
as most of Git's functions. Therefore, the error value -1 naturally is
handled correctly, and we do not have to take care of it specifically.

Signed-off-by: Johannes Schindelin <johannes.schinde...@gmx.de>
---
 builtin/am.c | 62 +++++++++++++++++++++---------------------------------------
 1 file changed, 22 insertions(+), 40 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index b77bf11..cfb79ea 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1579,47 +1579,18 @@ static int build_fake_ancestor(const struct am_state 
*state, const char *index_f
 }
 
 /**
- * Do the three-way merge using fake ancestor, their tree constructed
- * from the fake ancestor and the postimage of the patch, and our
- * state.
- */
-static int run_fallback_merge_recursive(const struct am_state *state,
-                                       unsigned char *orig_tree,
-                                       unsigned char *our_tree,
-                                       unsigned char *their_tree)
-{
-       struct child_process cp = CHILD_PROCESS_INIT;
-       int status;
-
-       cp.git_cmd = 1;
-
-       argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
-                        sha1_to_hex(their_tree), linelen(state->msg), 
state->msg);
-       if (state->quiet)
-               argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
-
-       argv_array_push(&cp.args, "merge-recursive");
-       argv_array_push(&cp.args, sha1_to_hex(orig_tree));
-       argv_array_push(&cp.args, "--");
-       argv_array_push(&cp.args, sha1_to_hex(our_tree));
-       argv_array_push(&cp.args, sha1_to_hex(their_tree));
-
-       status = run_command(&cp) ? (-1) : 0;
-       discard_cache();
-       read_cache();
-       return status;
-}
-
-/**
  * Attempt a threeway merge, using index_path as the temporary index.
  */
 static int fall_back_threeway(const struct am_state *state, const char 
*index_path)
 {
-       unsigned char orig_tree[GIT_SHA1_RAWSZ], their_tree[GIT_SHA1_RAWSZ],
-                     our_tree[GIT_SHA1_RAWSZ];
+       struct object_id orig_tree, their_tree, our_tree;
+       const struct object_id *bases[1] = { &orig_tree };
+       struct merge_options o;
+       struct commit *result;
+       char *their_tree_name;
 
-       if (get_sha1("HEAD", our_tree) < 0)
-               hashcpy(our_tree, EMPTY_TREE_SHA1_BIN);
+       if (get_oid("HEAD", &our_tree) < 0)
+               hashcpy(our_tree.hash, EMPTY_TREE_SHA1_BIN);
 
        if (build_fake_ancestor(state, index_path))
                return error("could not build fake ancestor");
@@ -1627,7 +1598,7 @@ static int fall_back_threeway(const struct am_state 
*state, const char *index_pa
        discard_cache();
        read_cache_from(index_path);
 
-       if (write_index_as_tree(orig_tree, &the_index, index_path, 0, NULL))
+       if (write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, 
NULL))
                return error(_("Repository lacks necessary blobs to fall back 
on 3-way merge."));
 
        say(state, stdout, _("Using index info to reconstruct a base tree..."));
@@ -1643,7 +1614,7 @@ static int fall_back_threeway(const struct am_state 
*state, const char *index_pa
                init_revisions(&rev_info, NULL);
                rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
                diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, 
rev_info.prefix);
-               add_pending_sha1(&rev_info, "HEAD", our_tree, 0);
+               add_pending_sha1(&rev_info, "HEAD", our_tree.hash, 0);
                diff_setup_done(&rev_info.diffopt);
                run_diff_index(&rev_info, 1);
        }
@@ -1652,7 +1623,7 @@ static int fall_back_threeway(const struct am_state 
*state, const char *index_pa
                return error(_("Did you hand edit your patch?\n"
                                "It does not apply to blobs recorded in its 
index."));
 
-       if (write_index_as_tree(their_tree, &the_index, index_path, 0, NULL))
+       if (write_index_as_tree(their_tree.hash, &the_index, index_path, 0, 
NULL))
                return error("could not write tree");
 
        say(state, stdout, _("Falling back to patching base and 3-way 
merge..."));
@@ -1668,11 +1639,22 @@ static int fall_back_threeway(const struct am_state 
*state, const char *index_pa
         * changes.
         */
 
-       if (run_fallback_merge_recursive(state, orig_tree, our_tree, 
their_tree)) {
+       init_merge_options(&o);
+
+       o.branch1 = "HEAD";
+       their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
+       o.branch2 = their_tree_name;
+
+       if (state->quiet)
+               o.verbosity = 0;
+
+       if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, 
&result)) {
                rerere(state->allow_rerere_autoupdate);
+               free(their_tree_name);
                return error(_("Failed to merge in the changes."));
        }
 
+       free(their_tree_name);
        return 0;
 }
 
-- 
2.9.0.281.g286a8d9


--
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