Skip to content

Commit 694a981

Browse files
gitsterdscho
authored andcommitted
Merge branch 'js/am-3-merge-recursive-direct' into jch
The merge_recursive_generic() function has been made a bit safer to call from inside a process. "git am -3" was taught to make a direct call to the function when falling back to three-way merge. Being able to make a direct call would be good in general, but as a performance thing, the change needs to be backed up by numbers. I haven't gone through the "gently" change with fine toothed comb; I can see that the change avoids calling die(), but I haven't made sure that the program states (e.g. what's in the in-core index) are adjusted sensibly when it returns to the caller instead of dying, or the codepaths that used to die() are free of resource leaks. The original code certainly did not care the program states at the point of dying exactly because it knew it is going to exit, but now they have to care, and they need to be audited. * js/am-3-merge-recursive-direct: am: make a direct call to merge_recursive merge_recursive_options: introduce the "gently" flag Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent df7abff commit 694a981

3 files changed

Lines changed: 51 additions & 22 deletions

File tree

builtin/am.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,25 +1588,25 @@ static int run_fallback_merge_recursive(const struct am_state *state,
15881588
unsigned char *our_tree,
15891589
unsigned char *his_tree)
15901590
{
1591-
struct child_process cp = CHILD_PROCESS_INIT;
1591+
const unsigned char *bases[1] = {orig_tree};
1592+
struct merge_options o;
1593+
struct commit *result;
1594+
char *his_tree_name;
15921595
int status;
15931596

1594-
cp.git_cmd = 1;
1597+
init_merge_options(&o);
1598+
1599+
o.gently = 1;
1600+
o.branch1 = "HEAD";
1601+
his_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
1602+
o.branch2 = his_tree_name;
15951603

1596-
argv_array_pushf(&cp.env_array, "GITHEAD_%s=%.*s",
1597-
sha1_to_hex(his_tree), linelen(state->msg), state->msg);
15981604
if (state->quiet)
1599-
argv_array_push(&cp.env_array, "GIT_MERGE_VERBOSITY=0");
1605+
o.verbosity = 0;
16001606

1601-
argv_array_push(&cp.args, "merge-recursive");
1602-
argv_array_push(&cp.args, sha1_to_hex(orig_tree));
1603-
argv_array_push(&cp.args, "--");
1604-
argv_array_push(&cp.args, sha1_to_hex(our_tree));
1605-
argv_array_push(&cp.args, sha1_to_hex(his_tree));
1607+
status = merge_recursive_generic(&o, our_tree, his_tree, 1, bases, &result);
1608+
free(his_tree_name);
16061609

1607-
status = run_command(&cp) ? (-1) : 0;
1608-
discard_cache();
1609-
read_cache();
16101610
return status;
16111611
}
16121612

merge-recursive.c

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,12 @@ struct tree *write_tree_from_memory(struct merge_options *o)
266266
active_cache_tree = cache_tree();
267267

268268
if (!cache_tree_fully_valid(active_cache_tree) &&
269-
cache_tree_update(&the_index, 0) < 0)
270-
die(_("error building trees"));
269+
cache_tree_update(&the_index, 0) < 0) {
270+
if (!o->gently)
271+
die(_("error building trees"));
272+
error(_("error building trees"));
273+
return NULL;
274+
}
271275

272276
result = lookup_tree(active_cache_tree->sha1);
273277

@@ -714,6 +718,8 @@ static int make_room_for_path(struct merge_options *o, const char *path)
714718
error(msg, path, _(": perhaps a D/F conflict?"));
715719
return -1;
716720
}
721+
if (o->gently)
722+
return error(msg, path, "");
717723
die(msg, path, "");
718724
}
719725

@@ -1342,8 +1348,11 @@ static int process_renames(struct merge_options *o,
13421348
const char *ren2_src = ren2->pair->one->path;
13431349
const char *ren2_dst = ren2->pair->two->path;
13441350
enum rename_type rename_type;
1345-
if (strcmp(ren1_src, ren2_src) != 0)
1351+
if (strcmp(ren1_src, ren2_src) != 0) {
1352+
if (o->gently)
1353+
return error("ren1_src != ren2_src");
13461354
die("ren1_src != ren2_src");
1355+
}
13471356
ren2->dst_entry->processed = 1;
13481357
ren2->processed = 1;
13491358
if (strcmp(ren1_dst, ren2_dst) != 0) {
@@ -1376,8 +1385,11 @@ static int process_renames(struct merge_options *o,
13761385
char *ren2_dst;
13771386
ren2 = lookup->util;
13781387
ren2_dst = ren2->pair->two->path;
1379-
if (strcmp(ren1_dst, ren2_dst) != 0)
1388+
if (strcmp(ren1_dst, ren2_dst) != 0) {
1389+
if (o->gently)
1390+
return error("ren1_dst != ren2_dst");
13801391
die("ren1_dst != ren2_dst");
1392+
}
13811393

13821394
clean_merge = 0;
13831395
ren2->processed = 1;
@@ -1824,6 +1836,13 @@ int merge_trees(struct merge_options *o,
18241836
code = git_merge_trees(o->call_depth, common, head, merge);
18251837

18261838
if (code != 0) {
1839+
if (o->gently) {
1840+
error(_("merging of trees %s and %s failed"),
1841+
oid_to_hex(&head->object.oid),
1842+
oid_to_hex(&merge->object.oid));
1843+
return -128;
1844+
}
1845+
18271846
if (show(o, 4) || o->call_depth)
18281847
die(_("merging of trees %s and %s failed"),
18291848
oid_to_hex(&head->object.oid),
@@ -1870,8 +1889,8 @@ int merge_trees(struct merge_options *o,
18701889
else
18711890
clean = 1;
18721891

1873-
if (o->call_depth)
1874-
*result = write_tree_from_memory(o);
1892+
if (o->call_depth && !(*result = write_tree_from_memory(o)))
1893+
return -1;
18751894

18761895
return clean;
18771896
}
@@ -1946,14 +1965,18 @@ int merge_recursive(struct merge_options *o,
19461965
saved_b2 = o->branch2;
19471966
o->branch1 = "Temporary merge branch 1";
19481967
o->branch2 = "Temporary merge branch 2";
1949-
merge_recursive(o, merged_common_ancestors, iter->item,
1950-
NULL, &merged_common_ancestors);
1968+
if (merge_recursive(o, merged_common_ancestors, iter->item,
1969+
NULL, &merged_common_ancestors) < 0)
1970+
return -1;
19511971
o->branch1 = saved_b1;
19521972
o->branch2 = saved_b2;
19531973
o->call_depth--;
19541974

1955-
if (!merged_common_ancestors)
1975+
if (!merged_common_ancestors) {
1976+
if (o->gently)
1977+
return error(_("merge returned no commit"));
19561978
die(_("merge returned no commit"));
1979+
}
19571980
}
19581981

19591982
discard_cache();
@@ -1963,6 +1986,8 @@ int merge_recursive(struct merge_options *o,
19631986
o->ancestor = "merged common ancestors";
19641987
clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
19651988
&mrtree);
1989+
if (clean < 0)
1990+
return clean;
19661991

19671992
if (o->call_depth) {
19681993
*result = make_virtual_commit(mrtree, "merged tree");
@@ -2019,6 +2044,9 @@ int merge_recursive_generic(struct merge_options *o,
20192044
hold_locked_index(lock, 1);
20202045
clean = merge_recursive(o, head_commit, next_commit, ca,
20212046
result);
2047+
if (clean < 0)
2048+
return clean;
2049+
20222050
if (active_cache_changed &&
20232051
write_locked_index(&the_index, lock, COMMIT_LOCK))
20242052
return error(_("Unable to write index."));

merge-recursive.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct merge_options {
1515
const char *subtree_shift;
1616
unsigned buffer_output : 1;
1717
unsigned renormalize : 1;
18+
unsigned gently : 1;
1819
long xdl_opts;
1920
int verbosity;
2021
int detect_rename;

0 commit comments

Comments
 (0)