log and rev-list: add --graph option

This new option causes a text-based representation of the history to be
printed to the left of the normal output.

Signed-off-by: Adam Simpkins <adam@adamsimpkins.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Adam Simpkins 2008-05-04 03:36:54 -07:00 коммит произвёл Junio C Hamano
Родитель c12172d2ea
Коммит 7fefda5cc7
6 изменённых файлов: 161 добавлений и 16 удалений

Просмотреть файл

@ -75,6 +75,16 @@ you would get an output line this:
-xxxxxxx... 1st on a
-----------------------------------------------------------------------
--graph::
Draw a text-based graphical representation of the commit history
on the left hand side of the output. This may cause extra lines
to be printed in between commits, in order for the graph history
to be drawn properly.
+
This implies the '--topo-order' option by default, but the
'--date-order' option may also be specified.
Diff Formatting
~~~~~~~~~~~~~~~

Просмотреть файл

@ -74,14 +74,17 @@ state.
Calling sequence
----------------
* Create a `struct git_graph` by calling `graph_init()`.
* Create a `struct git_graph` by calling `graph_init()`. When using the
revision walking API, this is done automatically by `setup_revisions()` if
the '--graph' option is supplied.
* Use the revision walking API to walk through a group of contiguous commits.
The `get_revision()` function automatically calls `graph_update()` each time
it is invoked.
* For each commit traversed, call `graph_update()` to move the graph to the
next commit. Once `graph_update()` has been called, call `graph_next_line()`
repeatedly, until `graph_is_commit_finished()` returns non-zero. Each call
to `graph_next_line()` will output a single line of the graph. The resulting
* For each commit, call `graph_next_line()` repeatedly, until
`graph_is_commit_finished()` returns non-zero. Each call go
`graph_next_line()` will output a single line of the graph. The resulting
lines will not contain any newlines. `graph_next_line()` returns 1 if the
resulting line contains the current commit, or 0 if this is merely a line
needed to adjust the graph before or after the current commit. This return

Просмотреть файл

@ -10,6 +10,7 @@
#include "list-objects.h"
#include "builtin.h"
#include "log-tree.h"
#include "graph.h"
/* bits #0-15 in revision.h */
@ -58,6 +59,8 @@ static const char *header_prefix;
static void finish_commit(struct commit *commit);
static void show_commit(struct commit *commit)
{
graph_show_commit(revs.graph);
if (show_timestamp)
printf("%lu ", commit->date);
if (header_prefix)
@ -96,9 +99,48 @@ static void show_commit(struct commit *commit)
pretty_print_commit(revs.commit_format, commit,
&buf, revs.abbrev, NULL, NULL,
revs.date_mode, 0);
if (buf.len)
printf("%s%c", buf.buf, hdr_termination);
if (revs.graph) {
if (buf.len) {
if (revs.commit_format != CMIT_FMT_ONELINE)
graph_show_oneline(revs.graph);
graph_show_commit_msg(revs.graph, &buf);
/*
* Add a newline after the commit message.
*
* Usually, this newline produces a blank
* padding line between entries, in which case
* we need to add graph padding on this line.
*
* However, the commit message may not end in a
* newline. In this case the newline simply
* ends the last line of the commit message,
* and we don't need any graph output. (This
* always happens with CMIT_FMT_ONELINE, and it
* happens with CMIT_FMT_USERFORMAT when the
* format doesn't explicitly end in a newline.)
*/
if (buf.len && buf.buf[buf.len - 1] == '\n')
graph_show_padding(revs.graph);
putchar('\n');
} else {
/*
* If the message buffer is empty, just show
* the rest of the graph output for this
* commit.
*/
if (graph_show_remainder(revs.graph))
putchar('\n');
}
} else {
if (buf.len)
printf("%s%c", buf.buf, hdr_termination);
}
strbuf_release(&buf);
} else {
if (graph_show_remainder(revs.graph))
putchar('\n');
}
maybe_flush_or_die(stdout, "stdout");
finish_commit(commit);

Просмотреть файл

@ -1,6 +1,7 @@
#include "cache.h"
#include "diff.h"
#include "commit.h"
#include "graph.h"
#include "log-tree.h"
#include "reflog-walk.h"
@ -165,11 +166,16 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
}
printf("From %s Mon Sep 17 00:00:00 2001\n", name);
if (opt->message_id)
graph_show_oneline(opt->graph);
if (opt->message_id) {
printf("Message-Id: <%s>\n", opt->message_id);
if (opt->ref_message_id)
graph_show_oneline(opt->graph);
}
if (opt->ref_message_id) {
printf("In-Reply-To: <%s>\nReferences: <%s>\n",
opt->ref_message_id, opt->ref_message_id);
graph_show_oneline(opt->graph);
}
if (opt->mime_boundary) {
static char subject_buffer[1024];
static char buffer[1024];
@ -220,6 +226,8 @@ void show_log(struct rev_info *opt)
opt->loginfo = NULL;
if (!opt->verbose_header) {
graph_show_commit(opt->graph);
if (commit->object.flags & BOUNDARY)
putchar('-');
else if (commit->object.flags & UNINTERESTING)
@ -234,6 +242,10 @@ void show_log(struct rev_info *opt)
if (opt->print_parents)
show_parents(commit, abbrev_commit);
show_decorations(commit);
if (opt->graph && !graph_is_commit_finished(opt->graph)) {
putchar('\n');
graph_show_remainder(opt->graph);
}
putchar(opt->diffopt.line_termination);
return;
}
@ -243,10 +255,32 @@ void show_log(struct rev_info *opt)
* Otherwise, add a diffopt.line_termination character before all
* entries but the first. (IOW, as a separator between entries)
*/
if (opt->shown_one && !opt->use_terminator)
if (opt->shown_one && !opt->use_terminator) {
/*
* If entries are separated by a newline, the output
* should look human-readable. If the last entry ended
* with a newline, print the graph output before this
* newline. Otherwise it will end up as a completely blank
* line and will look like a gap in the graph.
*
* If the entry separator is not a newline, the output is
* primarily intended for programmatic consumption, and we
* never want the extra graph output before the entry
* separator.
*/
if (opt->diffopt.line_termination == '\n' &&
!opt->missing_newline)
graph_show_padding(opt->graph);
putchar(opt->diffopt.line_termination);
}
opt->shown_one = 1;
/*
* If the history graph was requested,
* print the graph, up to this commit's line
*/
graph_show_commit(opt->graph);
/*
* Print header line of header..
*/
@ -279,8 +313,19 @@ void show_log(struct rev_info *opt)
abbrev_commit));
show_decorations(commit);
printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
if (opt->commit_format == CMIT_FMT_ONELINE) {
putchar(' ');
} else {
putchar('\n');
graph_show_oneline(opt->graph);
}
if (opt->reflog_info) {
/*
* setup_revisions() ensures that opt->reflog_info
* and opt->graph cannot both be set,
* so we don't need to worry about printing the
* graph info here.
*/
show_reflog_message(opt->reflog_info,
opt->commit_format == CMIT_FMT_ONELINE,
opt->date_mode);
@ -304,13 +349,30 @@ void show_log(struct rev_info *opt)
if (opt->add_signoff)
append_signoff(&msgbuf, opt->add_signoff);
if (opt->show_log_size)
if (opt->show_log_size) {
printf("log size %i\n", (int)msgbuf.len);
graph_show_oneline(opt->graph);
}
if (msgbuf.len)
/*
* Set opt->missing_newline if msgbuf doesn't
* end in a newline (including if it is empty)
*/
if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
opt->missing_newline = 1;
else
opt->missing_newline = 0;
if (opt->graph)
graph_show_commit_msg(opt->graph, &msgbuf);
else
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
if (opt->use_terminator)
if (opt->use_terminator) {
if (!opt->missing_newline)
graph_show_padding(opt->graph);
putchar('\n');
}
strbuf_release(&msgbuf);
}

Просмотреть файл

@ -6,6 +6,7 @@
#include "diff.h"
#include "refs.h"
#include "revision.h"
#include "graph.h"
#include "grep.h"
#include "reflog-walk.h"
#include "patch-ids.h"
@ -1203,6 +1204,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
get_commit_format(arg+8, revs);
continue;
}
if (!prefixcmp(arg, "--graph")) {
revs->topo_order = 1;
revs->rewrite_parents = 1;
revs->graph = graph_init();
continue;
}
if (!strcmp(arg, "--root")) {
revs->show_root_diff = 1;
continue;
@ -1397,6 +1404,15 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
if (revs->reverse && revs->reflog_info)
die("cannot combine --reverse with --walk-reflogs");
/*
* Limitations on the graph functionality
*/
if (revs->reverse && revs->graph)
die("cannot combine --reverse with --graph");
if (revs->reflog_info && revs->graph)
die("cannot combine --walk-reflogs with --graph");
return left;
}
@ -1598,7 +1614,7 @@ static void gc_boundary(struct object_array *array)
}
}
struct commit *get_revision(struct rev_info *revs)
static struct commit *get_revision_internal(struct rev_info *revs)
{
struct commit *c = NULL;
struct commit_list *l;
@ -1705,3 +1721,11 @@ struct commit *get_revision(struct rev_info *revs)
return c;
}
struct commit *get_revision(struct rev_info *revs)
{
struct commit *c = get_revision_internal(revs);
if (c && revs->graph)
graph_update(revs->graph, c);
return c;
}

Просмотреть файл

@ -66,7 +66,8 @@ struct rev_info {
/* Format info */
unsigned int shown_one:1,
abbrev_commit:1,
use_terminator:1;
use_terminator:1,
missing_newline:1;
enum date_mode date_mode;
const char **ignore_packed; /* pretend objects in these are unpacked */
@ -89,6 +90,9 @@ struct rev_info {
/* Filter by commit log message */
struct grep_opt *grep_filter;
/* Display history graph */
struct git_graph *graph;
/* special limits */
int skip_count;
int max_count;