@matheusbsbs / matheus-bagliano / commits / 7fefda5cc7
Fork 0

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>

Adam Simpkins committed May 4, 2008 at 03:36 UTC 7fefda5cc7a5faf7962092367bedb321a634d54d
6 files changed +161 -16
Documentation/rev-list-options.txt
+10
@@ -75,6 +75,16 @@ you would get an output line this:
75 -xxxxxxx... 1st on a
76 -----------------------------------------------------------------------
77
78 +--graph::
79 +
80 + Draw a text-based graphical representation of the commit history
81 + on the left hand side of the output. This may cause extra lines
82 + to be printed in between commits, in order for the graph history
83 + to be drawn properly.
84 ++
85 +This implies the '--topo-order' option by default, but the
86 +'--date-order' option may also be specified.
87 +
88 Diff Formatting
89 ~~~~~~~~~~~~~~~
90
Documentation/technical/api-history-graph.txt
+8 -5
@@ -74,14 +74,17 @@ state.
74 Calling sequence
75 ----------------
76
77 -* Create a `struct git_graph` by calling `graph_init()`.
77 +* Create a `struct git_graph` by calling `graph_init()`. When using the
78 + revision walking API, this is done automatically by `setup_revisions()` if
79 + the '--graph' option is supplied.
80
81 * Use the revision walking API to walk through a group of contiguous commits.
82 + The `get_revision()` function automatically calls `graph_update()` each time
83 + it is invoked.
84
81 -* For each commit traversed, call `graph_update()` to move the graph to the
82 - next commit. Once `graph_update()` has been called, call `graph_next_line()`
83 - repeatedly, until `graph_is_commit_finished()` returns non-zero. Each call
84 - to `graph_next_line()` will output a single line of the graph. The resulting
85 +* For each commit, call `graph_next_line()` repeatedly, until
86 + `graph_is_commit_finished()` returns non-zero. Each call go
87 + `graph_next_line()` will output a single line of the graph. The resulting
88 lines will not contain any newlines. `graph_next_line()` returns 1 if the
89 resulting line contains the current commit, or 0 if this is merely a line
90 needed to adjust the graph before or after the current commit. This return
builtin-rev-list.c
+44 -2
@@ -10,6 +10,7 @@
10 #include "list-objects.h"
11 #include "builtin.h"
12 #include "log-tree.h"
13 +#include "graph.h"
14
15 /* bits #0-15 in revision.h */
16
@@ -58,6 +59,8 @@ static const char *header_prefix;
59 static void finish_commit(struct commit *commit);
60 static void show_commit(struct commit *commit)
61 {
62 + graph_show_commit(revs.graph);
63 +
64 if (show_timestamp)
65 printf("%lu ", commit->date);
66 if (header_prefix)
@@ -96,9 +99,48 @@ static void show_commit(struct commit *commit)
99 pretty_print_commit(revs.commit_format, commit,
100 &buf, revs.abbrev, NULL, NULL,
101 revs.date_mode, 0);
99 - if (buf.len)
100 - printf("%s%c", buf.buf, hdr_termination);
102 + if (revs.graph) {
103 + if (buf.len) {
104 + if (revs.commit_format != CMIT_FMT_ONELINE)
105 + graph_show_oneline(revs.graph);
106 +
107 + graph_show_commit_msg(revs.graph, &buf);
108 +
109 + /*
110 + * Add a newline after the commit message.
111 + *
112 + * Usually, this newline produces a blank
113 + * padding line between entries, in which case
114 + * we need to add graph padding on this line.
115 + *
116 + * However, the commit message may not end in a
117 + * newline. In this case the newline simply
118 + * ends the last line of the commit message,
119 + * and we don't need any graph output. (This
120 + * always happens with CMIT_FMT_ONELINE, and it
121 + * happens with CMIT_FMT_USERFORMAT when the
122 + * format doesn't explicitly end in a newline.)
123 + */
124 + if (buf.len && buf.buf[buf.len - 1] == '\n')
125 + graph_show_padding(revs.graph);
126 + putchar('\n');
127 + } else {
128 + /*
129 + * If the message buffer is empty, just show
130 + * the rest of the graph output for this
131 + * commit.
132 + */
133 + if (graph_show_remainder(revs.graph))
134 + putchar('\n');
135 + }
136 + } else {
137 + if (buf.len)
138 + printf("%s%c", buf.buf, hdr_termination);
139 + }
140 strbuf_release(&buf);
141 + } else {
142 + if (graph_show_remainder(revs.graph))
143 + putchar('\n');
144 }
145 maybe_flush_or_die(stdout, "stdout");
146 finish_commit(commit);
log-tree.c
+69 -7
@@ -1,6 +1,7 @@
1 #include "cache.h"
2 #include "diff.h"
3 #include "commit.h"
4 +#include "graph.h"
5 #include "log-tree.h"
6 #include "reflog-walk.h"
7
@@ -165,11 +166,16 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
166 }
167
168 printf("From %s Mon Sep 17 00:00:00 2001\n", name);
168 - if (opt->message_id)
169 + graph_show_oneline(opt->graph);
170 + if (opt->message_id) {
171 printf("Message-Id: <%s>\n", opt->message_id);
170 - if (opt->ref_message_id)
172 + graph_show_oneline(opt->graph);
173 + }
174 + if (opt->ref_message_id) {
175 printf("In-Reply-To: <%s>\nReferences: <%s>\n",
176 opt->ref_message_id, opt->ref_message_id);
177 + graph_show_oneline(opt->graph);
178 + }
179 if (opt->mime_boundary) {
180 static char subject_buffer[1024];
181 static char buffer[1024];
@@ -220,6 +226,8 @@ void show_log(struct rev_info *opt)
226
227 opt->loginfo = NULL;
228 if (!opt->verbose_header) {
229 + graph_show_commit(opt->graph);
230 +
231 if (commit->object.flags & BOUNDARY)
232 putchar('-');
233 else if (commit->object.flags & UNINTERESTING)
@@ -234,6 +242,10 @@ void show_log(struct rev_info *opt)
242 if (opt->print_parents)
243 show_parents(commit, abbrev_commit);
244 show_decorations(commit);
245 + if (opt->graph && !graph_is_commit_finished(opt->graph)) {
246 + putchar('\n');
247 + graph_show_remainder(opt->graph);
248 + }
249 putchar(opt->diffopt.line_termination);
250 return;
251 }
@@ -243,10 +255,32 @@ void show_log(struct rev_info *opt)
255 * Otherwise, add a diffopt.line_termination character before all
256 * entries but the first. (IOW, as a separator between entries)
257 */
246 - if (opt->shown_one && !opt->use_terminator)
258 + if (opt->shown_one && !opt->use_terminator) {
259 + /*
260 + * If entries are separated by a newline, the output
261 + * should look human-readable. If the last entry ended
262 + * with a newline, print the graph output before this
263 + * newline. Otherwise it will end up as a completely blank
264 + * line and will look like a gap in the graph.
265 + *
266 + * If the entry separator is not a newline, the output is
267 + * primarily intended for programmatic consumption, and we
268 + * never want the extra graph output before the entry
269 + * separator.
270 + */
271 + if (opt->diffopt.line_termination == '\n' &&
272 + !opt->missing_newline)
273 + graph_show_padding(opt->graph);
274 putchar(opt->diffopt.line_termination);
275 + }
276 opt->shown_one = 1;
277
278 + /*
279 + * If the history graph was requested,
280 + * print the graph, up to this commit's line
281 + */
282 + graph_show_commit(opt->graph);
283 +
284 /*
285 * Print header line of header..
286 */
@@ -279,8 +313,19 @@ void show_log(struct rev_info *opt)
313 abbrev_commit));
314 show_decorations(commit);
315 printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
282 - putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
316 + if (opt->commit_format == CMIT_FMT_ONELINE) {
317 + putchar(' ');
318 + } else {
319 + putchar('\n');
320 + graph_show_oneline(opt->graph);
321 + }
322 if (opt->reflog_info) {
323 + /*
324 + * setup_revisions() ensures that opt->reflog_info
325 + * and opt->graph cannot both be set,
326 + * so we don't need to worry about printing the
327 + * graph info here.
328 + */
329 show_reflog_message(opt->reflog_info,
330 opt->commit_format == CMIT_FMT_ONELINE,
331 opt->date_mode);
@@ -304,13 +349,30 @@ void show_log(struct rev_info *opt)
349
350 if (opt->add_signoff)
351 append_signoff(&msgbuf, opt->add_signoff);
307 - if (opt->show_log_size)
352 + if (opt->show_log_size) {
353 printf("log size %i\n", (int)msgbuf.len);
354 + graph_show_oneline(opt->graph);
355 + }
356
310 - if (msgbuf.len)
357 + /*
358 + * Set opt->missing_newline if msgbuf doesn't
359 + * end in a newline (including if it is empty)
360 + */
361 + if (!msgbuf.len || msgbuf.buf[msgbuf.len - 1] != '\n')
362 + opt->missing_newline = 1;
363 + else
364 + opt->missing_newline = 0;
365 +
366 + if (opt->graph)
367 + graph_show_commit_msg(opt->graph, &msgbuf);
368 + else
369 fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
312 - if (opt->use_terminator)
370 + if (opt->use_terminator) {
371 + if (!opt->missing_newline)
372 + graph_show_padding(opt->graph);
373 putchar('\n');
374 + }
375 +
376 strbuf_release(&msgbuf);
377 }
378
revision.c
+25 -1
@@ -6,6 +6,7 @@
6 #include "diff.h"
7 #include "refs.h"
8 #include "revision.h"
9 +#include "graph.h"
10 #include "grep.h"
11 #include "reflog-walk.h"
12 #include "patch-ids.h"
@@ -1203,6 +1204,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
1204 get_commit_format(arg+8, revs);
1205 continue;
1206 }
1207 + if (!prefixcmp(arg, "--graph")) {
1208 + revs->topo_order = 1;
1209 + revs->rewrite_parents = 1;
1210 + revs->graph = graph_init();
1211 + continue;
1212 + }
1213 if (!strcmp(arg, "--root")) {
1214 revs->show_root_diff = 1;
1215 continue;
@@ -1397,6 +1404,15 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
1404 if (revs->reverse && revs->reflog_info)
1405 die("cannot combine --reverse with --walk-reflogs");
1406
1407 + /*
1408 + * Limitations on the graph functionality
1409 + */
1410 + if (revs->reverse && revs->graph)
1411 + die("cannot combine --reverse with --graph");
1412 +
1413 + if (revs->reflog_info && revs->graph)
1414 + die("cannot combine --walk-reflogs with --graph");
1415 +
1416 return left;
1417 }
1418
@@ -1598,7 +1614,7 @@ static void gc_boundary(struct object_array *array)
1614 }
1615 }
1616
1601 -struct commit *get_revision(struct rev_info *revs)
1617 +static struct commit *get_revision_internal(struct rev_info *revs)
1618 {
1619 struct commit *c = NULL;
1620 struct commit_list *l;
@@ -1705,3 +1721,11 @@ struct commit *get_revision(struct rev_info *revs)
1721
1722 return c;
1723 }
1724 +
1725 +struct commit *get_revision(struct rev_info *revs)
1726 +{
1727 + struct commit *c = get_revision_internal(revs);
1728 + if (c && revs->graph)
1729 + graph_update(revs->graph, c);
1730 + return c;
1731 +}
revision.h
+5 -1
@@ -66,7 +66,8 @@ struct rev_info {
66 /* Format info */
67 unsigned int shown_one:1,
68 abbrev_commit:1,
69 - use_terminator:1;
69 + use_terminator:1,
70 + missing_newline:1;
71 enum date_mode date_mode;
72
73 const char **ignore_packed; /* pretend objects in these are unpacked */
@@ -89,6 +90,9 @@ struct rev_info {
90 /* Filter by commit log message */
91 struct grep_opt *grep_filter;
92
93 + /* Display history graph */
94 + struct git_graph *graph;
95 +
96 /* special limits */
97 int skip_count;
98 int max_count;