From ef1177d18e35c030c37aa533002a11d98361e6b9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 Jul 2016 18:05:50 +0200 Subject: die("bug"): report bugs consistently The vast majority of error messages in Git's source code which report a bug use the convention to prefix the message with "BUG:". As part of cleaning up merge-recursive to stop die()ing except in case of detected bugs, let's just make the remainder of the bug reports consistent with the de facto rule. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin/ls-files.c | 3 ++- builtin/update-index.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'builtin') diff --git a/builtin/ls-files.c b/builtin/ls-files.c index f02e3d23bb..00ea91aae6 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -118,7 +118,8 @@ static void show_killed_files(struct dir_struct *dir) */ pos = cache_name_pos(ent->name, ent->len); if (0 <= pos) - die("bug in show-killed-files"); + die("BUG: killed-file %.*s not found", + ent->len, ent->name); pos = -pos - 1; while (pos < active_nr && ce_stage(active_cache[pos])) diff --git a/builtin/update-index.c b/builtin/update-index.c index 6cdfd5f730..ba04b197d8 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1146,7 +1146,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) report(_("Untracked cache enabled for '%s'"), get_git_work_tree()); break; default: - die("Bug: bad untracked_cache value: %d", untracked_cache); + die("BUG: bad untracked_cache value: %d", untracked_cache); } if (active_cache_changed) { -- cgit v1.2.3 From f241ff0d0a9ddb84b2f673a1b7a92fea0d6add3a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 Jul 2016 18:06:02 +0200 Subject: prepare the builtins for a libified merge_recursive() Previously, callers of merge_trees() or merge_recursive() expected that code to die() with an error message. This used to be okay because we called those commands from scripts, and had a chance to print out a message in case the command failed fatally (read: with exit code 128). As scripting incurs its own set of problems (portability, speed, idiosyncrasies of different shells, limited data structures leading to inefficient code), we are converting more and more of these scripts into builtins, using library functions directly. We already tried to use merge_recursive() directly in the builtin git-am, for example. Unfortunately, we had to roll it back temporarily because some of the code in merge-recursive.c still deemed it okay to call die(), when the builtin am code really wanted to print out a useful advice after the merge failed fatally. In the next commits, we want to fix that. The code touched by this commit expected merge_trees() to die() with some useful message when there is an error condition, but merge_trees() is going to be improved by converting all die() calls to return error() instead (i.e. return value -1 after printing out the message as before), so that the caller can react more flexibly. This is a step to prepare for the version of merge_trees() that no longer dies, even if we just imitate the previous behavior by calling exit(128): this is what callers of e.g. `git merge` have come to expect. Note that the callers of the sequencer (revert and cherry-pick) already fail fast even for the return value -1; The only difference is that they now get a chance to say " failed". A caller of merge_trees() might want handle error messages themselves (or even suppress them). As this patch is already complex enough, we leave that change for a later patch. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin/checkout.c | 4 +++- builtin/merge.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'builtin') diff --git a/builtin/checkout.c b/builtin/checkout.c index 27c1a05246..07dea3bc81 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -567,8 +567,10 @@ static int merge_working_tree(const struct checkout_opts *opts, o.ancestor = old->name; o.branch1 = new->name; o.branch2 = "local"; - merge_trees(&o, new->commit->tree, work, + ret = merge_trees(&o, new->commit->tree, work, old->commit->tree, &result); + if (ret < 0) + exit(128); ret = reset_tree(new->commit->tree, opts, 0, writeout_error); if (ret) diff --git a/builtin/merge.c b/builtin/merge.c index 19b3bc2f2f..148a9a51b9 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -673,6 +673,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, hold_locked_index(&lock, 1); clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); + if (clean < 0) + exit(128); if (active_cache_changed && write_locked_index(&the_index, &lock, COMMIT_LOCK)) die (_("unable to write %s"), get_index_file()); -- cgit v1.2.3 From 3f338f43b0eb8081660bbf694074a368cf07355e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 26 Jul 2016 18:06:30 +0200 Subject: am -3: use merge_recursive() directly again 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 Signed-off-by: Junio C Hamano --- builtin/am.c | 62 +++++++++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 40 deletions(-) (limited to 'builtin') diff --git a/builtin/am.c b/builtin/am.c index b77bf11ace..cfb79ea906 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1578,48 +1578,19 @@ static int build_fake_ancestor(const struct am_state *state, const char *index_f return 0; } -/** - * 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; } -- cgit v1.2.3 From 548009c0d58c74dde2c51f675b369b4c50878f1b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 1 Aug 2016 13:44:53 +0200 Subject: merge_trees(): ensure that the callers release output buffer The recursive merge machinery accumulates its output in an output buffer, to be flushed at the end of merge_recursive(). At this point, we forgot to release the output buffer. When calling merge_trees() (i.e. the non-recursive part of the recursive merge) directly, the output buffer is never flushed because the caller may be merge_recursive() which wants to flush the output itself. For the same reason, merge_trees() cannot release the output buffer: it may still be needed. Forgetting to release the output buffer did not matter much when running git-checkout, or git-merge-recursive, because we exited after the operation anyway. Ever since cherry-pick learned to pick a commit range, however, this memory leak had the potential of becoming a problem. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin/checkout.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin') diff --git a/builtin/checkout.c b/builtin/checkout.c index 07dea3bc81..8d852d4585 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -573,6 +573,7 @@ static int merge_working_tree(const struct checkout_opts *opts, exit(128); ret = reset_tree(new->commit->tree, opts, 0, writeout_error); + strbuf_release(&o.obuf); if (ret) return ret; } -- cgit v1.2.3