graph.con commit Add history graph API (c12172d)
   1#include "cache.h"
   2#include "commit.h"
   3#include "graph.h"
   4#include "diff.h"
   5#include "revision.h"
   6
   7/*
   8 * TODO:
   9 * - Add colors to the graph.
  10 *   Pick a color for each column, and print all characters
  11 *   in that column with the specified color.
  12 *
  13 * - Limit the number of columns, similar to the way gitk does.
  14 *   If we reach more than a specified number of columns, omit
  15 *   sections of some columns.
  16 *
  17 * - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states
  18 *   could be made more compact by printing horizontal lines, instead of
  19 *   long diagonal lines.  For example, during collapsing, something like
  20 *   this:          instead of this:
  21 *   | | | | |      | | | | |
  22 *   | |_|_|/       | | | |/
  23 *   |/| | |        | | |/|
  24 *   | | | |        | |/| |
  25 *                  |/| | |
  26 *                  | | | |
  27 *
  28 *   If there are several parallel diagonal lines, they will need to be
  29 *   replaced with horizontal lines on subsequent rows.
  30 */
  31
  32struct column {
  33        /*
  34         * The parent commit of this column.
  35         */
  36        struct commit *commit;
  37        /*
  38         * XXX: Once we add support for colors, struct column could also
  39         * contain the color of its branch line.
  40         */
  41};
  42
  43enum graph_state {
  44        GRAPH_PADDING,
  45        GRAPH_SKIP,
  46        GRAPH_PRE_COMMIT,
  47        GRAPH_COMMIT,
  48        GRAPH_POST_MERGE,
  49        GRAPH_COLLAPSING
  50};
  51
  52struct git_graph {
  53        /*
  54         * The commit currently being processed
  55         */
  56        struct commit *commit;
  57        /*
  58         * The number of parents this commit has.
  59         * (Stored so we don't have to walk over them each time we need
  60         * this number)
  61         */
  62        int num_parents;
  63        /*
  64         * The next expansion row to print
  65         * when state is GRAPH_PRE_COMMIT
  66         */
  67        int expansion_row;
  68        /*
  69         * The current output state.
  70         * This tells us what kind of line graph_next_line() should output.
  71         */
  72        enum graph_state state;
  73        /*
  74         * The maximum number of columns that can be stored in the columns
  75         * and new_columns arrays.  This is also half the number of entries
  76         * that can be stored in the mapping and new_mapping arrays.
  77         */
  78        int column_capacity;
  79        /*
  80         * The number of columns (also called "branch lines" in some places)
  81         */
  82        int num_columns;
  83        /*
  84         * The number of columns in the new_columns array
  85         */
  86        int num_new_columns;
  87        /*
  88         * The number of entries in the mapping array
  89         */
  90        int mapping_size;
  91        /*
  92         * The column state before we output the current commit.
  93         */
  94        struct column *columns;
  95        /*
  96         * The new column state after we output the current commit.
  97         * Only valid when state is GRAPH_COLLAPSING.
  98         */
  99        struct column *new_columns;
 100        /*
 101         * An array that tracks the current state of each
 102         * character in the output line during state GRAPH_COLLAPSING.
 103         * Each entry is -1 if this character is empty, or a non-negative
 104         * integer if the character contains a branch line.  The value of
 105         * the integer indicates the target position for this branch line.
 106         * (I.e., this array maps the current column positions to their
 107         * desired positions.)
 108         *
 109         * The maximum capacity of this array is always
 110         * sizeof(int) * 2 * column_capacity.
 111         */
 112        int *mapping;
 113        /*
 114         * A temporary array for computing the next mapping state
 115         * while we are outputting a mapping line.  This is stored as part
 116         * of the git_graph simply so we don't have to allocate a new
 117         * temporary array each time we have to output a collapsing line.
 118         */
 119        int *new_mapping;
 120};
 121
 122struct git_graph *graph_init(void)
 123{
 124        struct git_graph *graph = xmalloc(sizeof(struct git_graph));
 125        graph->commit = NULL;
 126        graph->num_parents = 0;
 127        graph->expansion_row = 0;
 128        graph->state = GRAPH_PADDING;
 129        graph->num_columns = 0;
 130        graph->num_new_columns = 0;
 131        graph->mapping_size = 0;
 132
 133        /*
 134         * Allocate a reasonably large default number of columns
 135         * We'll automatically grow columns later if we need more room.
 136         */
 137        graph->column_capacity = 30;
 138        graph->columns = xmalloc(sizeof(struct column) *
 139                                 graph->column_capacity);
 140        graph->new_columns = xmalloc(sizeof(struct column) *
 141                                     graph->column_capacity);
 142        graph->mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
 143        graph->new_mapping = xmalloc(sizeof(int) * 2 * graph->column_capacity);
 144
 145        return graph;
 146}
 147
 148void graph_release(struct git_graph *graph)
 149{
 150        free(graph->columns);
 151        free(graph->new_columns);
 152        free(graph->mapping);
 153        free(graph);
 154}
 155
 156static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
 157{
 158        if (graph->column_capacity >= num_columns)
 159                return;
 160
 161        do {
 162                graph->column_capacity *= 2;
 163        } while (graph->column_capacity < num_columns);
 164
 165        graph->columns = xrealloc(graph->columns,
 166                                  sizeof(struct column) *
 167                                  graph->column_capacity);
 168        graph->new_columns = xrealloc(graph->new_columns,
 169                                      sizeof(struct column) *
 170                                      graph->column_capacity);
 171        graph->mapping = xrealloc(graph->mapping,
 172                                  sizeof(int) * 2 * graph->column_capacity);
 173        graph->new_mapping = xrealloc(graph->new_mapping,
 174                                      sizeof(int) * 2 * graph->column_capacity);
 175}
 176
 177static void graph_insert_into_new_columns(struct git_graph *graph,
 178                                          struct commit *commit,
 179                                          int *mapping_index)
 180{
 181        int i;
 182
 183        /*
 184         * Ignore uinteresting and pruned commits
 185         */
 186        if (commit->object.flags & (UNINTERESTING | TREESAME))
 187                return;
 188
 189        /*
 190         * If the commit is already in the new_columns list, we don't need to
 191         * add it.  Just update the mapping correctly.
 192         */
 193        for (i = 0; i < graph->num_new_columns; i++) {
 194                if (graph->new_columns[i].commit == commit) {
 195                        graph->mapping[*mapping_index] = i;
 196                        *mapping_index += 2;
 197                        return;
 198                }
 199        }
 200
 201        /*
 202         * This commit isn't already in new_columns.  Add it.
 203         */
 204        graph->new_columns[graph->num_new_columns].commit = commit;
 205        graph->mapping[*mapping_index] = graph->num_new_columns;
 206        *mapping_index += 2;
 207        graph->num_new_columns++;
 208}
 209
 210static void graph_update_columns(struct git_graph *graph)
 211{
 212        struct commit_list *parent;
 213        struct column *tmp_columns;
 214        int max_new_columns;
 215        int mapping_idx;
 216        int i, seen_this;
 217
 218        /*
 219         * Swap graph->columns with graph->new_columns
 220         * graph->columns contains the state for the previous commit,
 221         * and new_columns now contains the state for our commit.
 222         *
 223         * We'll re-use the old columns array as storage to compute the new
 224         * columns list for the commit after this one.
 225         */
 226        tmp_columns = graph->columns;
 227        graph->columns = graph->new_columns;
 228        graph->num_columns = graph->num_new_columns;
 229
 230        graph->new_columns = tmp_columns;
 231        graph->num_new_columns = 0;
 232
 233        /*
 234         * Now update new_columns and mapping with the information for the
 235         * commit after this one.
 236         *
 237         * First, make sure we have enough room.  At most, there will
 238         * be graph->num_columns + graph->num_parents columns for the next
 239         * commit.
 240         */
 241        max_new_columns = graph->num_columns + graph->num_parents;
 242        graph_ensure_capacity(graph, max_new_columns);
 243
 244        /*
 245         * Clear out graph->mapping
 246         */
 247        graph->mapping_size = 2 * max_new_columns;
 248        for (i = 0; i < graph->mapping_size; i++)
 249                graph->mapping[i] = -1;
 250
 251        /*
 252         * Populate graph->new_columns and graph->mapping
 253         *
 254         * Some of the parents of this commit may already be in
 255         * graph->columns.  If so, graph->new_columns should only contain a
 256         * single entry for each such commit.  graph->mapping should
 257         * contain information about where each current branch line is
 258         * supposed to end up after the collapsing is performed.
 259         */
 260        seen_this = 0;
 261        mapping_idx = 0;
 262        for (i = 0; i <= graph->num_columns; i++) {
 263                struct commit *col_commit;
 264                if (i == graph->num_columns) {
 265                        if (seen_this)
 266                                break;
 267                        col_commit = graph->commit;
 268                } else {
 269                        col_commit = graph->columns[i].commit;
 270                }
 271
 272                if (col_commit == graph->commit) {
 273                        seen_this = 1;
 274                        for (parent = graph->commit->parents;
 275                             parent;
 276                             parent = parent->next) {
 277                                graph_insert_into_new_columns(graph,
 278                                                              parent->item,
 279                                                              &mapping_idx);
 280                        }
 281                } else {
 282                        graph_insert_into_new_columns(graph, col_commit,
 283                                                      &mapping_idx);
 284                }
 285        }
 286
 287        /*
 288         * Shrink mapping_size to be the minimum necessary
 289         */
 290        while (graph->mapping_size > 1 &&
 291               graph->mapping[graph->mapping_size - 1] < 0)
 292                graph->mapping_size--;
 293}
 294
 295void graph_update(struct git_graph *graph, struct commit *commit)
 296{
 297        struct commit_list *parent;
 298
 299        /*
 300         * Set the new commit
 301         */
 302        graph->commit = commit;
 303
 304        /*
 305         * Count how many parents this commit has
 306         */
 307        graph->num_parents = 0;
 308        for (parent = commit->parents; parent; parent = parent->next)
 309                graph->num_parents++;
 310
 311        /*
 312         * Call graph_update_columns() to update
 313         * columns, new_columns, and mapping.
 314         */
 315        graph_update_columns(graph);
 316
 317        graph->expansion_row = 0;
 318
 319        /*
 320         * Update graph->state.
 321         *
 322         * If the previous commit didn't get to the GRAPH_PADDING state,
 323         * it never finished its output.  Goto GRAPH_SKIP, to print out
 324         * a line to indicate that portion of the graph is missing.
 325         *
 326         * Otherwise, if there are 3 or more parents, we need to print
 327         * extra rows before the commit, to expand the branch lines around
 328         * it and make room for it.
 329         *
 330         * If there are less than 3 parents, we can immediately print the
 331         * commit line.
 332         */
 333        if (graph->state != GRAPH_PADDING)
 334                graph->state = GRAPH_SKIP;
 335        else if (graph->num_parents >= 3)
 336                graph->state = GRAPH_PRE_COMMIT;
 337        else
 338                graph->state = GRAPH_COMMIT;
 339}
 340
 341static int graph_is_mapping_correct(struct git_graph *graph)
 342{
 343        int i;
 344
 345        /*
 346         * The mapping is up to date if each entry is at its target,
 347         * or is 1 greater than its target.
 348         * (If it is 1 greater than the target, '/' will be printed, so it
 349         * will look correct on the next row.)
 350         */
 351        for (i = 0; i < graph->mapping_size; i++) {
 352                int target = graph->mapping[i];
 353                if (target < 0)
 354                        continue;
 355                if (target == (i / 2))
 356                        continue;
 357                return 0;
 358        }
 359
 360        return 1;
 361}
 362
 363static void graph_pad_horizontally(struct git_graph *graph, struct strbuf *sb)
 364{
 365        /*
 366         * Add additional spaces to the end of the strbuf, so that all
 367         * lines for a particular commit have the same width.
 368         *
 369         * This way, fields printed to the right of the graph will remain
 370         * aligned for the entire commit.
 371         *
 372         * This computation results in 3 extra space to the right in most
 373         * cases, but only 1 extra space if the commit doesn't have any
 374         * children that have already been displayed in the graph (i.e.,
 375         * if the current commit isn't in graph->columns).
 376         */
 377        size_t extra;
 378        size_t final_width = graph->num_columns + graph->num_parents;
 379        if (graph->num_parents < 1)
 380                final_width++;
 381        final_width *= 2;
 382
 383        if (sb->len >= final_width)
 384                return;
 385
 386        extra = final_width - sb->len;
 387        strbuf_addf(sb, "%*s", (int) extra, "");
 388}
 389
 390static void graph_output_padding_line(struct git_graph *graph,
 391                                      struct strbuf *sb)
 392{
 393        int i;
 394
 395        /*
 396         * We could conceivable be called with a NULL commit
 397         * if our caller has a bug, and invokes graph_next_line()
 398         * immediately after graph_init(), without first calling
 399         * graph_update().  Return without outputting anything in this
 400         * case.
 401         */
 402        if (!graph->commit)
 403                return;
 404
 405        /*
 406         * Output a padding row, that leaves all branch lines unchanged
 407         */
 408        for (i = 0; i < graph->num_new_columns; i++) {
 409                strbuf_addstr(sb, "| ");
 410        }
 411
 412        graph_pad_horizontally(graph, sb);
 413}
 414
 415static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
 416{
 417        /*
 418         * Output an ellipsis to indicate that a portion
 419         * of the graph is missing.
 420         */
 421        strbuf_addstr(sb, "...");
 422        graph_pad_horizontally(graph, sb);
 423
 424        if (graph->num_parents >= 3)
 425                graph->state = GRAPH_PRE_COMMIT;
 426        else
 427                graph->state = GRAPH_COMMIT;
 428}
 429
 430static void graph_output_pre_commit_line(struct git_graph *graph,
 431                                         struct strbuf *sb)
 432{
 433        int num_expansion_rows;
 434        int i, seen_this;
 435
 436        /*
 437         * This function formats a row that increases the space around a commit
 438         * with multiple parents, to make room for it.  It should only be
 439         * called when there are 3 or more parents.
 440         *
 441         * We need 2 extra rows for every parent over 2.
 442         */
 443        assert(graph->num_parents >= 3);
 444        num_expansion_rows = (graph->num_parents - 2) * 2;
 445
 446        /*
 447         * graph->expansion_row tracks the current expansion row we are on.
 448         * It should be in the range [0, num_expansion_rows - 1]
 449         */
 450        assert(0 <= graph->expansion_row &&
 451               graph->expansion_row < num_expansion_rows);
 452
 453        /*
 454         * Output the row
 455         */
 456        seen_this = 0;
 457        for (i = 0; i < graph->num_columns; i++) {
 458                struct column *col = &graph->columns[i];
 459                if (col->commit == graph->commit) {
 460                        seen_this = 1;
 461                        strbuf_addf(sb, "| %*s", graph->expansion_row, "");
 462                } else if (seen_this) {
 463                        strbuf_addstr(sb, "\\ ");
 464                } else {
 465                        strbuf_addstr(sb, "| ");
 466                }
 467        }
 468
 469        graph_pad_horizontally(graph, sb);
 470
 471        /*
 472         * Increment graph->expansion_row,
 473         * and move to state GRAPH_COMMIT if necessary
 474         */
 475        graph->expansion_row++;
 476        if (graph->expansion_row >= num_expansion_rows)
 477                graph->state = GRAPH_COMMIT;
 478}
 479
 480void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 481{
 482        int seen_this = 0;
 483        int i, j;
 484
 485        /*
 486         * Output the row containing this commit
 487         * Iterate up to and including graph->num_columns,
 488         * since the current commit may not be in any of the existing
 489         * columns.  (This happens when the current commit doesn't have any
 490         * children that we have already processed.)
 491         */
 492        seen_this = 0;
 493        for (i = 0; i <= graph->num_columns; i++) {
 494                struct commit *col_commit;
 495                if (i == graph->num_columns) {
 496                        if (seen_this)
 497                                break;
 498                        col_commit = graph->commit;
 499                } else {
 500                        col_commit = graph->columns[i].commit;
 501                }
 502
 503                if (col_commit == graph->commit) {
 504                        seen_this = 1;
 505                        if (graph->num_parents > 1)
 506                                strbuf_addch(sb, 'M');
 507                        else
 508                                strbuf_addch(sb, '*');
 509
 510                        if (graph->num_parents < 2)
 511                                strbuf_addch(sb, ' ');
 512                        else if (graph->num_parents == 2)
 513                                strbuf_addstr(sb, "  ");
 514                        else {
 515                                int num_dashes =
 516                                        ((graph->num_parents - 2) * 2) - 1;
 517                                for (j = 0; j < num_dashes; j++)
 518                                        strbuf_addch(sb, '-');
 519                                strbuf_addstr(sb, ". ");
 520                        }
 521                } else if (seen_this && (graph->num_parents > 1)) {
 522                        strbuf_addstr(sb, "\\ ");
 523                } else {
 524                        strbuf_addstr(sb, "| ");
 525                }
 526        }
 527
 528        graph_pad_horizontally(graph, sb);
 529
 530        /*
 531         * Update graph->state
 532         */
 533        if (graph->num_parents > 1)
 534                graph->state = GRAPH_POST_MERGE;
 535        else if (graph_is_mapping_correct(graph))
 536                graph->state = GRAPH_PADDING;
 537        else
 538                graph->state = GRAPH_COLLAPSING;
 539}
 540
 541void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
 542{
 543        int seen_this = 0;
 544        int i, j;
 545
 546        /*
 547         * Output the post-merge row
 548         */
 549        for (i = 0; i <= graph->num_columns; i++) {
 550                struct commit *col_commit;
 551                if (i == graph->num_columns) {
 552                        if (seen_this)
 553                                break;
 554                        col_commit = graph->commit;
 555                } else {
 556                        col_commit = graph->columns[i].commit;
 557                }
 558
 559                if (col_commit == graph->commit) {
 560                        seen_this = 1;
 561                        strbuf_addch(sb, '|');
 562                        for (j = 0; j < graph->num_parents - 1; j++)
 563                                strbuf_addstr(sb, "\\ ");
 564                        if (graph->num_parents == 2)
 565                                strbuf_addch(sb, ' ');
 566                } else if (seen_this && (graph->num_parents > 2)) {
 567                        strbuf_addstr(sb, "\\ ");
 568                } else {
 569                        strbuf_addstr(sb, "| ");
 570                }
 571        }
 572
 573        graph_pad_horizontally(graph, sb);
 574
 575        /*
 576         * Update graph->state
 577         */
 578        if (graph_is_mapping_correct(graph))
 579                graph->state = GRAPH_PADDING;
 580        else
 581                graph->state = GRAPH_COLLAPSING;
 582}
 583
 584void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
 585{
 586        int i;
 587        int *tmp_mapping;
 588
 589        /*
 590         * Clear out the new_mapping array
 591         */
 592        for (i = 0; i < graph->mapping_size; i++)
 593                graph->new_mapping[i] = -1;
 594
 595        for (i = 0; i < graph->mapping_size; i++) {
 596                int target = graph->mapping[i];
 597                if (target < 0)
 598                        continue;
 599
 600                /*
 601                 * Since update_columns() always inserts the leftmost
 602                 * column first, each branch's target location should
 603                 * always be either its current location or to the left of
 604                 * its current location.
 605                 *
 606                 * We never have to move branches to the right.  This makes
 607                 * the graph much more legible, since whenever branches
 608                 * cross, only one is moving directions.
 609                 */
 610                assert(target * 2 <= i);
 611
 612                if (target * 2 == i) {
 613                        /*
 614                         * This column is already in the
 615                         * correct place
 616                         */
 617                        assert(graph->new_mapping[i] == -1);
 618                        graph->new_mapping[i] = target;
 619                } else if (graph->new_mapping[i - 1] < 0) {
 620                        /*
 621                         * Nothing is to the left.
 622                         * Move to the left by one
 623                         */
 624                        graph->new_mapping[i - 1] = target;
 625                } else if (graph->new_mapping[i - 1] == target) {
 626                        /*
 627                         * There is a branch line to our left
 628                         * already, and it is our target.  We
 629                         * combine with this line, since we share
 630                         * the same parent commit.
 631                         *
 632                         * We don't have to add anything to the
 633                         * output or new_mapping, since the
 634                         * existing branch line has already taken
 635                         * care of it.
 636                         */
 637                } else {
 638                        /*
 639                         * There is a branch line to our left,
 640                         * but it isn't our target.  We need to
 641                         * cross over it.
 642                         *
 643                         * The space just to the left of this
 644                         * branch should always be empty.
 645                         */
 646                        assert(graph->new_mapping[i - 1] > target);
 647                        assert(graph->new_mapping[i - 2] < 0);
 648                        graph->new_mapping[i - 2] = target;
 649                }
 650        }
 651
 652        /*
 653         * The new mapping may be 1 smaller than the old mapping
 654         */
 655        if (graph->new_mapping[graph->mapping_size - 1] < 0)
 656                graph->mapping_size--;
 657
 658        /*
 659         * Output out a line based on the new mapping info
 660         */
 661        for (i = 0; i < graph->mapping_size; i++) {
 662                int target = graph->new_mapping[i];
 663                if (target < 0)
 664                        strbuf_addch(sb, ' ');
 665                else if (target * 2 == i)
 666                        strbuf_addch(sb, '|');
 667                else
 668                        strbuf_addch(sb, '/');
 669        }
 670
 671        graph_pad_horizontally(graph, sb);
 672
 673        /*
 674         * Swap mapping and new_mapping
 675         */
 676        tmp_mapping = graph->mapping;
 677        graph->mapping = graph->new_mapping;
 678        graph->new_mapping = tmp_mapping;
 679
 680        /*
 681         * If graph->mapping indicates that all of the branch lines
 682         * are already in the correct positions, we are done.
 683         * Otherwise, we need to collapse some branch lines together.
 684         */
 685        if (graph_is_mapping_correct(graph))
 686                graph->state = GRAPH_PADDING;
 687}
 688
 689int graph_next_line(struct git_graph *graph, struct strbuf *sb)
 690{
 691        switch (graph->state) {
 692        case GRAPH_PADDING:
 693                graph_output_padding_line(graph, sb);
 694                return 0;
 695        case GRAPH_SKIP:
 696                graph_output_skip_line(graph, sb);
 697                return 0;
 698        case GRAPH_PRE_COMMIT:
 699                graph_output_pre_commit_line(graph, sb);
 700                return 0;
 701        case GRAPH_COMMIT:
 702                graph_output_commit_line(graph, sb);
 703                return 1;
 704        case GRAPH_POST_MERGE:
 705                graph_output_post_merge_line(graph, sb);
 706                return 0;
 707        case GRAPH_COLLAPSING:
 708                graph_output_collapsing_line(graph, sb);
 709                return 0;
 710        }
 711
 712        assert(0);
 713        return 0;
 714}
 715
 716void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
 717{
 718        int i, j;
 719
 720        if (graph->state != GRAPH_COMMIT) {
 721                graph_next_line(graph, sb);
 722                return;
 723        }
 724
 725        /*
 726         * Output the row containing this commit
 727         * Iterate up to and including graph->num_columns,
 728         * since the current commit may not be in any of the existing
 729         * columns.  (This happens when the current commit doesn't have any
 730         * children that we have already processed.)
 731         */
 732        for (i = 0; i < graph->num_columns; i++) {
 733                struct commit *col_commit = graph->columns[i].commit;
 734                if (col_commit == graph->commit) {
 735                        strbuf_addch(sb, '|');
 736
 737                        if (graph->num_parents < 3)
 738                                strbuf_addch(sb, ' ');
 739                        else {
 740                                int num_spaces = ((graph->num_parents - 2) * 2);
 741                                for (j = 0; j < num_spaces; j++)
 742                                        strbuf_addch(sb, ' ');
 743                        }
 744                } else {
 745                        strbuf_addstr(sb, "| ");
 746                }
 747        }
 748
 749        graph_pad_horizontally(graph, sb);
 750}
 751
 752int graph_is_commit_finished(struct git_graph const *graph)
 753{
 754        return (graph->state == GRAPH_PADDING);
 755}
 756
 757void graph_show_commit(struct git_graph *graph)
 758{
 759        struct strbuf msgbuf;
 760        int shown_commit_line = 0;
 761
 762        if (!graph)
 763                return;
 764
 765        strbuf_init(&msgbuf, 0);
 766
 767        while (!shown_commit_line) {
 768                shown_commit_line = graph_next_line(graph, &msgbuf);
 769                fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
 770                if (!shown_commit_line)
 771                        putchar('\n');
 772                strbuf_setlen(&msgbuf, 0);
 773        }
 774
 775        strbuf_release(&msgbuf);
 776}
 777
 778void graph_show_oneline(struct git_graph *graph)
 779{
 780        struct strbuf msgbuf;
 781
 782        if (!graph)
 783                return;
 784
 785        strbuf_init(&msgbuf, 0);
 786        graph_next_line(graph, &msgbuf);
 787        fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
 788        strbuf_release(&msgbuf);
 789}
 790
 791void graph_show_padding(struct git_graph *graph)
 792{
 793        struct strbuf msgbuf;
 794
 795        if (!graph)
 796                return;
 797
 798        strbuf_init(&msgbuf, 0);
 799        graph_padding_line(graph, &msgbuf);
 800        fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
 801        strbuf_release(&msgbuf);
 802}
 803
 804int graph_show_remainder(struct git_graph *graph)
 805{
 806        struct strbuf msgbuf;
 807        int shown = 0;
 808
 809        if (!graph)
 810                return 0;
 811
 812        if (graph_is_commit_finished(graph))
 813                return 0;
 814
 815        strbuf_init(&msgbuf, 0);
 816        for (;;) {
 817                graph_next_line(graph, &msgbuf);
 818                fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
 819                strbuf_setlen(&msgbuf, 0);
 820                shown = 1;
 821
 822                if (!graph_is_commit_finished(graph))
 823                        putchar('\n');
 824                else
 825                        break;
 826        }
 827        strbuf_release(&msgbuf);
 828
 829        return shown;
 830}
 831
 832
 833void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
 834{
 835        char *p;
 836
 837        if (!graph) {
 838                fwrite(sb->buf, sizeof(char), sb->len, stdout);
 839                return;
 840        }
 841
 842        /*
 843         * Print the strbuf line by line,
 844         * and display the graph info before each line but the first.
 845         */
 846        p = sb->buf;
 847        while (p) {
 848                size_t len;
 849                char *next_p = strchr(p, '\n');
 850                if (next_p) {
 851                        next_p++;
 852                        len = next_p - p;
 853                } else {
 854                        len = (sb->buf + sb->len) - p;
 855                }
 856                fwrite(p, sizeof(char), len, stdout);
 857                if (next_p && *next_p != '\0')
 858                        graph_show_oneline(graph);
 859                p = next_p;
 860        }
 861}
 862
 863void graph_show_commit_msg(struct git_graph *graph,
 864                           struct strbuf const *sb)
 865{
 866        int newline_terminated;
 867
 868        if (!graph) {
 869                /*
 870                 * If there's no graph, just print the message buffer.
 871                 *
 872                 * The message buffer for CMIT_FMT_ONELINE and
 873                 * CMIT_FMT_USERFORMAT are already missing a terminating
 874                 * newline.  All of the other formats should have it.
 875                 */
 876                fwrite(sb->buf, sizeof(char), sb->len, stdout);
 877                return;
 878        }
 879
 880        newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');
 881
 882        /*
 883         * Show the commit message
 884         */
 885        graph_show_strbuf(graph, sb);
 886
 887        /*
 888         * If there is more output needed for this commit, show it now
 889         */
 890        if (!graph_is_commit_finished(graph)) {
 891                /*
 892                 * If sb doesn't have a terminating newline, print one now,
 893                 * so we can start the remainder of the graph output on a
 894                 * new line.
 895                 */
 896                if (!newline_terminated)
 897                        putchar('\n');
 898
 899                graph_show_remainder(graph);
 900
 901                /*
 902                 * If sb ends with a newline, our output should too.
 903                 */
 904                if (newline_terminated)
 905                        putchar('\n');
 906        }
 907}