@@ -63,7 +63,6 @@ enum graph_state {
GRAPH_SKIP,
GRAPH_PRE_COMMIT,
GRAPH_COMMIT,
- GRAPH_POST_MERGE,
GRAPH_COLLAPSING
};
@@ -153,12 +152,6 @@ struct git_graph {
* This tells us what kind of line graph_next_line() should output.
*/
enum graph_state state;
- /*
- * The output state for the previous line of output.
- * This is primarily used to determine how the first merge line
- * should appear, based on the last line of the previous commit.
- */
- enum graph_state prev_state;
/*
* The index of the column that refers to this commit.
*
@@ -167,13 +160,9 @@ struct git_graph {
*/
int commit_index;
/*
- * The commit_index for the previously displayed commit.
- *
- * This is used to determine how the first line of a merge
- * graph output should appear, based on the last line of the
- * previous commit.
+ * If previous line was a merge commit, then this is its commit index
*/
- int prev_commit_index;
+ int prev_merge_index;
/*
* The maximum number of columns that can be stored in the columns
* and new_columns arrays. This is also half the number of entries
@@ -282,9 +271,7 @@ struct git_graph *graph_init(struct rev_info *opt)
graph->num_parents = 0;
graph->expansion_row = 0;
graph->state = GRAPH_PADDING;
- graph->prev_state = GRAPH_PADDING;
graph->commit_index = 0;
- graph->prev_commit_index = 0;
graph->num_columns = 0;
graph->num_new_columns = 0;
graph->mapping_size = 0;
@@ -317,7 +304,6 @@ struct git_graph *graph_init(struct rev_info *opt)
static void graph_update_state(struct git_graph *graph, enum graph_state s)
{
- graph->prev_state = graph->state;
graph->state = s;
}
@@ -602,6 +588,13 @@ static void graph_update_columns(struct git_graph *graph)
graph_update_width(graph, is_commit_in_columns);
}
+static int need_pre_commit(struct git_graph *graph)
+{
+ return (graph->num_parents == 2 && graph->prev_merge_index != 0xffff)
+ || (graph->num_parents >= 3 &&
+ graph->commit_index < (graph->num_columns - 1));
+}
+
void graph_update(struct git_graph *graph, struct commit *commit)
{
struct commit_list *parent;
@@ -622,13 +615,6 @@ void graph_update(struct git_graph *graph, struct commit *commit)
graph->num_parents++;
}
- /*
- * Store the old commit_index in prev_commit_index.
- * graph_update_columns() will update graph->commit_index for this
- * commit.
- */
- graph->prev_commit_index = graph->commit_index;
-
/*
* Call graph_update_columns() to update
* columns, new_columns, and mapping.
@@ -639,9 +625,6 @@ void graph_update(struct git_graph *graph, struct commit *commit)
/*
* Update graph->state.
- * Note that we don't call graph_update_state() here, since
- * we don't want to update graph->prev_state. No line for
- * graph->state was ever printed.
*
* If the previous commit didn't get to the GRAPH_PADDING state,
* it never finished its output. Goto GRAPH_SKIP, to print out
@@ -657,8 +640,7 @@ void graph_update(struct git_graph *graph, struct commit *commit)
*/
if (graph->state != GRAPH_PADDING)
graph->state = GRAPH_SKIP;
- else if (graph->num_parents >= 3 &&
- graph->commit_index < (graph->num_columns - 1))
+ else if (need_pre_commit(graph))
graph->state = GRAPH_PRE_COMMIT;
else
graph->state = GRAPH_COMMIT;
@@ -742,8 +724,7 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
strbuf_addstr(sb, "...");
graph_pad_horizontally(graph, sb, 3);
- if (graph->num_parents >= 3 &&
- graph->commit_index < (graph->num_columns - 1))
+ if (need_pre_commit(graph))
graph_update_state(graph, GRAPH_PRE_COMMIT);
else
graph_update_state(graph, GRAPH_COMMIT);
@@ -763,14 +744,16 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
*
* We need 2 extra rows for every parent over 2.
*/
- assert(graph->num_parents >= 3);
+ assert(graph->num_parents >= 2);
num_expansion_rows = (graph->num_parents - 2) * 2;
+ if (num_expansion_rows == 0)
+ graph->expansion_row = -1;
/*
* graph->expansion_row tracks the current expansion row we are on.
* It should be in the range [0, num_expansion_rows - 1]
*/
- assert(0 <= graph->expansion_row &&
+ assert(-1 <= graph->expansion_row &&
graph->expansion_row < num_expansion_rows);
/*
@@ -783,25 +766,9 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
if (col->commit == graph->commit) {
seen_this = 1;
strbuf_write_column(sb, col, '|');
- strbuf_addchars(sb, ' ', graph->expansion_row);
- chars_written += 1 + graph->expansion_row;
- } else if (seen_this && (graph->expansion_row == 0)) {
- /*
- * This is the first line of the pre-commit output.
- * If the previous commit was a merge commit and
- * ended in the GRAPH_POST_MERGE state, all branch
- * lines after graph->prev_commit_index were
- * printed as "\" on the previous line. Continue
- * to print them as "\" on this line. Otherwise,
- * print the branch lines as "|".
- */
- if (graph->prev_state == GRAPH_POST_MERGE &&
- graph->prev_commit_index < i)
- strbuf_write_column(sb, col, '\\');
- else
- strbuf_write_column(sb, col, '|');
- chars_written++;
- } else if (seen_this && (graph->expansion_row > 0)) {
+ strbuf_addchars(sb, ' ', graph->expansion_row + 1);
+ chars_written += 2 + graph->expansion_row;
+ } else if (seen_this) {
strbuf_write_column(sb, col, '\\');
chars_written++;
} else {
@@ -887,8 +854,7 @@ static int graph_draw_octopus_merge(struct git_graph *graph,
int i;
for (i = 0; i < dashful_parents; i++) {
strbuf_write_column(sb, &graph->new_columns[i+first_col], '-');
- strbuf_write_column(sb, &graph->new_columns[i+first_col],
- i == dashful_parents-1 ? '.' : '-');
+ strbuf_write_column(sb, &graph->new_columns[i+first_col], '-');
}
return 2 * dashful_parents;
}
@@ -896,7 +862,8 @@ static int graph_draw_octopus_merge(struct git_graph *graph,
static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
{
int seen_this = 0;
- int i, chars_written;
+ int i, j, k, chars_written;
+ char draw_ch;
/*
* Output the row containing this commit
@@ -910,6 +877,7 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
for (i = 0; i <= graph->num_columns; i++) {
struct column *col = &graph->columns[i];
struct commit *col_commit;
+ int add_space = 1;
if (i == graph->num_columns) {
if (seen_this)
break;
@@ -923,138 +891,76 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
graph_output_commit_char(graph, sb);
chars_written++;
- if (graph->num_parents > 2)
+ draw_ch = graph->num_parents == 2 ? '_' : 0;
+ if (graph->num_parents > 2) {
chars_written += graph_draw_octopus_merge(graph,
sb);
- } else if (seen_this && (graph->num_parents > 2)) {
- strbuf_write_column(sb, col, '\\');
- chars_written++;
- } else if (seen_this && (graph->num_parents == 2)) {
- /*
- * This is a 2-way merge commit.
- * There is no GRAPH_PRE_COMMIT stage for 2-way
- * merges, so this is the first line of output
- * for this commit. Check to see what the previous
- * line of output was.
- *
- * If it was GRAPH_POST_MERGE, the branch line
- * coming into this commit may have been '\',
- * and not '|' or '/'. If so, output the branch
- * line as '\' on this line, instead of '|'. This
- * makes the output look nicer.
- */
- if (graph->prev_state == GRAPH_POST_MERGE &&
- graph->prev_commit_index < i)
- strbuf_write_column(sb, col, '\\');
- else
- strbuf_write_column(sb, col, '|');
- chars_written++;
- } else {
- strbuf_write_column(sb, col, '|');
- chars_written++;
- }
- strbuf_addch(sb, ' ');
- chars_written++;
- }
-
- graph_pad_horizontally(graph, sb, chars_written);
-
- /*
- * Update graph->state
- */
- if (graph->num_parents > 1)
- graph_update_state(graph, GRAPH_POST_MERGE);
- else if (graph_is_mapping_correct(graph))
- graph_update_state(graph, GRAPH_PADDING);
- else
- graph_update_state(graph, GRAPH_COLLAPSING);
-}
-
-static struct column *find_new_column_by_commit(struct git_graph *graph,
- struct commit *commit)
-{
- int i;
- for (i = 0; i < graph->num_new_columns; i++) {
- if (graph->new_columns[i].commit == commit)
- return &graph->new_columns[i];
- }
- return NULL;
-}
-
-static void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
-{
- int seen_this = 0;
- int i, j, chars_written;
-
- /*
- * Output the post-merge row
- */
- chars_written = 0;
- for (i = 0; i <= graph->num_columns; i++) {
- struct column *col = &graph->columns[i];
- struct commit *col_commit;
- if (i == graph->num_columns) {
- if (seen_this)
- break;
- col_commit = graph->commit;
- } else {
- col_commit = col->commit;
- }
-
- if (col_commit == graph->commit) {
- /*
- * Since the current commit is a merge find
- * the columns for the parent commits in
- * new_columns and use those to format the
- * edges.
- */
- struct commit_list *parents = NULL;
- struct column *par_column;
- seen_this = 1;
- parents = first_interesting_parent(graph);
- assert(parents);
- par_column = find_new_column_by_commit(graph, parents->item);
- assert(par_column);
-
- strbuf_write_column(sb, par_column, '|');
- chars_written++;
- for (j = 0; j < graph->num_parents - 1; j++) {
- parents = next_interesting_parent(graph, parents);
- assert(parents);
- par_column = find_new_column_by_commit(graph, parents->item);
- assert(par_column);
- strbuf_write_column(sb, par_column, '\\');
- strbuf_addch(sb, ' ');
+ draw_ch = '.';
}
- chars_written += j * 2;
- } else if (seen_this) {
- strbuf_write_column(sb, col, '\\');
- strbuf_addch(sb, ' ');
- chars_written += 2;
+ if (graph->num_parents > 1) {
+ j = i+1, k = i+2;
+ if (i > 0 && graph->mapping[j*2] == i-1)
+ col = &graph->new_columns[i-1];
+ else
+ col = &graph->new_columns[i+graph->num_parents-1];
+ /*
+ optimize collapse after merge case:
+ i j k
+ | * <hash> some commit
+ *. \ <hash> merge branch with another commit
+ | |/ <--- collapse line
+ | * <hash> another commit
+
+ this happens if the mapping of the second next
+ column merges with the next column
+ remember this by marking seen_this = 2
+ adjust mapping array because we fixed it here
+
+ output:
+ | * <hash> some commit
+ *.| <hash> merge branch with another commit
+ | * <hash> another commit
+
+ this saves a line, plus the merge commit is
+ not indented anymore relative to what's merged
+ */
+ if (graph->mapping[j*2] == j && graph->mapping[k*2] == j) {
+ for (; k*2 < graph->mapping_size; k++)
+ graph->mapping[k*2] = k;
+ add_space = 0;
+ seen_this = 2; /* draw a '|' */
+ }
+ }
+ } else if (seen_this == 1 && (graph->num_parents >= 2)) {
+ draw_ch = '\\';
} else {
- strbuf_write_column(sb, col, '|');
- strbuf_addch(sb, ' ');
- chars_written += 2;
+ draw_ch = '|';
}
+ if (draw_ch)
+ strbuf_write_column(sb, col, draw_ch);
+ if (add_space)
+ strbuf_addch(sb, ' ');
+ chars_written += 1 + add_space;
}
- graph_pad_horizontally(graph, sb, chars_written);
-
/*
* Update graph->state
*/
- if (graph_is_mapping_correct(graph))
+ graph->prev_merge_index = 0xffff;
+ if (graph_is_mapping_correct(graph)) {
graph_update_state(graph, GRAPH_PADDING);
- else
+ if (graph->num_parents > 1)
+ graph->prev_merge_index = graph->commit_index;
+ } else
graph_update_state(graph, GRAPH_COLLAPSING);
}
static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
{
- int i;
- short used_horizontal = 0;
+ int i, j;
int horizontal_edge = -1;
int horizontal_edge_target = -1;
+ char draw_ch;
/*
* Clear out the new_mapping array
@@ -1097,16 +1003,15 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* select this one.
*/
if (horizontal_edge == -1) {
- int j;
horizontal_edge = i;
horizontal_edge_target = target;
/*
* The variable target is the index of the graph
- * column, and therefore target*2+3 is the
+ * column, and therefore target*2+1 is the
* actual screen column of the first horizontal
* line.
*/
- for (j = (target * 2)+3; j < (i - 2); j += 2)
+ for (j = (target * 2)+1; j < i; j += 2)
graph->new_mapping[j] = target;
}
} else if (graph->new_mapping[i - 1] == target) {
@@ -1158,27 +1063,19 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
*/
for (i = 0; i < graph->mapping_size; i++) {
int target = graph->new_mapping[i];
- if (target < 0)
+ if (target < 0) {
strbuf_addch(sb, ' ');
- else if (target * 2 == i)
- strbuf_write_column(sb, &graph->new_columns[target], '|');
- else if (target == horizontal_edge_target &&
- i != horizontal_edge - 1) {
- /*
- * Set the mappings for all but the
- * first segment to -1 so that they
- * won't continue into the next line.
- */
- if (i != (target * 2)+3)
- graph->new_mapping[i] = -1;
- used_horizontal = 1;
- strbuf_write_column(sb, &graph->new_columns[target], '_');
+ continue;
+ }
+ if (target * 2 == i) {
+ draw_ch = '|';
} else {
- if (used_horizontal && i < horizontal_edge)
+ if (i < horizontal_edge)
graph->new_mapping[i] = -1;
- strbuf_write_column(sb, &graph->new_columns[target], '/');
-
+ draw_ch = target == horizontal_edge_target &&
+ i != horizontal_edge-1 ? '_' : '/';
}
+ strbuf_write_column(sb, &graph->new_columns[target], draw_ch);
}
graph_pad_horizontally(graph, sb, graph->mapping_size);
@@ -1212,9 +1109,6 @@ int graph_next_line(struct git_graph *graph, struct strbuf *sb)
case GRAPH_COMMIT:
graph_output_commit_line(graph, sb);
return 1;
- case GRAPH_POST_MERGE:
- graph_output_post_merge_line(graph, sb);
- return 0;
case GRAPH_COLLAPSING:
graph_output_collapsing_line(graph, sb);
return 0;
@@ -1258,11 +1152,6 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
}
graph_pad_horizontally(graph, sb, chars_written);
-
- /*
- * Update graph->prev_state since we have output a padding line
- */
- graph->prev_state = GRAPH_PADDING;
}
int graph_is_commit_finished(struct git_graph const *graph)
Before this commit, graphs with merges have an empty line after a merge commit to make room for a new branch. But this causes the child commits (commits merged with the merge commit) to be separated from the merge commit. Especially with the --tree option this is confusing, as there is no empty line after a series of child commits anymore (because it is a tree after all). Therefore this change modifies the merge point to not need an extra line (the POST_MERGE state is removed), using an underscore to branch out instead of a '\'. It also optimizes the case where a branch point meets a merge commit. Signed-off-by: Micha Nelissen <nelissen.micha@gmail.com> --- graph.c | 281 +++++++++++++++++--------------------------------------- 1 file changed, 85 insertions(+), 196 deletions(-)