]> asedeno.scripts.mit.edu Git - git.git/blobdiff - graph.c
log --graph --left-right: show left/right information in place of '*'
[git.git] / graph.c
diff --git a/graph.c b/graph.c
index 616e18b13f496cd97bce5333b6c7655ae3cfa2f0..dc2c1ec5d77932dc1e30057603d02a79b4d60f94 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -54,12 +54,22 @@ struct git_graph {
         * The commit currently being processed
         */
        struct commit *commit;
+       /* The rev-info used for the current traversal */
+       struct rev_info *revs;
        /*
-        * The number of parents this commit has.
-        * (Stored so we don't have to walk over them each time we need
-        * this number)
+        * The number of interesting parents that this commit has.
+        *
+        * Note that this is not the same as the actual number of parents.
+        * This count excludes parents that won't be printed in the graph
+        * output, as determined by graph_is_interesting().
         */
        int num_parents;
+       /*
+        * The width of the graph output for this commit.
+        * All rows for this commit are padded to this width, so that
+        * messages printed after the graph output are aligned.
+        */
+       int width;
        /*
         * The next expansion row to print
         * when state is GRAPH_PRE_COMMIT
@@ -119,10 +129,11 @@ struct git_graph {
        int *new_mapping;
 };
 
-struct git_graph *graph_init(void)
+struct git_graph *graph_init(struct rev_info *opt)
 {
        struct git_graph *graph = xmalloc(sizeof(struct git_graph));
        graph->commit = NULL;
+       graph->revs = opt;
        graph->num_parents = 0;
        graph->expansion_row = 0;
        graph->state = GRAPH_PADDING;
@@ -174,6 +185,18 @@ static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
                                      sizeof(int) * 2 * graph->column_capacity);
 }
 
+/*
+ * Returns 1 if the commit will be printed in the graph output,
+ * and 0 otherwise.
+ */
+static int graph_is_interesting(struct commit *commit)
+{
+       /*
+        * Uninteresting and pruned commits won't be printed
+        */
+       return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1;
+}
+
 static void graph_insert_into_new_columns(struct git_graph *graph,
                                          struct commit *commit,
                                          int *mapping_index)
@@ -181,9 +204,9 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
        int i;
 
        /*
-        * Ignore uinteresting and pruned commits
+        * Ignore uinteresting commits
         */
-       if (commit->object.flags & (UNINTERESTING | TREESAME))
+       if (!graph_is_interesting(commit))
                return;
 
        /*
@@ -207,13 +230,48 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
        graph->num_new_columns++;
 }
 
+static void graph_update_width(struct git_graph *graph,
+                              int is_commit_in_existing_columns)
+{
+       /*
+        * Compute the width needed to display the graph for this commit.
+        * This is the maximum width needed for any row.  All other rows
+        * will be padded to this width.
+        *
+        * Compute the number of columns in the widest row:
+        * Count each existing column (graph->num_columns), and each new
+        * column added by this commit.
+        */
+       int max_cols = graph->num_columns + graph->num_parents;
+
+       /*
+        * Even if the current commit has no parents to be printed, it
+        * still takes up a column for itself.
+        */
+       if (graph->num_parents < 1)
+               max_cols++;
+
+       /*
+        * We added a column for the the current commit as part of
+        * graph->num_parents.  If the current commit was already in
+        * graph->columns, then we have double counted it.
+        */
+       if (is_commit_in_existing_columns)
+               max_cols--;
+
+       /*
+        * Each column takes up 2 spaces
+        */
+       graph->width = max_cols * 2;
+}
+
 static void graph_update_columns(struct git_graph *graph)
 {
        struct commit_list *parent;
        struct column *tmp_columns;
        int max_new_columns;
        int mapping_idx;
-       int i, seen_this;
+       int i, seen_this, is_commit_in_columns;
 
        /*
         * Swap graph->columns with graph->new_columns
@@ -259,17 +317,20 @@ static void graph_update_columns(struct git_graph *graph)
         */
        seen_this = 0;
        mapping_idx = 0;
+       is_commit_in_columns = 1;
        for (i = 0; i <= graph->num_columns; i++) {
                struct commit *col_commit;
                if (i == graph->num_columns) {
                        if (seen_this)
                                break;
+                       is_commit_in_columns = 0;
                        col_commit = graph->commit;
                } else {
                        col_commit = graph->columns[i].commit;
                }
 
                if (col_commit == graph->commit) {
+                       int old_mapping_idx = mapping_idx;
                        seen_this = 1;
                        for (parent = graph->commit->parents;
                             parent;
@@ -278,6 +339,14 @@ static void graph_update_columns(struct git_graph *graph)
                                                              parent->item,
                                                              &mapping_idx);
                        }
+                       /*
+                        * We always need to increment mapping_idx by at
+                        * least 2, even if it has no interesting parents.
+                        * The current commit always takes up at least 2
+                        * spaces.
+                        */
+                       if (mapping_idx == old_mapping_idx)
+                               mapping_idx += 2;
                } else {
                        graph_insert_into_new_columns(graph, col_commit,
                                                      &mapping_idx);
@@ -290,6 +359,11 @@ static void graph_update_columns(struct git_graph *graph)
        while (graph->mapping_size > 1 &&
               graph->mapping[graph->mapping_size - 1] < 0)
                graph->mapping_size--;
+
+       /*
+        * Compute graph->width for this commit
+        */
+       graph_update_width(graph, is_commit_in_columns);
 }
 
 void graph_update(struct git_graph *graph, struct commit *commit)
@@ -302,11 +376,13 @@ void graph_update(struct git_graph *graph, struct commit *commit)
        graph->commit = commit;
 
        /*
-        * Count how many parents this commit has
+        * Count how many interesting parents this commit has
         */
        graph->num_parents = 0;
-       for (parent = commit->parents; parent; parent = parent->next)
-               graph->num_parents++;
+       for (parent = commit->parents; parent; parent = parent->next) {
+               if (graph_is_interesting(parent->item))
+                       graph->num_parents++;
+       }
 
        /*
         * Call graph_update_columns() to update
@@ -368,22 +444,12 @@ static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
         *
         * This way, fields printed to the right of the graph will remain
         * aligned for the entire commit.
-        *
-        * This computation results in 3 extra space to the right in most
-        * cases, but only 1 extra space if the commit doesn't have any
-        * children that have already been displayed in the graph (i.e.,
-        * if the current commit isn't in graph->columns).
         */
-       size_t extra;
-       size_t final_width = graph->num_columns + graph->num_parents;
-       if (graph->num_parents < 1)
-               final_width++;
-       final_width *= 2;
-
-       if (sb->len >= final_width)
+       int extra;
+       if (sb->len >= graph->width)
                return;
 
-       extra = final_width - sb->len;
+       extra = graph->width - sb->len;
        strbuf_addf(sb, "%*s", (int) extra, "");
 }
 
@@ -502,7 +568,13 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 
                if (col_commit == graph->commit) {
                        seen_this = 1;
-                       if (graph->num_parents > 1)
+
+                       if (graph->revs && graph->revs->left_right) {
+                               if (graph->commit->object.flags & SYMMETRIC_LEFT)
+                                       strbuf_addch(sb, '<');
+                               else
+                                       strbuf_addch(sb, '>');
+                       } else if (graph->num_parents > 1)
                                strbuf_addch(sb, 'M');
                        else
                                strbuf_addch(sb, '*');