With the new --bases, print merge commits' parents' merge bases.  This
is mostly a proof of viability, in particular wrt. revision walk
decoupling and speed.

We can do "inline" get_merge_bases() (via get_octopus_merge_bases)
because the walks in get_merge_bases() only use flag bits 16-19, and
we reset them after use.  The get_revision()/log display walk OTOH
uses only flag bits 0-15 (actually only 0-10 as of this commit).

Speed-wise it turns out to be better than attempting to compute merge
bases in one go, mostly because the latter approach would require
extensive data structures to track flags.  This commit does not have
to: the commit graph will be loaded anyway, and the room for flags is
already there.  As a big plus, this approach also works in a streaming
fashion, showing the first few commits very quickly.

Signed-off-by: Thomas Rast <t...@thomasrast.ch>
---

As indicated in the cover letter, this is cute, but I'm not married to
it.  It's probably just a useless instance of feature creep.

 Documentation/rev-list-options.txt |  7 +++++++
 log-tree.c                         |  3 +++
 pretty.c                           |  3 +++
 revision.c                         |  2 ++
 revision.h                         |  2 ++
 t/t4202-log.sh                     | 31 +++++++++++++++++++++++++++++++
 6 files changed, 48 insertions(+)

diff --git a/Documentation/rev-list-options.txt 
b/Documentation/rev-list-options.txt
index 03533af..d023290 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -705,6 +705,13 @@ endif::git-rev-list[]
        Print also the children of the commit (in the form "commit child...").
        Also enables parent rewriting, see 'History Simplification' below.
 
+ifndef::git-rev-list[]
+--bases::
+       For merge commits, print the merge bases of the commit's
+       parents.  (These are the bases that were used in the creation
+       of the merge itself.)
+endif::git-rev-list[]
+
 ifdef::git-rev-list[]
 --timestamp::
        Print the raw commit timestamp.
diff --git a/log-tree.c b/log-tree.c
index 08970bf..080f412 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -622,6 +622,8 @@ void show_log(struct rev_info *opt)
        ctx.output_encoding = get_log_output_encoding();
        if (opt->from_ident.mail_begin && opt->from_ident.name_begin)
                ctx.from_ident = &opt->from_ident;
+       if (opt->show_merge_bases && commit->parents && commit->parents->next)
+               ctx.merge_bases = get_octopus_merge_bases(commit->parents);
        pretty_print_commit(&ctx, commit, &msgbuf);
 
        if (opt->add_signoff)
@@ -662,6 +664,7 @@ void show_log(struct rev_info *opt)
 
        strbuf_release(&msgbuf);
        free(ctx.notes_message);
+       free(ctx.merge_bases);
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
diff --git a/pretty.c b/pretty.c
index 5e44cf8..8b28664 100644
--- a/pretty.c
+++ b/pretty.c
@@ -552,6 +552,9 @@ static void add_merge_info(const struct 
pretty_print_context *pp,
                return;
 
        pp_commit_list(pp, sb, "Merge:", parent);
+
+       if (pp->merge_bases)
+               pp_commit_list(pp, sb, "Bases:", pp->merge_bases);
 }
 
 static char *get_header(const struct commit *commit, const char *msg,
diff --git a/revision.c b/revision.c
index a0df72f..72255fb 100644
--- a/revision.c
+++ b/revision.c
@@ -1729,6 +1729,8 @@ static int handle_revision_opt(struct rev_info *revs, int 
argc, const char **arg
        } else if (!strcmp(arg, "--parents")) {
                revs->rewrite_parents = 1;
                revs->print_parents = 1;
+       } else if (!strcmp(arg, "--merge-bases")) {
+               revs->show_merge_bases = 1;
        } else if (!strcmp(arg, "--dense")) {
                revs->dense = 1;
        } else if (!strcmp(arg, "--sparse")) {
diff --git a/revision.h b/revision.h
index 88967d6..3111228 100644
--- a/revision.h
+++ b/revision.h
@@ -19,6 +19,7 @@
 #define PATCHSAME      (1u<<9)
 #define BOTTOM         (1u<<10)
 #define ALL_REV_FLAGS  ((1u<<11)-1)
+/* merge-base.c uses bits 16-19.  --merge-bases will break if they overlap! */
 
 #define DECORATE_SHORT_REFS    1
 #define DECORATE_FULL_REFS     2
@@ -137,6 +138,7 @@ struct rev_info {
                        preserve_subject:1;
        unsigned int    disable_stdin:1;
        unsigned int    leak_pending:1;
+       unsigned int    show_merge_bases:1;
 
        enum date_mode date_mode;
 
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index cb03d28..64f34a6 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -841,4 +841,35 @@ test_expect_success 'dotdot is a parent directory' '
        test_cmp expect actual
 '
 
+shorten () {
+       for arg; do
+               git rev-parse --short "$arg"
+       done
+}
+
+fill_in_merge_bases () {
+       while IFS= read line; do
+               case "$line" in
+               Merge:*)
+                       printf "%s\n" "$line"
+                       printf "%s" "Bases:"
+                       printf " %s" $(shorten \
+                           $(git merge-base --all --octopus \
+                               ${line##Merge:}))
+                       printf "\n"
+                       ;;
+               *)
+                       printf "%s\n" "$line"
+                       ;;
+               esac
+       done
+}
+
+test_expect_success '--merge-bases' '
+       git log |
+       fill_in_merge_bases >expect
+       git log --merge-bases >actual &&
+       test_cmp expect actual
+'
+
 test_done
-- 
1.9.rc2.232.gdd31389

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