Hi Elijah,

On Thu, 25 Jul 2019, Elijah Newren wrote:

> In commit 7ca56aa07619 ("merge-recursive: add a label for ancestor",
> 2010-03-20), a label was added for the '||||||' line to make it have
> the more informative heading '|||||| merged common ancestors', with
> the statement:
>
>     It would be nicer to use a more informative label.  Perhaps someone
>     will provide one some day.
>
> This chosen label was perfectly reasonable when recursiveness kicks in,
> i.e. when there are multiple merge bases.  (I can't think of a better
> label in such cases.)  But it is actually somewhat misleading when there
> is a unique merge base or no merge base.  Change this based on the
> number of merge bases:
>     >=2: "merged common ancestors"
>     1:   <abbreviated commit hash>
>     0:   "<empty tree>"

Nice!

> Also, the code in merge_3way making use of opt->ancestor was overly
> complex because it tried to handle the case of opt->ancestor being NULL.
> We always set it first, though, so just add an assert that opt->ancestor
> is not NULL and simplify the surrounding code.
>
> Tests have also been added to check that we get the right ancestor name
> for each of the three cases.
>
> Signed-off-by: Elijah Newren <new...@gmail.com>
> ---
>  merge-recursive.c                 |  35 ++++--
>  t/t6036-recursive-corner-cases.sh |   8 +-
>  t/t6047-diff3-conflict-markers.sh | 191 ++++++++++++++++++++++++++++++
>  3 files changed, 220 insertions(+), 14 deletions(-)
>  create mode 100755 t/t6047-diff3-conflict-markers.sh
>
> diff --git a/merge-recursive.c b/merge-recursive.c
> index 4cd6599296..8ac53cacdf 100644
> --- a/merge-recursive.c
> +++ b/merge-recursive.c
> @@ -1034,7 +1034,7 @@ static int merge_3way(struct merge_options *opt,
>  {
>       mmfile_t orig, src1, src2;
>       struct ll_merge_options ll_opts = {0};
> -     char *base_name, *name1, *name2;
> +     char *base, *name1, *name2;

Renaming this variable at the same time as doing other, more involved
changes, made this patch a bit harder to review for me, I must admit.

>       int merge_status;
>
>       ll_opts.renormalize = opt->renormalize;
> @@ -1058,16 +1058,13 @@ static int merge_3way(struct merge_options *opt,
>               }
>       }
>
> -     assert(a->path && b->path && o->path);
> -     if (strcmp(a->path, b->path) ||
> -         (opt->ancestor != NULL && strcmp(a->path, o->path) != 0)) {
> -             base_name = opt->ancestor == NULL ? NULL :
> -                     mkpathdup("%s:%s", opt->ancestor, o->path);
> +     assert(a->path && b->path && o->path && opt->ancestor);
> +     if (strcmp(a->path, b->path) || strcmp(a->path, o->path) != 0) {
> +             base  = mkpathdup("%s:%s", opt->ancestor, o->path);
>               name1 = mkpathdup("%s:%s", branch1, a->path);
>               name2 = mkpathdup("%s:%s", branch2, b->path);
>       } else {
> -             base_name = opt->ancestor == NULL ? NULL :
> -                     mkpathdup("%s", opt->ancestor);
> +             base  = mkpathdup("%s", opt->ancestor);
>               name1 = mkpathdup("%s", branch1);
>               name2 = mkpathdup("%s", branch2);
>       }
> @@ -1076,11 +1073,11 @@ static int merge_3way(struct merge_options *opt,
>       read_mmblob(&src1, &a->oid);
>       read_mmblob(&src2, &b->oid);
>
> -     merge_status = ll_merge(result_buf, a->path, &orig, base_name,
> +     merge_status = ll_merge(result_buf, a->path, &orig, base,
>                               &src1, name1, &src2, name2,
>                               opt->repo->index, &ll_opts);
>
> -     free(base_name);
> +     free(base);
>       free(name1);
>       free(name2);
>       free(orig.ptr);
> @@ -3517,6 +3514,8 @@ static int merge_recursive_internal(struct 
> merge_options *opt,
>       struct commit *merged_merge_bases;
>       struct tree *result_tree;
>       int clean;
> +     int num_merge_bases;
> +     struct strbuf commit_name = STRBUF_INIT;
>
>       if (show(opt, 4)) {
>               output(opt, 4, _("Merging:"));
> @@ -3538,6 +3537,7 @@ static int merge_recursive_internal(struct 
> merge_options *opt,
>                       output_commit_title(opt, iter->item);
>       }
>
> +     num_merge_bases = commit_list_count(merge_bases);

At first, I thought that this does not require a separate variable
because it is used exactly once.

But then I realized that the next line changes the number of commits in
`merge_bases`, so it actually _is_ required.

>       merged_merge_bases = pop_commit(&merge_bases);
>       if (merged_merge_bases == NULL) {
>               /* if there is no common ancestor, use an empty tree */
> @@ -3579,13 +3579,26 @@ static int merge_recursive_internal(struct 
> merge_options *opt,
>       if (!opt->priv->call_depth)
>               repo_read_index(opt->repo);
>
> -     opt->ancestor = "merged common ancestors";
> +     switch (num_merge_bases) {
> +     case 0:
> +             opt->ancestor = "<empty tree>";
> +             break;
> +     case 1:
> +             strbuf_add_unique_abbrev(&commit_name,

The name `commit_name` would suggest a different usage to me. How about
`pretty_merge_base`?

> +                                      &merged_merge_bases->object.oid,
> +                                      DEFAULT_ABBREV);
> +             opt->ancestor = commit_name.buf;
> +             break;
> +     default:
> +             opt->ancestor = "merged common ancestors";
> +     }
>       clean = merge_trees_internal(opt,
>                                    repo_get_commit_tree(opt->repo, h1),
>                                    repo_get_commit_tree(opt->repo, h2),
>                                    repo_get_commit_tree(opt->repo,
>                                                         merged_merge_bases),
>                                    &result_tree);
> +     strbuf_release(&commit_name);
>       if (clean < 0) {
>               flush_output(opt);
>               return clean;

I was a bit too tired to look more closely at the test cases, in
particular after seeing the enormous complexity of the added test
script. I wonder whether it really has to be all that complex (e.g. why
use a complicated `test_seq` when a `test_commit A A.t
"1${LF}2${LF}3${LF}A${LF}` would suffice? Why start by `git checkout
--orphan` on a just-created repository?)

But otherwise, the patch series looks pretty good to me.

Thanks,
Dscho

Reply via email to