Skip to content

Commit 631bc59

Browse files
pabloosabaterrgitster
authored andcommitted
graph: add --graph-lane-limit option
Repositories that have many active branches at the same time produce wide graphs. A lane consists of two columns, the edge and the space padding, each branch takes a lane in the graph and there is no way to limit how many can be shown. Add '--graph-lane-limit=<n>' revision option that caps the number of visible lanes to n. This option requires '--graph', without it a limit to the graph has no meaning, in this case error out. Zero and negative values are valid inputs but silently ignored treating them as "no limit", the same as not using the option. This follows what '--max-parents' does with negative values. When the limit is set, lanes over the limit are not drawn. Teach each graph state to stop rendering at the lane limit and print a "~" truncation mark, so users know that there are hidden lanes. The "~" was chosen because it was not used elsewhere in the graph and it is discrete. On the commit line, if the commit lives on a visible lane, show the normal commit mark and truncate after it, if the commit lives on the first hidden lane show the "*" instead of the truncation mark so it is known that this commit sits on the first hidden lane. Commits on deeper lanes don't leave a mark. For merges, the post-merge lane is only needed when the commit or the first parent lives on a visible lane (to draw the connection between them), when both are on hidden lanes, post-merge carries no useful information, skip it and go to collapsing or padding state. Also fix a pre-existing indentation issue. Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 6e8d538 commit 631bc59

3 files changed

Lines changed: 134 additions & 23 deletions

File tree

graph.c

Lines changed: 127 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,15 @@ struct git_graph {
317317
struct strbuf prefix_buf;
318318
};
319319

320+
static int graph_needs_truncation(struct git_graph *graph, int lane)
321+
{
322+
int max = graph->revs->graph_max_lanes;
323+
/*
324+
* Ignore values <= 0, meaning no limit.
325+
*/
326+
return max > 0 && lane >= max;
327+
}
328+
320329
static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
321330
{
322331
struct git_graph *graph = data;
@@ -696,6 +705,18 @@ static void graph_update_columns(struct git_graph *graph)
696705
}
697706
}
698707

708+
/*
709+
* If graph_max_lanes is set, cap the padding from the branches
710+
*/
711+
if (graph->revs->graph_max_lanes > 0) {
712+
/*
713+
* width of "| " per lanes plus truncation mark "~ ".
714+
*/
715+
int max_columns_width = graph->revs->graph_max_lanes * 2 + 2;
716+
if (graph->width > max_columns_width)
717+
graph->width = max_columns_width;
718+
}
719+
699720
/*
700721
* Shrink mapping_size to be the minimum necessary
701722
*/
@@ -846,6 +867,10 @@ static void graph_output_padding_line(struct git_graph *graph,
846867
* Output a padding row, that leaves all branch lines unchanged
847868
*/
848869
for (i = 0; i < graph->num_new_columns; i++) {
870+
if (graph_needs_truncation(graph, i)) {
871+
graph_line_addstr(line, "~ ");
872+
break;
873+
}
849874
graph_line_write_column(line, &graph->new_columns[i], '|');
850875
graph_line_addch(line, ' ');
851876
}
@@ -903,6 +928,9 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
903928
seen_this = 1;
904929
graph_line_write_column(line, col, '|');
905930
graph_line_addchars(line, ' ', graph->expansion_row);
931+
} else if (seen_this && graph_needs_truncation(graph, i)) {
932+
graph_line_addstr(line, "~ ");
933+
break;
906934
} else if (seen_this && (graph->expansion_row == 0)) {
907935
/*
908936
* This is the first line of the pre-commit output.
@@ -994,6 +1022,12 @@ static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line
9941022
col = &graph->new_columns[j];
9951023

9961024
graph_line_write_column(line, col, '-');
1025+
1026+
if (graph_needs_truncation(graph, j / 2 + i)) {
1027+
graph_line_addstr(line, "~ ");
1028+
break;
1029+
}
1030+
9971031
graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
9981032
}
9991033

@@ -1028,8 +1062,17 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10281062
seen_this = 1;
10291063
graph_output_commit_char(graph, line);
10301064

1065+
if (graph_needs_truncation(graph, i)) {
1066+
graph_line_addch(line, ' ');
1067+
break;
1068+
}
1069+
10311070
if (graph->num_parents > 2)
10321071
graph_draw_octopus_merge(graph, line);
1072+
} else if (graph_needs_truncation(graph, i)) {
1073+
graph_line_addstr(line, "~ ");
1074+
seen_this = 1;
1075+
break;
10331076
} else if (seen_this && (graph->edges_added > 1)) {
10341077
graph_line_write_column(line, col, '\\');
10351078
} else if (seen_this && (graph->edges_added == 1)) {
@@ -1065,10 +1108,32 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10651108

10661109
/*
10671110
* Update graph->state
1111+
*
1112+
* If the commit is a merge and the first parent is in a visible lane,
1113+
* then the GRAPH_POST_MERGE is needed to draw the merge lane.
1114+
*
1115+
* If the commit is over the truncation limit, but the first parent is on
1116+
* a visible lane, then we still need the merge lane but truncated.
1117+
*
1118+
* If both commit and first parent are over the truncation limit, then
1119+
* there's no need to draw the merge lane because it would work as a
1120+
* padding lane.
10681121
*/
1069-
if (graph->num_parents > 1)
1070-
graph_update_state(graph, GRAPH_POST_MERGE);
1071-
else if (graph_is_mapping_correct(graph))
1122+
if (graph->num_parents > 1) {
1123+
if (!graph_needs_truncation(graph, graph->commit_index)) {
1124+
graph_update_state(graph, GRAPH_POST_MERGE);
1125+
} else {
1126+
struct commit_list *first_parent = first_interesting_parent(graph);
1127+
int first_parent_col = graph_find_new_column_by_commit(graph, first_parent->item);
1128+
1129+
if (!graph_needs_truncation(graph, first_parent_col))
1130+
graph_update_state(graph, GRAPH_POST_MERGE);
1131+
else if (graph_is_mapping_correct(graph))
1132+
graph_update_state(graph, GRAPH_PADDING);
1133+
else
1134+
graph_update_state(graph, GRAPH_COLLAPSING);
1135+
}
1136+
} else if (graph_is_mapping_correct(graph))
10721137
graph_update_state(graph, GRAPH_PADDING);
10731138
else
10741139
graph_update_state(graph, GRAPH_COLLAPSING);
@@ -1109,6 +1174,7 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11091174
int par_column;
11101175
int idx = graph->merge_layout;
11111176
char c;
1177+
int truncated = 0;
11121178
seen_this = 1;
11131179

11141180
for (j = 0; j < graph->num_parents; j++) {
@@ -1117,23 +1183,46 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11171183

11181184
c = merge_chars[idx];
11191185
graph_line_write_column(line, &graph->new_columns[par_column], c);
1186+
if (graph_needs_truncation(graph, j / 2 + i) &&
1187+
j / 2 + i <= graph->num_columns) {
1188+
if ((j + i * 2) % 2 != 0)
1189+
graph_line_addch(line, ' ');
1190+
graph_line_addstr(line, "~ ");
1191+
truncated = 1;
1192+
break;
1193+
}
1194+
11201195
if (idx == 2) {
1121-
if (graph->edges_added > 0 || j < graph->num_parents - 1)
1196+
if (graph_needs_truncation(graph, (j + 1) / 2 + i) &&
1197+
j < graph->num_parents - 1) {
1198+
graph_line_addstr(line, "~ ");
1199+
truncated = 1;
1200+
break;
1201+
} else if (graph->edges_added > 0 || j < graph->num_parents - 1)
11221202
graph_line_addch(line, ' ');
11231203
} else {
11241204
idx++;
11251205
}
11261206
parents = next_interesting_parent(graph, parents);
11271207
}
1208+
if (truncated)
1209+
break;
11281210
if (graph->edges_added == 0)
11291211
graph_line_addch(line, ' ');
1130-
1212+
} else if (graph_needs_truncation(graph, i)) {
1213+
graph_line_addstr(line, "~ ");
1214+
break;
11311215
} else if (seen_this) {
11321216
if (graph->edges_added > 0)
11331217
graph_line_write_column(line, col, '\\');
11341218
else
11351219
graph_line_write_column(line, col, '|');
1136-
graph_line_addch(line, ' ');
1220+
/*
1221+
* If it's between two lanes and next would be truncated,
1222+
* don't add space padding.
1223+
*/
1224+
if (!graph_needs_truncation(graph, i + 1))
1225+
graph_line_addch(line, ' ');
11371226
} else {
11381227
graph_line_write_column(line, col, '|');
11391228
if (graph->merge_layout != 0 || i != graph->commit_index - 1) {
@@ -1164,6 +1253,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
11641253
short used_horizontal = 0;
11651254
int horizontal_edge = -1;
11661255
int horizontal_edge_target = -1;
1256+
int truncated = 0;
11671257

11681258
/*
11691259
* Swap the mapping and old_mapping arrays
@@ -1279,26 +1369,35 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
12791369
*/
12801370
for (i = 0; i < graph->mapping_size; i++) {
12811371
int target = graph->mapping[i];
1282-
if (target < 0)
1283-
graph_line_addch(line, ' ');
1284-
else if (target * 2 == i)
1285-
graph_line_write_column(line, &graph->new_columns[target], '|');
1286-
else if (target == horizontal_edge_target &&
1287-
i != horizontal_edge - 1) {
1288-
/*
1289-
* Set the mappings for all but the
1290-
* first segment to -1 so that they
1291-
* won't continue into the next line.
1292-
*/
1293-
if (i != (target * 2)+3)
1294-
graph->mapping[i] = -1;
1295-
used_horizontal = 1;
1296-
graph_line_write_column(line, &graph->new_columns[target], '_');
1372+
1373+
if (!truncated && graph_needs_truncation(graph, i / 2)) {
1374+
graph_line_addstr(line, "~ ");
1375+
truncated = 1;
1376+
}
1377+
1378+
if (target < 0) {
1379+
if (!truncated)
1380+
graph_line_addch(line, ' ');
1381+
} else if (target * 2 == i) {
1382+
if (!truncated)
1383+
graph_line_write_column(line, &graph->new_columns[target], '|');
1384+
} else if (target == horizontal_edge_target &&
1385+
i != horizontal_edge - 1) {
1386+
/*
1387+
* Set the mappings for all but the
1388+
* first segment to -1 so that they
1389+
* won't continue into the next line.
1390+
*/
1391+
if (i != (target * 2)+3)
1392+
graph->mapping[i] = -1;
1393+
used_horizontal = 1;
1394+
if (!truncated)
1395+
graph_line_write_column(line, &graph->new_columns[target], '_');
12971396
} else {
12981397
if (used_horizontal && i < horizontal_edge)
12991398
graph->mapping[i] = -1;
1300-
graph_line_write_column(line, &graph->new_columns[target], '/');
1301-
1399+
if (!truncated)
1400+
graph_line_write_column(line, &graph->new_columns[target], '/');
13021401
}
13031402
}
13041403

@@ -1372,6 +1471,11 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
13721471
for (i = 0; i < graph->num_columns; i++) {
13731472
struct column *col = &graph->columns[i];
13741473

1474+
if (graph_needs_truncation(graph, i)) {
1475+
graph_line_addch(&line, '~');
1476+
break;
1477+
}
1478+
13751479
graph_line_write_column(&line, col, '|');
13761480

13771481
if (col->commit == graph->commit && graph->num_parents > 2) {

revision.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,6 +2605,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
26052605
} else if (!strcmp(arg, "--no-graph")) {
26062606
graph_clear(revs->graph);
26072607
revs->graph = NULL;
2608+
} else if (skip_prefix(arg, "--graph-lane-limit=", &optarg)) {
2609+
revs->graph_max_lanes = parse_count(optarg);
26082610
} else if (!strcmp(arg, "--encode-email-headers")) {
26092611
revs->encode_email_headers = 1;
26102612
} else if (!strcmp(arg, "--no-encode-email-headers")) {
@@ -3172,6 +3174,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
31723174

31733175
if (revs->no_walk && revs->graph)
31743176
die(_("options '%s' and '%s' cannot be used together"), "--no-walk", "--graph");
3177+
3178+
if (revs->graph_max_lanes > 0 && !revs->graph)
3179+
die(_("the option '%s' requires '%s'"), "--graph-lane-limit", "--graph");
3180+
31753181
if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
31763182
die(_("the option '%s' requires '%s'"), "--grep-reflog", "--walk-reflogs");
31773183

revision.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ struct rev_info {
304304

305305
/* Display history graph */
306306
struct git_graph *graph;
307+
int graph_max_lanes;
307308

308309
/* special limits */
309310
int skip_count;

0 commit comments

Comments
 (0)