##// END OF EJS Templates
graphlog: unify log -G revset translation
Patrick Mezard -
r14085:4852753d default
parent child Browse files
Show More
@@ -1,366 +1,370
1 # ASCII graph log extension for Mercurial
1 # ASCII graph log extension for Mercurial
2 #
2 #
3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to view revision graphs from a shell
8 '''command to view revision graphs from a shell
9
9
10 This extension adds a --graph option to the incoming, outgoing and log
10 This extension adds a --graph option to the incoming, outgoing and log
11 commands. When this options is given, an ASCII representation of the
11 commands. When this options is given, an ASCII representation of the
12 revision graph is also shown.
12 revision graph is also shown.
13 '''
13 '''
14
14
15 from mercurial.cmdutil import revrange, show_changeset
15 from mercurial.cmdutil import revrange, show_changeset
16 from mercurial.commands import templateopts
16 from mercurial.commands import templateopts
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 from mercurial.node import nullrev
18 from mercurial.node import nullrev
19 from mercurial import cmdutil, commands, extensions
19 from mercurial import cmdutil, commands, extensions
20 from mercurial import hg, scmutil, util, graphmod
20 from mercurial import hg, scmutil, util, graphmod
21
21
22 ASCIIDATA = 'ASC'
22 ASCIIDATA = 'ASC'
23
23
24 def asciiedges(seen, rev, parents):
24 def asciiedges(seen, rev, parents):
25 """adds edge info to changelog DAG walk suitable for ascii()"""
25 """adds edge info to changelog DAG walk suitable for ascii()"""
26 if rev not in seen:
26 if rev not in seen:
27 seen.append(rev)
27 seen.append(rev)
28 nodeidx = seen.index(rev)
28 nodeidx = seen.index(rev)
29
29
30 knownparents = []
30 knownparents = []
31 newparents = []
31 newparents = []
32 for parent in parents:
32 for parent in parents:
33 if parent in seen:
33 if parent in seen:
34 knownparents.append(parent)
34 knownparents.append(parent)
35 else:
35 else:
36 newparents.append(parent)
36 newparents.append(parent)
37
37
38 ncols = len(seen)
38 ncols = len(seen)
39 seen[nodeidx:nodeidx + 1] = newparents
39 seen[nodeidx:nodeidx + 1] = newparents
40 edges = [(nodeidx, seen.index(p)) for p in knownparents]
40 edges = [(nodeidx, seen.index(p)) for p in knownparents]
41
41
42 if len(newparents) > 0:
42 if len(newparents) > 0:
43 edges.append((nodeidx, nodeidx))
43 edges.append((nodeidx, nodeidx))
44 if len(newparents) > 1:
44 if len(newparents) > 1:
45 edges.append((nodeidx, nodeidx + 1))
45 edges.append((nodeidx, nodeidx + 1))
46
46
47 nmorecols = len(seen) - ncols
47 nmorecols = len(seen) - ncols
48 return nodeidx, edges, ncols, nmorecols
48 return nodeidx, edges, ncols, nmorecols
49
49
50 def fix_long_right_edges(edges):
50 def fix_long_right_edges(edges):
51 for (i, (start, end)) in enumerate(edges):
51 for (i, (start, end)) in enumerate(edges):
52 if end > start:
52 if end > start:
53 edges[i] = (start, end + 1)
53 edges[i] = (start, end + 1)
54
54
55 def get_nodeline_edges_tail(
55 def get_nodeline_edges_tail(
56 node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
56 node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
57 if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
57 if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
58 # Still going in the same non-vertical direction.
58 # Still going in the same non-vertical direction.
59 if n_columns_diff == -1:
59 if n_columns_diff == -1:
60 start = max(node_index + 1, p_node_index)
60 start = max(node_index + 1, p_node_index)
61 tail = ["|", " "] * (start - node_index - 1)
61 tail = ["|", " "] * (start - node_index - 1)
62 tail.extend(["/", " "] * (n_columns - start))
62 tail.extend(["/", " "] * (n_columns - start))
63 return tail
63 return tail
64 else:
64 else:
65 return ["\\", " "] * (n_columns - node_index - 1)
65 return ["\\", " "] * (n_columns - node_index - 1)
66 else:
66 else:
67 return ["|", " "] * (n_columns - node_index - 1)
67 return ["|", " "] * (n_columns - node_index - 1)
68
68
69 def draw_edges(edges, nodeline, interline):
69 def draw_edges(edges, nodeline, interline):
70 for (start, end) in edges:
70 for (start, end) in edges:
71 if start == end + 1:
71 if start == end + 1:
72 interline[2 * end + 1] = "/"
72 interline[2 * end + 1] = "/"
73 elif start == end - 1:
73 elif start == end - 1:
74 interline[2 * start + 1] = "\\"
74 interline[2 * start + 1] = "\\"
75 elif start == end:
75 elif start == end:
76 interline[2 * start] = "|"
76 interline[2 * start] = "|"
77 else:
77 else:
78 nodeline[2 * end] = "+"
78 nodeline[2 * end] = "+"
79 if start > end:
79 if start > end:
80 (start, end) = (end, start)
80 (start, end) = (end, start)
81 for i in range(2 * start + 1, 2 * end):
81 for i in range(2 * start + 1, 2 * end):
82 if nodeline[i] != "+":
82 if nodeline[i] != "+":
83 nodeline[i] = "-"
83 nodeline[i] = "-"
84
84
85 def get_padding_line(ni, n_columns, edges):
85 def get_padding_line(ni, n_columns, edges):
86 line = []
86 line = []
87 line.extend(["|", " "] * ni)
87 line.extend(["|", " "] * ni)
88 if (ni, ni - 1) in edges or (ni, ni) in edges:
88 if (ni, ni - 1) in edges or (ni, ni) in edges:
89 # (ni, ni - 1) (ni, ni)
89 # (ni, ni - 1) (ni, ni)
90 # | | | | | | | |
90 # | | | | | | | |
91 # +---o | | o---+
91 # +---o | | o---+
92 # | | c | | c | |
92 # | | c | | c | |
93 # | |/ / | |/ /
93 # | |/ / | |/ /
94 # | | | | | |
94 # | | | | | |
95 c = "|"
95 c = "|"
96 else:
96 else:
97 c = " "
97 c = " "
98 line.extend([c, " "])
98 line.extend([c, " "])
99 line.extend(["|", " "] * (n_columns - ni - 1))
99 line.extend(["|", " "] * (n_columns - ni - 1))
100 return line
100 return line
101
101
102 def asciistate():
102 def asciistate():
103 """returns the initial value for the "state" argument to ascii()"""
103 """returns the initial value for the "state" argument to ascii()"""
104 return [0, 0]
104 return [0, 0]
105
105
106 def ascii(ui, state, type, char, text, coldata):
106 def ascii(ui, state, type, char, text, coldata):
107 """prints an ASCII graph of the DAG
107 """prints an ASCII graph of the DAG
108
108
109 takes the following arguments (one call per node in the graph):
109 takes the following arguments (one call per node in the graph):
110
110
111 - ui to write to
111 - ui to write to
112 - Somewhere to keep the needed state in (init to asciistate())
112 - Somewhere to keep the needed state in (init to asciistate())
113 - Column of the current node in the set of ongoing edges.
113 - Column of the current node in the set of ongoing edges.
114 - Type indicator of node data == ASCIIDATA.
114 - Type indicator of node data == ASCIIDATA.
115 - Payload: (char, lines):
115 - Payload: (char, lines):
116 - Character to use as node's symbol.
116 - Character to use as node's symbol.
117 - List of lines to display as the node's text.
117 - List of lines to display as the node's text.
118 - Edges; a list of (col, next_col) indicating the edges between
118 - Edges; a list of (col, next_col) indicating the edges between
119 the current node and its parents.
119 the current node and its parents.
120 - Number of columns (ongoing edges) in the current revision.
120 - Number of columns (ongoing edges) in the current revision.
121 - The difference between the number of columns (ongoing edges)
121 - The difference between the number of columns (ongoing edges)
122 in the next revision and the number of columns (ongoing edges)
122 in the next revision and the number of columns (ongoing edges)
123 in the current revision. That is: -1 means one column removed;
123 in the current revision. That is: -1 means one column removed;
124 0 means no columns added or removed; 1 means one column added.
124 0 means no columns added or removed; 1 means one column added.
125 """
125 """
126
126
127 idx, edges, ncols, coldiff = coldata
127 idx, edges, ncols, coldiff = coldata
128 assert -2 < coldiff < 2
128 assert -2 < coldiff < 2
129 if coldiff == -1:
129 if coldiff == -1:
130 # Transform
130 # Transform
131 #
131 #
132 # | | | | | |
132 # | | | | | |
133 # o | | into o---+
133 # o | | into o---+
134 # |X / |/ /
134 # |X / |/ /
135 # | | | |
135 # | | | |
136 fix_long_right_edges(edges)
136 fix_long_right_edges(edges)
137
137
138 # add_padding_line says whether to rewrite
138 # add_padding_line says whether to rewrite
139 #
139 #
140 # | | | | | | | |
140 # | | | | | | | |
141 # | o---+ into | o---+
141 # | o---+ into | o---+
142 # | / / | | | # <--- padding line
142 # | / / | | | # <--- padding line
143 # o | | | / /
143 # o | | | / /
144 # o | |
144 # o | |
145 add_padding_line = (len(text) > 2 and coldiff == -1 and
145 add_padding_line = (len(text) > 2 and coldiff == -1 and
146 [x for (x, y) in edges if x + 1 < y])
146 [x for (x, y) in edges if x + 1 < y])
147
147
148 # fix_nodeline_tail says whether to rewrite
148 # fix_nodeline_tail says whether to rewrite
149 #
149 #
150 # | | o | | | | o | |
150 # | | o | | | | o | |
151 # | | |/ / | | |/ /
151 # | | |/ / | | |/ /
152 # | o | | into | o / / # <--- fixed nodeline tail
152 # | o | | into | o / / # <--- fixed nodeline tail
153 # | |/ / | |/ /
153 # | |/ / | |/ /
154 # o | | o | |
154 # o | | o | |
155 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
155 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
156
156
157 # nodeline is the line containing the node character (typically o)
157 # nodeline is the line containing the node character (typically o)
158 nodeline = ["|", " "] * idx
158 nodeline = ["|", " "] * idx
159 nodeline.extend([char, " "])
159 nodeline.extend([char, " "])
160
160
161 nodeline.extend(
161 nodeline.extend(
162 get_nodeline_edges_tail(idx, state[1], ncols, coldiff,
162 get_nodeline_edges_tail(idx, state[1], ncols, coldiff,
163 state[0], fix_nodeline_tail))
163 state[0], fix_nodeline_tail))
164
164
165 # shift_interline is the line containing the non-vertical
165 # shift_interline is the line containing the non-vertical
166 # edges between this entry and the next
166 # edges between this entry and the next
167 shift_interline = ["|", " "] * idx
167 shift_interline = ["|", " "] * idx
168 if coldiff == -1:
168 if coldiff == -1:
169 n_spaces = 1
169 n_spaces = 1
170 edge_ch = "/"
170 edge_ch = "/"
171 elif coldiff == 0:
171 elif coldiff == 0:
172 n_spaces = 2
172 n_spaces = 2
173 edge_ch = "|"
173 edge_ch = "|"
174 else:
174 else:
175 n_spaces = 3
175 n_spaces = 3
176 edge_ch = "\\"
176 edge_ch = "\\"
177 shift_interline.extend(n_spaces * [" "])
177 shift_interline.extend(n_spaces * [" "])
178 shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
178 shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
179
179
180 # draw edges from the current node to its parents
180 # draw edges from the current node to its parents
181 draw_edges(edges, nodeline, shift_interline)
181 draw_edges(edges, nodeline, shift_interline)
182
182
183 # lines is the list of all graph lines to print
183 # lines is the list of all graph lines to print
184 lines = [nodeline]
184 lines = [nodeline]
185 if add_padding_line:
185 if add_padding_line:
186 lines.append(get_padding_line(idx, ncols, edges))
186 lines.append(get_padding_line(idx, ncols, edges))
187 lines.append(shift_interline)
187 lines.append(shift_interline)
188
188
189 # make sure that there are as many graph lines as there are
189 # make sure that there are as many graph lines as there are
190 # log strings
190 # log strings
191 while len(text) < len(lines):
191 while len(text) < len(lines):
192 text.append("")
192 text.append("")
193 if len(lines) < len(text):
193 if len(lines) < len(text):
194 extra_interline = ["|", " "] * (ncols + coldiff)
194 extra_interline = ["|", " "] * (ncols + coldiff)
195 while len(lines) < len(text):
195 while len(lines) < len(text):
196 lines.append(extra_interline)
196 lines.append(extra_interline)
197
197
198 # print lines
198 # print lines
199 indentation_level = max(ncols, ncols + coldiff)
199 indentation_level = max(ncols, ncols + coldiff)
200 for (line, logstr) in zip(lines, text):
200 for (line, logstr) in zip(lines, text):
201 ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr)
201 ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr)
202 ui.write(ln.rstrip() + '\n')
202 ui.write(ln.rstrip() + '\n')
203
203
204 # ... and start over
204 # ... and start over
205 state[0] = coldiff
205 state[0] = coldiff
206 state[1] = idx
206 state[1] = idx
207
207
208 def get_revs(repo, rev_opt):
208 def get_revs(repo, rev_opt):
209 if rev_opt:
209 if rev_opt:
210 revs = revrange(repo, rev_opt)
210 revs = revrange(repo, rev_opt)
211 if len(revs) == 0:
211 if len(revs) == 0:
212 return (nullrev, nullrev)
212 return (nullrev, nullrev)
213 return (max(revs), min(revs))
213 return (max(revs), min(revs))
214 else:
214 else:
215 return (len(repo) - 1, 0)
215 return (len(repo) - 1, 0)
216
216
217 def check_unsupported_flags(opts):
217 def check_unsupported_flags(opts):
218 for op in ["follow_first", "copies", "newest_first"]:
218 for op in ["follow_first", "copies", "newest_first"]:
219 if op in opts and opts[op]:
219 if op in opts and opts[op]:
220 raise util.Abort(_("-G/--graph option is incompatible with --%s")
220 raise util.Abort(_("-G/--graph option is incompatible with --%s")
221 % op.replace("_", "-"))
221 % op.replace("_", "-"))
222
222
223 def revset(pats, opts):
223 def revset(pats, opts):
224 """Return revset str built of revisions, log options and file patterns.
224 """Return revset str built of revisions, log options and file patterns.
225 """
225 """
226 opt2revset = dict(only_merges='merge()',
226 opt2revset = {
227 only_branch='branch($)',
227 'follow': (0, 'follow()'),
228 no_merges='not merge()',
228 'no_merges': (0, 'not merge()'),
229 include='file($)',
229 'only_merges': (0, 'merge()'),
230 exclude='not file($)',
230 'removed': (0, 'removes("*")'),
231 prune='not ($ or ancestors($))',
231 'date': (1, 'date($)'),
232 user='user($)',
232 'branch': (2, 'branch($)'),
233 branch='branch($)',
233 'exclude': (2, 'not file($)'),
234 keyword='keyword($)',
234 'include': (2, 'file($)'),
235 follow='follow()',
235 'keyword': (2, 'keyword($)'),
236 removed='removes("*")')
236 'only_branch': (2, 'branch($)'),
237 opt2revset = dict((k, v.replace('$', '%(val)r'))
237 'prune': (2, 'not ($ or ancestors($))'),
238 for k,v in opt2revset.iteritems())
238 'user': (2, 'user($)'),
239 }
239 revset = []
240 revset = []
240 for op, val in opts.iteritems():
241 for op, val in opts.iteritems():
241 if not val:
242 if not val:
242 continue
243 continue
243 revop = opt2revset.get(op, op)
244 if op == 'rev':
244 if op in ('follow', 'only_merges', 'no_merges', 'removed'):
245 # Already a revset
245 revset.append('%s' % revop)
246 revset.extend(val)
246 elif op in ('date',):
247 if op not in opt2revset:
247 revset.append('%s(%r)' % (revop, val))
248 continue
248 elif op in ('include', 'exclude', 'user', 'branch', 'keyword',
249 arity, revop = opt2revset[op]
249 'prune', 'only_branch'):
250 revop = revop.replace('$', '%(val)r')
251 if arity == 0:
252 revset.append(revop)
253 elif arity == 1:
254 revset.append(revop % {'val': val})
255 else:
250 for f in val:
256 for f in val:
251 revset.append(revop % {'val': f})
257 revset.append(revop % {'val': f})
252 elif op == 'rev':
253 revset.extend(val)
254
258
255 for path in pats:
259 for path in pats:
256 revset.append('file(%r)' % path)
260 revset.append('file(%r)' % path)
257
261
258 revset = ' and '.join(revset) or 'all()'
262 revset = ' and '.join(revset) or 'all()'
259 # we want reverted revset to build graph
263 # we want reverted revset to build graph
260 revset = 'reverse(%s)' % revset
264 revset = 'reverse(%s)' % revset
261 if opts['limit']:
265 if opts['limit']:
262 revset = 'limit(%s, %s)' % (revset, opts['limit'])
266 revset = 'limit(%s, %s)' % (revset, opts['limit'])
263 return revset
267 return revset
264
268
265 def generate(ui, dag, displayer, showparents, edgefn):
269 def generate(ui, dag, displayer, showparents, edgefn):
266 seen, state = [], asciistate()
270 seen, state = [], asciistate()
267 for rev, type, ctx, parents in dag:
271 for rev, type, ctx, parents in dag:
268 char = ctx.node() in showparents and '@' or 'o'
272 char = ctx.node() in showparents and '@' or 'o'
269 displayer.show(ctx)
273 displayer.show(ctx)
270 lines = displayer.hunk.pop(rev).split('\n')[:-1]
274 lines = displayer.hunk.pop(rev).split('\n')[:-1]
271 displayer.flush(rev)
275 displayer.flush(rev)
272 ascii(ui, state, type, char, lines, edgefn(seen, rev, parents))
276 ascii(ui, state, type, char, lines, edgefn(seen, rev, parents))
273 displayer.close()
277 displayer.close()
274
278
275 def graphlog(ui, repo, *pats, **opts):
279 def graphlog(ui, repo, *pats, **opts):
276 """show revision history alongside an ASCII revision graph
280 """show revision history alongside an ASCII revision graph
277
281
278 Print a revision history alongside a revision graph drawn with
282 Print a revision history alongside a revision graph drawn with
279 ASCII characters.
283 ASCII characters.
280
284
281 Nodes printed as an @ character are parents of the working
285 Nodes printed as an @ character are parents of the working
282 directory.
286 directory.
283 """
287 """
284
288
285 check_unsupported_flags(opts)
289 check_unsupported_flags(opts)
286
290
287 revs = revrange(repo, [revset(pats, opts)])
291 revs = revrange(repo, [revset(pats, opts)])
288 revdag = graphmod.dagwalker(repo, revs)
292 revdag = graphmod.dagwalker(repo, revs)
289
293
290 displayer = show_changeset(ui, repo, opts, buffered=True)
294 displayer = show_changeset(ui, repo, opts, buffered=True)
291 showparents = [ctx.node() for ctx in repo[None].parents()]
295 showparents = [ctx.node() for ctx in repo[None].parents()]
292 generate(ui, revdag, displayer, showparents, asciiedges)
296 generate(ui, revdag, displayer, showparents, asciiedges)
293
297
294 def graphrevs(repo, nodes, opts):
298 def graphrevs(repo, nodes, opts):
295 limit = cmdutil.loglimit(opts)
299 limit = cmdutil.loglimit(opts)
296 nodes.reverse()
300 nodes.reverse()
297 if limit is not None:
301 if limit is not None:
298 nodes = nodes[:limit]
302 nodes = nodes[:limit]
299 return graphmod.nodes(repo, nodes)
303 return graphmod.nodes(repo, nodes)
300
304
301 def goutgoing(ui, repo, dest=None, **opts):
305 def goutgoing(ui, repo, dest=None, **opts):
302 """show the outgoing changesets alongside an ASCII revision graph
306 """show the outgoing changesets alongside an ASCII revision graph
303
307
304 Print the outgoing changesets alongside a revision graph drawn with
308 Print the outgoing changesets alongside a revision graph drawn with
305 ASCII characters.
309 ASCII characters.
306
310
307 Nodes printed as an @ character are parents of the working
311 Nodes printed as an @ character are parents of the working
308 directory.
312 directory.
309 """
313 """
310
314
311 check_unsupported_flags(opts)
315 check_unsupported_flags(opts)
312 o = hg._outgoing(ui, repo, dest, opts)
316 o = hg._outgoing(ui, repo, dest, opts)
313 if o is None:
317 if o is None:
314 return
318 return
315
319
316 revdag = graphrevs(repo, o, opts)
320 revdag = graphrevs(repo, o, opts)
317 displayer = show_changeset(ui, repo, opts, buffered=True)
321 displayer = show_changeset(ui, repo, opts, buffered=True)
318 showparents = [ctx.node() for ctx in repo[None].parents()]
322 showparents = [ctx.node() for ctx in repo[None].parents()]
319 generate(ui, revdag, displayer, showparents, asciiedges)
323 generate(ui, revdag, displayer, showparents, asciiedges)
320
324
321 def gincoming(ui, repo, source="default", **opts):
325 def gincoming(ui, repo, source="default", **opts):
322 """show the incoming changesets alongside an ASCII revision graph
326 """show the incoming changesets alongside an ASCII revision graph
323
327
324 Print the incoming changesets alongside a revision graph drawn with
328 Print the incoming changesets alongside a revision graph drawn with
325 ASCII characters.
329 ASCII characters.
326
330
327 Nodes printed as an @ character are parents of the working
331 Nodes printed as an @ character are parents of the working
328 directory.
332 directory.
329 """
333 """
330 def subreporecurse():
334 def subreporecurse():
331 return 1
335 return 1
332
336
333 check_unsupported_flags(opts)
337 check_unsupported_flags(opts)
334 def display(other, chlist, displayer):
338 def display(other, chlist, displayer):
335 revdag = graphrevs(other, chlist, opts)
339 revdag = graphrevs(other, chlist, opts)
336 showparents = [ctx.node() for ctx in repo[None].parents()]
340 showparents = [ctx.node() for ctx in repo[None].parents()]
337 generate(ui, revdag, displayer, showparents, asciiedges)
341 generate(ui, revdag, displayer, showparents, asciiedges)
338
342
339 hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)
343 hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)
340
344
341 def uisetup(ui):
345 def uisetup(ui):
342 '''Initialize the extension.'''
346 '''Initialize the extension.'''
343 _wrapcmd(ui, 'log', commands.table, graphlog)
347 _wrapcmd(ui, 'log', commands.table, graphlog)
344 _wrapcmd(ui, 'incoming', commands.table, gincoming)
348 _wrapcmd(ui, 'incoming', commands.table, gincoming)
345 _wrapcmd(ui, 'outgoing', commands.table, goutgoing)
349 _wrapcmd(ui, 'outgoing', commands.table, goutgoing)
346
350
347 def _wrapcmd(ui, cmd, table, wrapfn):
351 def _wrapcmd(ui, cmd, table, wrapfn):
348 '''wrap the command'''
352 '''wrap the command'''
349 def graph(orig, *args, **kwargs):
353 def graph(orig, *args, **kwargs):
350 if kwargs['graph']:
354 if kwargs['graph']:
351 return wrapfn(*args, **kwargs)
355 return wrapfn(*args, **kwargs)
352 return orig(*args, **kwargs)
356 return orig(*args, **kwargs)
353 entry = extensions.wrapcommand(table, cmd, graph)
357 entry = extensions.wrapcommand(table, cmd, graph)
354 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
358 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
355
359
356 cmdtable = {
360 cmdtable = {
357 "glog":
361 "glog":
358 (graphlog,
362 (graphlog,
359 [('l', 'limit', '',
363 [('l', 'limit', '',
360 _('limit number of changes displayed'), _('NUM')),
364 _('limit number of changes displayed'), _('NUM')),
361 ('p', 'patch', False, _('show patch')),
365 ('p', 'patch', False, _('show patch')),
362 ('r', 'rev', [],
366 ('r', 'rev', [],
363 _('show the specified revision or range'), _('REV')),
367 _('show the specified revision or range'), _('REV')),
364 ] + templateopts,
368 ] + templateopts,
365 _('hg glog [OPTION]... [FILE]')),
369 _('hg glog [OPTION]... [FILE]')),
366 }
370 }
General Comments 0
You need to be logged in to leave comments. Login now