@@ -317,6 +317,15 @@ struct git_graph {
317317 struct strbuf prefix_buf ;
318318};
319319
320+ static inline 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+
320329static const char * diff_output_prefix_callback (struct diff_options * opt , void * data )
321330{
322331 struct git_graph * graph = data ;
@@ -696,6 +705,19 @@ static void graph_update_columns(struct git_graph *graph)
696705 }
697706 }
698707
708+ /*
709+ * If graph_max_lanes is set, cap the width
710+ */
711+ if (graph -> revs -> graph_max_lanes > 0 ) {
712+ /*
713+ * width of "| " per lanes plus truncation mark "~ ".
714+ * Allow commits from merges to align to the merged lane.
715+ */
716+ int max_width = graph -> revs -> graph_max_lanes * 2 + 2 ;
717+ if (graph -> width > max_width )
718+ graph -> width = max_width ;
719+ }
720+
699721 /*
700722 * Shrink mapping_size to be the minimum necessary
701723 */
@@ -846,6 +868,10 @@ static void graph_output_padding_line(struct git_graph *graph,
846868 * Output a padding row, that leaves all branch lines unchanged
847869 */
848870 for (i = 0 ; i < graph -> num_new_columns ; i ++ ) {
871+ if (graph_needs_truncation (graph , i )) {
872+ graph_line_addstr (line , "~ " );
873+ break ;
874+ }
849875 graph_line_write_column (line , & graph -> new_columns [i ], '|' );
850876 graph_line_addch (line , ' ' );
851877 }
@@ -903,6 +929,9 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
903929 seen_this = 1 ;
904930 graph_line_write_column (line , col , '|' );
905931 graph_line_addchars (line , ' ' , graph -> expansion_row );
932+ } else if (seen_this && graph_needs_truncation (graph , i )) {
933+ graph_line_addstr (line , "~ " );
934+ break ;
906935 } else if (seen_this && (graph -> expansion_row == 0 )) {
907936 /*
908937 * This is the first line of the pre-commit output.
@@ -994,6 +1023,16 @@ static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line
9941023 col = & graph -> new_columns [j ];
9951024
9961025 graph_line_write_column (line , col , '-' );
1026+
1027+ /*
1028+ * Commit is at commit_index, each iteration move one lane to
1029+ * the right from the commit.
1030+ */
1031+ if (graph_needs_truncation (graph , graph -> commit_index + 1 + i )) {
1032+ graph_line_addstr (line , "~ " );
1033+ break ;
1034+ }
1035+
9971036 graph_line_write_column (line , col , (i == dashed_parents - 1 ) ? '.' : '-' );
9981037 }
9991038
@@ -1028,8 +1067,17 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10281067 seen_this = 1 ;
10291068 graph_output_commit_char (graph , line );
10301069
1070+ if (graph_needs_truncation (graph , i )) {
1071+ graph_line_addch (line , ' ' );
1072+ break ;
1073+ }
1074+
10311075 if (graph -> num_parents > 2 )
10321076 graph_draw_octopus_merge (graph , line );
1077+ } else if (graph_needs_truncation (graph , i )) {
1078+ graph_line_addstr (line , "~ " );
1079+ seen_this = 1 ;
1080+ break ;
10331081 } else if (seen_this && (graph -> edges_added > 1 )) {
10341082 graph_line_write_column (line , col , '\\' );
10351083 } else if (seen_this && (graph -> edges_added == 1 )) {
@@ -1065,13 +1113,46 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10651113
10661114 /*
10671115 * Update graph->state
1116+ *
1117+ * If the commit is a merge and the first parent is in a visible lane,
1118+ * then the GRAPH_POST_MERGE is needed to draw the merge lane.
1119+ *
1120+ * If the commit is over the truncation limit, but the first parent is on
1121+ * a visible lane, then we still need the merge lane but truncated.
1122+ *
1123+ * If both commit and first parent are over the truncation limit, then
1124+ * there's no need to draw the merge lane because it would work as a
1125+ * padding lane.
10681126 */
1069- if (graph -> num_parents > 1 )
1070- graph_update_state (graph , GRAPH_POST_MERGE );
1071- else if (graph_is_mapping_correct (graph ))
1127+ if (graph -> num_parents > 1 ) {
1128+ if (!graph_needs_truncation (graph , graph -> commit_index )) {
1129+ graph_update_state (graph , GRAPH_POST_MERGE );
1130+ } else {
1131+ struct commit_list * p = first_interesting_parent (graph );
1132+ int lane ;
1133+
1134+ /*
1135+ * graph->num_parents are found using first_interesting_parent
1136+ * and next_interesting_parent so it can't be a scenario
1137+ * where num_parents > 1 and there are no interesting parents
1138+ */
1139+ if (!p )
1140+ BUG ("num_parents > 1 but no interesting parent" );
1141+
1142+ lane = graph_find_new_column_by_commit (graph , p -> item );
1143+
1144+ if (!graph_needs_truncation (graph , lane ))
1145+ graph_update_state (graph , GRAPH_POST_MERGE );
1146+ else if (graph_is_mapping_correct (graph ))
1147+ graph_update_state (graph , GRAPH_PADDING );
1148+ else
1149+ graph_update_state (graph , GRAPH_COLLAPSING );
1150+ }
1151+ } else if (graph_is_mapping_correct (graph )) {
10721152 graph_update_state (graph , GRAPH_PADDING );
1073- else
1153+ } else {
10741154 graph_update_state (graph , GRAPH_COLLAPSING );
1155+ }
10751156}
10761157
10771158static const char merge_chars [] = {'/' , '|' , '\\' };
@@ -1109,6 +1190,7 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11091190 int par_column ;
11101191 int idx = graph -> merge_layout ;
11111192 char c ;
1193+ int truncated = 0 ;
11121194 seen_this = 1 ;
11131195
11141196 for (j = 0 ; j < graph -> num_parents ; j ++ ) {
@@ -1117,23 +1199,56 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11171199
11181200 c = merge_chars [idx ];
11191201 graph_line_write_column (line , & graph -> new_columns [par_column ], c );
1202+
1203+ /*
1204+ * j counts parents, it needs to be halved to be
1205+ * comparable with i. Don't truncate if there are
1206+ * no more lanes to print (end of the lane)
1207+ */
1208+ if (graph_needs_truncation (graph , j / 2 + i ) &&
1209+ j / 2 + i <= graph -> num_columns ) {
1210+ if ((j + i * 2 ) % 2 != 0 )
1211+ graph_line_addch (line , ' ' );
1212+ graph_line_addstr (line , "~ " );
1213+ truncated = 1 ;
1214+ break ;
1215+ }
1216+
11201217 if (idx == 2 ) {
1121- if (graph -> edges_added > 0 || j < graph -> num_parents - 1 )
1218+ /*
1219+ * Check if the next lane needs truncation
1220+ * to avoid having the padding doubled
1221+ */
1222+ if (graph_needs_truncation (graph , (j + 1 ) / 2 + i ) &&
1223+ j < graph -> num_parents - 1 ) {
1224+ graph_line_addstr (line , "~ " );
1225+ truncated = 1 ;
1226+ break ;
1227+ } else if (graph -> edges_added > 0 || j < graph -> num_parents - 1 )
11221228 graph_line_addch (line , ' ' );
11231229 } else {
11241230 idx ++ ;
11251231 }
11261232 parents = next_interesting_parent (graph , parents );
11271233 }
1234+ if (truncated )
1235+ break ;
11281236 if (graph -> edges_added == 0 )
11291237 graph_line_addch (line , ' ' );
1130-
1238+ } else if (graph_needs_truncation (graph , i )) {
1239+ graph_line_addstr (line , "~ " );
1240+ break ;
11311241 } else if (seen_this ) {
11321242 if (graph -> edges_added > 0 )
11331243 graph_line_write_column (line , col , '\\' );
11341244 else
11351245 graph_line_write_column (line , col , '|' );
1136- graph_line_addch (line , ' ' );
1246+ /*
1247+ * If it's between two lanes and next would be truncated,
1248+ * don't add space padding.
1249+ */
1250+ if (!graph_needs_truncation (graph , i + 1 ))
1251+ graph_line_addch (line , ' ' );
11371252 } else {
11381253 graph_line_write_column (line , col , '|' );
11391254 if (graph -> merge_layout != 0 || i != graph -> commit_index - 1 ) {
@@ -1164,6 +1279,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
11641279 short used_horizontal = 0 ;
11651280 int horizontal_edge = -1 ;
11661281 int horizontal_edge_target = -1 ;
1282+ int truncated = 0 ;
11671283
11681284 /*
11691285 * Swap the mapping and old_mapping arrays
@@ -1279,26 +1395,35 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
12791395 */
12801396 for (i = 0 ; i < graph -> mapping_size ; i ++ ) {
12811397 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 ], '_' );
1398+
1399+ if (!truncated && graph_needs_truncation (graph , i / 2 )) {
1400+ graph_line_addstr (line , "~ " );
1401+ truncated = 1 ;
1402+ }
1403+
1404+ if (target < 0 ) {
1405+ if (!truncated )
1406+ graph_line_addch (line , ' ' );
1407+ } else if (target * 2 == i ) {
1408+ if (!truncated )
1409+ graph_line_write_column (line , & graph -> new_columns [target ], '|' );
1410+ } else if (target == horizontal_edge_target &&
1411+ i != horizontal_edge - 1 ) {
1412+ /*
1413+ * Set the mappings for all but the
1414+ * first segment to -1 so that they
1415+ * won't continue into the next line.
1416+ */
1417+ if (i != (target * 2 )+ 3 )
1418+ graph -> mapping [i ] = -1 ;
1419+ used_horizontal = 1 ;
1420+ if (!truncated )
1421+ graph_line_write_column (line , & graph -> new_columns [target ], '_' );
12971422 } else {
12981423 if (used_horizontal && i < horizontal_edge )
12991424 graph -> mapping [i ] = -1 ;
1300- graph_line_write_column ( line , & graph -> new_columns [ target ], '/' );
1301-
1425+ if (! truncated )
1426+ graph_line_write_column ( line , & graph -> new_columns [ target ], '/' );
13021427 }
13031428 }
13041429
@@ -1372,6 +1497,11 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
13721497 for (i = 0 ; i < graph -> num_columns ; i ++ ) {
13731498 struct column * col = & graph -> columns [i ];
13741499
1500+ if (graph_needs_truncation (graph , i )) {
1501+ graph_line_addstr (& line , "~ " );
1502+ break ;
1503+ }
1504+
13751505 graph_line_write_column (& line , col , '|' );
13761506
13771507 if (col -> commit == graph -> commit && graph -> num_parents > 2 ) {
0 commit comments