##// END OF EJS Templates
graphlog: evaluate FILE/-I/-X filesets on the working dir...
Patrick Mezard -
r16181:1fd352aa default
parent child Browse files
Show More
@@ -1,467 +1,469 b''
1 1 # ASCII graph log extension for Mercurial
2 2 #
3 3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''command to view revision graphs from a shell
9 9
10 10 This extension adds a --graph option to the incoming, outgoing and log
11 11 commands. When this options is given, an ASCII representation of the
12 12 revision graph is also shown.
13 13 '''
14 14
15 15 from mercurial.cmdutil import show_changeset
16 16 from mercurial.commands import templateopts
17 17 from mercurial.i18n import _
18 18 from mercurial.node import nullrev
19 19 from mercurial import cmdutil, commands, extensions, scmutil
20 20 from mercurial import hg, util, graphmod, templatekw
21 21
22 22 cmdtable = {}
23 23 command = cmdutil.command(cmdtable)
24 24
25 25 ASCIIDATA = 'ASC'
26 26
27 27 def asciiedges(type, char, lines, seen, rev, parents):
28 28 """adds edge info to changelog DAG walk suitable for ascii()"""
29 29 if rev not in seen:
30 30 seen.append(rev)
31 31 nodeidx = seen.index(rev)
32 32
33 33 knownparents = []
34 34 newparents = []
35 35 for parent in parents:
36 36 if parent in seen:
37 37 knownparents.append(parent)
38 38 else:
39 39 newparents.append(parent)
40 40
41 41 ncols = len(seen)
42 42 nextseen = seen[:]
43 43 nextseen[nodeidx:nodeidx + 1] = newparents
44 44 edges = [(nodeidx, nextseen.index(p)) for p in knownparents]
45 45
46 46 while len(newparents) > 2:
47 47 # ascii() only knows how to add or remove a single column between two
48 48 # calls. Nodes with more than two parents break this constraint so we
49 49 # introduce intermediate expansion lines to grow the active node list
50 50 # slowly.
51 51 edges.append((nodeidx, nodeidx))
52 52 edges.append((nodeidx, nodeidx + 1))
53 53 nmorecols = 1
54 54 yield (type, char, lines, (nodeidx, edges, ncols, nmorecols))
55 55 char = '\\'
56 56 lines = []
57 57 nodeidx += 1
58 58 ncols += 1
59 59 edges = []
60 60 del newparents[0]
61 61
62 62 if len(newparents) > 0:
63 63 edges.append((nodeidx, nodeidx))
64 64 if len(newparents) > 1:
65 65 edges.append((nodeidx, nodeidx + 1))
66 66 nmorecols = len(nextseen) - ncols
67 67 seen[:] = nextseen
68 68 yield (type, char, lines, (nodeidx, edges, ncols, nmorecols))
69 69
70 70 def fix_long_right_edges(edges):
71 71 for (i, (start, end)) in enumerate(edges):
72 72 if end > start:
73 73 edges[i] = (start, end + 1)
74 74
75 75 def get_nodeline_edges_tail(
76 76 node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
77 77 if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
78 78 # Still going in the same non-vertical direction.
79 79 if n_columns_diff == -1:
80 80 start = max(node_index + 1, p_node_index)
81 81 tail = ["|", " "] * (start - node_index - 1)
82 82 tail.extend(["/", " "] * (n_columns - start))
83 83 return tail
84 84 else:
85 85 return ["\\", " "] * (n_columns - node_index - 1)
86 86 else:
87 87 return ["|", " "] * (n_columns - node_index - 1)
88 88
89 89 def draw_edges(edges, nodeline, interline):
90 90 for (start, end) in edges:
91 91 if start == end + 1:
92 92 interline[2 * end + 1] = "/"
93 93 elif start == end - 1:
94 94 interline[2 * start + 1] = "\\"
95 95 elif start == end:
96 96 interline[2 * start] = "|"
97 97 else:
98 98 if 2 * end >= len(nodeline):
99 99 continue
100 100 nodeline[2 * end] = "+"
101 101 if start > end:
102 102 (start, end) = (end, start)
103 103 for i in range(2 * start + 1, 2 * end):
104 104 if nodeline[i] != "+":
105 105 nodeline[i] = "-"
106 106
107 107 def get_padding_line(ni, n_columns, edges):
108 108 line = []
109 109 line.extend(["|", " "] * ni)
110 110 if (ni, ni - 1) in edges or (ni, ni) in edges:
111 111 # (ni, ni - 1) (ni, ni)
112 112 # | | | | | | | |
113 113 # +---o | | o---+
114 114 # | | c | | c | |
115 115 # | |/ / | |/ /
116 116 # | | | | | |
117 117 c = "|"
118 118 else:
119 119 c = " "
120 120 line.extend([c, " "])
121 121 line.extend(["|", " "] * (n_columns - ni - 1))
122 122 return line
123 123
124 124 def asciistate():
125 125 """returns the initial value for the "state" argument to ascii()"""
126 126 return [0, 0]
127 127
128 128 def ascii(ui, state, type, char, text, coldata):
129 129 """prints an ASCII graph of the DAG
130 130
131 131 takes the following arguments (one call per node in the graph):
132 132
133 133 - ui to write to
134 134 - Somewhere to keep the needed state in (init to asciistate())
135 135 - Column of the current node in the set of ongoing edges.
136 136 - Type indicator of node data == ASCIIDATA.
137 137 - Payload: (char, lines):
138 138 - Character to use as node's symbol.
139 139 - List of lines to display as the node's text.
140 140 - Edges; a list of (col, next_col) indicating the edges between
141 141 the current node and its parents.
142 142 - Number of columns (ongoing edges) in the current revision.
143 143 - The difference between the number of columns (ongoing edges)
144 144 in the next revision and the number of columns (ongoing edges)
145 145 in the current revision. That is: -1 means one column removed;
146 146 0 means no columns added or removed; 1 means one column added.
147 147 """
148 148
149 149 idx, edges, ncols, coldiff = coldata
150 150 assert -2 < coldiff < 2
151 151 if coldiff == -1:
152 152 # Transform
153 153 #
154 154 # | | | | | |
155 155 # o | | into o---+
156 156 # |X / |/ /
157 157 # | | | |
158 158 fix_long_right_edges(edges)
159 159
160 160 # add_padding_line says whether to rewrite
161 161 #
162 162 # | | | | | | | |
163 163 # | o---+ into | o---+
164 164 # | / / | | | # <--- padding line
165 165 # o | | | / /
166 166 # o | |
167 167 add_padding_line = (len(text) > 2 and coldiff == -1 and
168 168 [x for (x, y) in edges if x + 1 < y])
169 169
170 170 # fix_nodeline_tail says whether to rewrite
171 171 #
172 172 # | | o | | | | o | |
173 173 # | | |/ / | | |/ /
174 174 # | o | | into | o / / # <--- fixed nodeline tail
175 175 # | |/ / | |/ /
176 176 # o | | o | |
177 177 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
178 178
179 179 # nodeline is the line containing the node character (typically o)
180 180 nodeline = ["|", " "] * idx
181 181 nodeline.extend([char, " "])
182 182
183 183 nodeline.extend(
184 184 get_nodeline_edges_tail(idx, state[1], ncols, coldiff,
185 185 state[0], fix_nodeline_tail))
186 186
187 187 # shift_interline is the line containing the non-vertical
188 188 # edges between this entry and the next
189 189 shift_interline = ["|", " "] * idx
190 190 if coldiff == -1:
191 191 n_spaces = 1
192 192 edge_ch = "/"
193 193 elif coldiff == 0:
194 194 n_spaces = 2
195 195 edge_ch = "|"
196 196 else:
197 197 n_spaces = 3
198 198 edge_ch = "\\"
199 199 shift_interline.extend(n_spaces * [" "])
200 200 shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
201 201
202 202 # draw edges from the current node to its parents
203 203 draw_edges(edges, nodeline, shift_interline)
204 204
205 205 # lines is the list of all graph lines to print
206 206 lines = [nodeline]
207 207 if add_padding_line:
208 208 lines.append(get_padding_line(idx, ncols, edges))
209 209 lines.append(shift_interline)
210 210
211 211 # make sure that there are as many graph lines as there are
212 212 # log strings
213 213 while len(text) < len(lines):
214 214 text.append("")
215 215 if len(lines) < len(text):
216 216 extra_interline = ["|", " "] * (ncols + coldiff)
217 217 while len(lines) < len(text):
218 218 lines.append(extra_interline)
219 219
220 220 # print lines
221 221 indentation_level = max(ncols, ncols + coldiff)
222 222 for (line, logstr) in zip(lines, text):
223 223 ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr)
224 224 ui.write(ln.rstrip() + '\n')
225 225
226 226 # ... and start over
227 227 state[0] = coldiff
228 228 state[1] = idx
229 229
230 230 def get_revs(repo, rev_opt):
231 231 if rev_opt:
232 232 revs = scmutil.revrange(repo, rev_opt)
233 233 if len(revs) == 0:
234 234 return (nullrev, nullrev)
235 235 return (max(revs), min(revs))
236 236 else:
237 237 return (len(repo) - 1, 0)
238 238
239 239 def check_unsupported_flags(pats, opts):
240 240 for op in ["newest_first"]:
241 241 if op in opts and opts[op]:
242 242 raise util.Abort(_("-G/--graph option is incompatible with --%s")
243 243 % op.replace("_", "-"))
244 244
245 245 def revset(repo, pats, opts):
246 246 """Return revset str built of revisions, log options and file patterns.
247 247 """
248 248 opt2revset = {
249 249 'follow': ('follow()', None),
250 250 'follow_first': ('_followfirst()', None),
251 251 'no_merges': ('not merge()', None),
252 252 'only_merges': ('merge()', None),
253 253 'removed': ('removes("*")', None),
254 254 'date': ('date(%(val)r)', None),
255 255 'branch': ('branch(%(val)r)', ' or '),
256 256 '_patslog': ('filelog(%(val)r)', ' or '),
257 257 '_patsfollow': ('follow(%(val)r)', ' or '),
258 258 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
259 259 'keyword': ('keyword(%(val)r)', ' or '),
260 260 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
261 261 'user': ('user(%(val)r)', ' or '),
262 262 'rev': ('%(val)s', ' or '),
263 263 }
264 264
265 265 opts = dict(opts)
266 266 # branch and only_branch are really aliases and must be handled at
267 267 # the same time
268 268 if 'branch' in opts and 'only_branch' in opts:
269 269 opts['branch'] = opts['branch'] + opts.pop('only_branch')
270 270
271 271 follow = opts.get('follow') or opts.get('follow_first')
272 272 followfirst = opts.get('follow_first')
273 273 if 'follow' in opts:
274 274 del opts['follow']
275 275 if 'follow_first' in opts:
276 276 del opts['follow_first']
277 277 # pats/include/exclude are passed to match.match() directly in
278 278 # _matchfile() revset but walkchangerevs() builds its matcher with
279 279 # scmutil.match(). The difference is input pats are globbed on
280 280 # platforms without shell expansion (windows).
281 281 pctx = repo[None]
282 282 match, pats = scmutil.matchandpats(pctx, pats, opts)
283 283 slowpath = match.anypats() or (match.files() and opts.get('removed'))
284 284 if not slowpath:
285 285 for f in match.files():
286 286 if follow and f not in pctx:
287 287 raise util.Abort(_('cannot follow file not in parent '
288 288 'revision: "%s"') % f)
289 289 filelog = repo.file(f)
290 290 if not len(filelog):
291 291 # A zero count may be a directory or deleted file, so
292 292 # try to find matching entries on the slow path.
293 293 if follow:
294 294 raise util.Abort(
295 295 _('cannot follow nonexistent file: "%s"') % f)
296 296 slowpath = True
297 297 if slowpath:
298 298 # See cmdutil.walkchangerevs() slow path.
299 299 #
300 300 if follow:
301 301 raise util.Abort(_('can only follow copies/renames for explicit '
302 302 'filenames'))
303 303 # pats/include/exclude cannot be represented as separate
304 304 # revset expressions as their filtering logic applies at file
305 305 # level. For instance "-I a -X a" matches a revision touching
306 # "a" and "b" while "file(a) and not file(b)" does not.
307 matchargs = []
306 # "a" and "b" while "file(a) and not file(b)" does
307 # not. Besides, filesets are evaluated against the working
308 # directory.
309 matchargs = ['r:']
308 310 for p in pats:
309 311 matchargs.append('p:' + p)
310 312 for p in opts.get('include', []):
311 313 matchargs.append('i:' + p)
312 314 for p in opts.get('exclude', []):
313 315 matchargs.append('x:' + p)
314 316 matchargs = ','.join(('%r' % p) for p in matchargs)
315 317 opts['rev'] = opts.get('rev', []) + ['_matchfiles(%s)' % matchargs]
316 318 else:
317 319 if follow:
318 320 if followfirst:
319 321 if pats:
320 322 opts['_patsfollowfirst'] = list(pats)
321 323 else:
322 324 opts['follow_first'] = True
323 325 else:
324 326 if pats:
325 327 opts['_patsfollow'] = list(pats)
326 328 else:
327 329 opts['follow'] = True
328 330 else:
329 331 opts['_patslog'] = list(pats)
330 332
331 333 revset = []
332 334 for op, val in opts.iteritems():
333 335 if not val:
334 336 continue
335 337 if op not in opt2revset:
336 338 continue
337 339 revop, andor = opt2revset[op]
338 340 if '%(val)' not in revop:
339 341 revset.append(revop)
340 342 else:
341 343 if not isinstance(val, list):
342 344 expr = revop % {'val': val}
343 345 else:
344 346 expr = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
345 347 revset.append(expr)
346 348
347 349 if revset:
348 350 revset = '(' + ' and '.join(revset) + ')'
349 351 else:
350 352 revset = 'all()'
351 353 return revset
352 354
353 355 def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None):
354 356 seen, state = [], asciistate()
355 357 for rev, type, ctx, parents in dag:
356 358 char = ctx.node() in showparents and '@' or 'o'
357 359 copies = None
358 360 if getrenamed and ctx.rev():
359 361 copies = []
360 362 for fn in ctx.files():
361 363 rename = getrenamed(fn, ctx.rev())
362 364 if rename:
363 365 copies.append((fn, rename[0]))
364 366 displayer.show(ctx, copies=copies)
365 367 lines = displayer.hunk.pop(rev).split('\n')[:-1]
366 368 displayer.flush(rev)
367 369 edges = edgefn(type, char, lines, seen, rev, parents)
368 370 for type, char, lines, coldata in edges:
369 371 ascii(ui, state, type, char, lines, coldata)
370 372 displayer.close()
371 373
372 374 @command('glog',
373 375 [('l', 'limit', '',
374 376 _('limit number of changes displayed'), _('NUM')),
375 377 ('p', 'patch', False, _('show patch')),
376 378 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
377 379 ] + templateopts,
378 380 _('hg glog [OPTION]... [FILE]'))
379 381 def graphlog(ui, repo, *pats, **opts):
380 382 """show revision history alongside an ASCII revision graph
381 383
382 384 Print a revision history alongside a revision graph drawn with
383 385 ASCII characters.
384 386
385 387 Nodes printed as an @ character are parents of the working
386 388 directory.
387 389 """
388 390
389 391 check_unsupported_flags(pats, opts)
390 392
391 393 revs = sorted(scmutil.revrange(repo, [revset(repo, pats, opts)]), reverse=1)
392 394 limit = cmdutil.loglimit(opts)
393 395 if limit is not None:
394 396 revs = revs[:limit]
395 397 revdag = graphmod.dagwalker(repo, revs)
396 398
397 399 getrenamed = None
398 400 if opts.get('copies'):
399 401 endrev = None
400 402 if opts.get('rev'):
401 403 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
402 404 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
403 405 displayer = show_changeset(ui, repo, opts, buffered=True)
404 406 showparents = [ctx.node() for ctx in repo[None].parents()]
405 407 generate(ui, revdag, displayer, showparents, asciiedges, getrenamed)
406 408
407 409 def graphrevs(repo, nodes, opts):
408 410 limit = cmdutil.loglimit(opts)
409 411 nodes.reverse()
410 412 if limit is not None:
411 413 nodes = nodes[:limit]
412 414 return graphmod.nodes(repo, nodes)
413 415
414 416 def goutgoing(ui, repo, dest=None, **opts):
415 417 """show the outgoing changesets alongside an ASCII revision graph
416 418
417 419 Print the outgoing changesets alongside a revision graph drawn with
418 420 ASCII characters.
419 421
420 422 Nodes printed as an @ character are parents of the working
421 423 directory.
422 424 """
423 425
424 426 check_unsupported_flags([], opts)
425 427 o = hg._outgoing(ui, repo, dest, opts)
426 428 if o is None:
427 429 return
428 430
429 431 revdag = graphrevs(repo, o, opts)
430 432 displayer = show_changeset(ui, repo, opts, buffered=True)
431 433 showparents = [ctx.node() for ctx in repo[None].parents()]
432 434 generate(ui, revdag, displayer, showparents, asciiedges)
433 435
434 436 def gincoming(ui, repo, source="default", **opts):
435 437 """show the incoming changesets alongside an ASCII revision graph
436 438
437 439 Print the incoming changesets alongside a revision graph drawn with
438 440 ASCII characters.
439 441
440 442 Nodes printed as an @ character are parents of the working
441 443 directory.
442 444 """
443 445 def subreporecurse():
444 446 return 1
445 447
446 448 check_unsupported_flags([], opts)
447 449 def display(other, chlist, displayer):
448 450 revdag = graphrevs(other, chlist, opts)
449 451 showparents = [ctx.node() for ctx in repo[None].parents()]
450 452 generate(ui, revdag, displayer, showparents, asciiedges)
451 453
452 454 hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)
453 455
454 456 def uisetup(ui):
455 457 '''Initialize the extension.'''
456 458 _wrapcmd('log', commands.table, graphlog)
457 459 _wrapcmd('incoming', commands.table, gincoming)
458 460 _wrapcmd('outgoing', commands.table, goutgoing)
459 461
460 462 def _wrapcmd(cmd, table, wrapfn):
461 463 '''wrap the command'''
462 464 def graph(orig, *args, **kwargs):
463 465 if kwargs['graph']:
464 466 return wrapfn(*args, **kwargs)
465 467 return orig(*args, **kwargs)
466 468 entry = extensions.wrapcommand(table, cmd, graph)
467 469 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
@@ -1,1329 +1,1341 b''
1 1 # revset.py - revision set queries for mercurial
2 2 #
3 3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import re
9 9 import parser, util, error, discovery, hbisect, phases
10 10 import node as nodemod
11 11 import bookmarks as bookmarksmod
12 12 import match as matchmod
13 13 from i18n import _
14 14 import encoding
15 15
16 16 elements = {
17 17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
18 18 "~": (18, None, ("ancestor", 18)),
19 19 "^": (18, None, ("parent", 18), ("parentpost", 18)),
20 20 "-": (5, ("negate", 19), ("minus", 5)),
21 21 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
22 22 ("dagrangepost", 17)),
23 23 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
24 24 ("dagrangepost", 17)),
25 25 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
26 26 "not": (10, ("not", 10)),
27 27 "!": (10, ("not", 10)),
28 28 "and": (5, None, ("and", 5)),
29 29 "&": (5, None, ("and", 5)),
30 30 "or": (4, None, ("or", 4)),
31 31 "|": (4, None, ("or", 4)),
32 32 "+": (4, None, ("or", 4)),
33 33 ",": (2, None, ("list", 2)),
34 34 ")": (0, None, None),
35 35 "symbol": (0, ("symbol",), None),
36 36 "string": (0, ("string",), None),
37 37 "end": (0, None, None),
38 38 }
39 39
40 40 keywords = set(['and', 'or', 'not'])
41 41
42 42 def tokenize(program):
43 43 pos, l = 0, len(program)
44 44 while pos < l:
45 45 c = program[pos]
46 46 if c.isspace(): # skip inter-token whitespace
47 47 pass
48 48 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
49 49 yield ('::', None, pos)
50 50 pos += 1 # skip ahead
51 51 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
52 52 yield ('..', None, pos)
53 53 pos += 1 # skip ahead
54 54 elif c in "():,-|&+!~^": # handle simple operators
55 55 yield (c, None, pos)
56 56 elif (c in '"\'' or c == 'r' and
57 57 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
58 58 if c == 'r':
59 59 pos += 1
60 60 c = program[pos]
61 61 decode = lambda x: x
62 62 else:
63 63 decode = lambda x: x.decode('string-escape')
64 64 pos += 1
65 65 s = pos
66 66 while pos < l: # find closing quote
67 67 d = program[pos]
68 68 if d == '\\': # skip over escaped characters
69 69 pos += 2
70 70 continue
71 71 if d == c:
72 72 yield ('string', decode(program[s:pos]), s)
73 73 break
74 74 pos += 1
75 75 else:
76 76 raise error.ParseError(_("unterminated string"), s)
77 77 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
78 78 s = pos
79 79 pos += 1
80 80 while pos < l: # find end of symbol
81 81 d = program[pos]
82 82 if not (d.isalnum() or d in "._/" or ord(d) > 127):
83 83 break
84 84 if d == '.' and program[pos - 1] == '.': # special case for ..
85 85 pos -= 1
86 86 break
87 87 pos += 1
88 88 sym = program[s:pos]
89 89 if sym in keywords: # operator keywords
90 90 yield (sym, None, s)
91 91 else:
92 92 yield ('symbol', sym, s)
93 93 pos -= 1
94 94 else:
95 95 raise error.ParseError(_("syntax error"), pos)
96 96 pos += 1
97 97 yield ('end', None, pos)
98 98
99 99 # helpers
100 100
101 101 def getstring(x, err):
102 102 if x and (x[0] == 'string' or x[0] == 'symbol'):
103 103 return x[1]
104 104 raise error.ParseError(err)
105 105
106 106 def getlist(x):
107 107 if not x:
108 108 return []
109 109 if x[0] == 'list':
110 110 return getlist(x[1]) + [x[2]]
111 111 return [x]
112 112
113 113 def getargs(x, min, max, err):
114 114 l = getlist(x)
115 115 if len(l) < min or (max >= 0 and len(l) > max):
116 116 raise error.ParseError(err)
117 117 return l
118 118
119 119 def getset(repo, subset, x):
120 120 if not x:
121 121 raise error.ParseError(_("missing argument"))
122 122 return methods[x[0]](repo, subset, *x[1:])
123 123
124 124 # operator methods
125 125
126 126 def stringset(repo, subset, x):
127 127 x = repo[x].rev()
128 128 if x == -1 and len(subset) == len(repo):
129 129 return [-1]
130 130 if len(subset) == len(repo) or x in subset:
131 131 return [x]
132 132 return []
133 133
134 134 def symbolset(repo, subset, x):
135 135 if x in symbols:
136 136 raise error.ParseError(_("can't use %s here") % x)
137 137 return stringset(repo, subset, x)
138 138
139 139 def rangeset(repo, subset, x, y):
140 140 m = getset(repo, subset, x)
141 141 if not m:
142 142 m = getset(repo, range(len(repo)), x)
143 143
144 144 n = getset(repo, subset, y)
145 145 if not n:
146 146 n = getset(repo, range(len(repo)), y)
147 147
148 148 if not m or not n:
149 149 return []
150 150 m, n = m[0], n[-1]
151 151
152 152 if m < n:
153 153 r = range(m, n + 1)
154 154 else:
155 155 r = range(m, n - 1, -1)
156 156 s = set(subset)
157 157 return [x for x in r if x in s]
158 158
159 159 def andset(repo, subset, x, y):
160 160 return getset(repo, getset(repo, subset, x), y)
161 161
162 162 def orset(repo, subset, x, y):
163 163 xl = getset(repo, subset, x)
164 164 s = set(xl)
165 165 yl = getset(repo, [r for r in subset if r not in s], y)
166 166 return xl + yl
167 167
168 168 def notset(repo, subset, x):
169 169 s = set(getset(repo, subset, x))
170 170 return [r for r in subset if r not in s]
171 171
172 172 def listset(repo, subset, a, b):
173 173 raise error.ParseError(_("can't use a list in this context"))
174 174
175 175 def func(repo, subset, a, b):
176 176 if a[0] == 'symbol' and a[1] in symbols:
177 177 return symbols[a[1]](repo, subset, b)
178 178 raise error.ParseError(_("not a function: %s") % a[1])
179 179
180 180 # functions
181 181
182 182 def adds(repo, subset, x):
183 183 """``adds(pattern)``
184 184 Changesets that add a file matching pattern.
185 185 """
186 186 # i18n: "adds" is a keyword
187 187 pat = getstring(x, _("adds requires a pattern"))
188 188 return checkstatus(repo, subset, pat, 1)
189 189
190 190 def ancestor(repo, subset, x):
191 191 """``ancestor(single, single)``
192 192 Greatest common ancestor of the two changesets.
193 193 """
194 194 # i18n: "ancestor" is a keyword
195 195 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
196 196 r = range(len(repo))
197 197 a = getset(repo, r, l[0])
198 198 b = getset(repo, r, l[1])
199 199 if len(a) != 1 or len(b) != 1:
200 200 # i18n: "ancestor" is a keyword
201 201 raise error.ParseError(_("ancestor arguments must be single revisions"))
202 202 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
203 203
204 204 return [r for r in an if r in subset]
205 205
206 206 def ancestors(repo, subset, x):
207 207 """``ancestors(set)``
208 208 Changesets that are ancestors of a changeset in set.
209 209 """
210 210 args = getset(repo, range(len(repo)), x)
211 211 if not args:
212 212 return []
213 213 s = set(repo.changelog.ancestors(*args)) | set(args)
214 214 return [r for r in subset if r in s]
215 215
216 216 def ancestorspec(repo, subset, x, n):
217 217 """``set~n``
218 218 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
219 219 """
220 220 try:
221 221 n = int(n[1])
222 222 except (TypeError, ValueError):
223 223 raise error.ParseError(_("~ expects a number"))
224 224 ps = set()
225 225 cl = repo.changelog
226 226 for r in getset(repo, subset, x):
227 227 for i in range(n):
228 228 r = cl.parentrevs(r)[0]
229 229 ps.add(r)
230 230 return [r for r in subset if r in ps]
231 231
232 232 def author(repo, subset, x):
233 233 """``author(string)``
234 234 Alias for ``user(string)``.
235 235 """
236 236 # i18n: "author" is a keyword
237 237 n = encoding.lower(getstring(x, _("author requires a string")))
238 238 return [r for r in subset if n in encoding.lower(repo[r].user())]
239 239
240 240 def bisect(repo, subset, x):
241 241 """``bisect(string)``
242 242 Changesets marked in the specified bisect status:
243 243
244 244 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
245 245 - ``goods``, ``bads`` : csets topologicaly good/bad
246 246 - ``range`` : csets taking part in the bisection
247 247 - ``pruned`` : csets that are goods, bads or skipped
248 248 - ``untested`` : csets whose fate is yet unknown
249 249 - ``ignored`` : csets ignored due to DAG topology
250 250 """
251 251 status = getstring(x, _("bisect requires a string")).lower()
252 252 return [r for r in subset if r in hbisect.get(repo, status)]
253 253
254 254 # Backward-compatibility
255 255 # - no help entry so that we do not advertise it any more
256 256 def bisected(repo, subset, x):
257 257 return bisect(repo, subset, x)
258 258
259 259 def bookmark(repo, subset, x):
260 260 """``bookmark([name])``
261 261 The named bookmark or all bookmarks.
262 262 """
263 263 # i18n: "bookmark" is a keyword
264 264 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
265 265 if args:
266 266 bm = getstring(args[0],
267 267 # i18n: "bookmark" is a keyword
268 268 _('the argument to bookmark must be a string'))
269 269 bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
270 270 if not bmrev:
271 271 raise util.Abort(_("bookmark '%s' does not exist") % bm)
272 272 bmrev = repo[bmrev].rev()
273 273 return [r for r in subset if r == bmrev]
274 274 bms = set([repo[r].rev()
275 275 for r in bookmarksmod.listbookmarks(repo).values()])
276 276 return [r for r in subset if r in bms]
277 277
278 278 def branch(repo, subset, x):
279 279 """``branch(string or set)``
280 280 All changesets belonging to the given branch or the branches of the given
281 281 changesets.
282 282 """
283 283 try:
284 284 b = getstring(x, '')
285 285 if b in repo.branchmap():
286 286 return [r for r in subset if repo[r].branch() == b]
287 287 except error.ParseError:
288 288 # not a string, but another revspec, e.g. tip()
289 289 pass
290 290
291 291 s = getset(repo, range(len(repo)), x)
292 292 b = set()
293 293 for r in s:
294 294 b.add(repo[r].branch())
295 295 s = set(s)
296 296 return [r for r in subset if r in s or repo[r].branch() in b]
297 297
298 298 def checkstatus(repo, subset, pat, field):
299 299 m = None
300 300 s = []
301 301 fast = not matchmod.patkind(pat)
302 302 for r in subset:
303 303 c = repo[r]
304 304 if fast:
305 305 if pat not in c.files():
306 306 continue
307 307 else:
308 308 if not m or matchmod.patkind(pat) == 'set':
309 309 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
310 310 for f in c.files():
311 311 if m(f):
312 312 break
313 313 else:
314 314 continue
315 315 files = repo.status(c.p1().node(), c.node())[field]
316 316 if fast:
317 317 if pat in files:
318 318 s.append(r)
319 319 else:
320 320 for f in files:
321 321 if m(f):
322 322 s.append(r)
323 323 break
324 324 return s
325 325
326 326 def _children(repo, narrow, s):
327 327 cs = set()
328 328 pr = repo.changelog.parentrevs
329 329 s = set(s)
330 330 for r in xrange(len(repo)):
331 331 for p in pr(r):
332 332 if p in s:
333 333 cs.add(r)
334 334 return cs
335 335
336 336 def children(repo, subset, x):
337 337 """``children(set)``
338 338 Child changesets of changesets in set.
339 339 """
340 340 s = getset(repo, range(len(repo)), x)
341 341 cs = _children(repo, subset, s)
342 342 return [r for r in subset if r in cs]
343 343
344 344 def closed(repo, subset, x):
345 345 """``closed()``
346 346 Changeset is closed.
347 347 """
348 348 # i18n: "closed" is a keyword
349 349 getargs(x, 0, 0, _("closed takes no arguments"))
350 350 return [r for r in subset if repo[r].extra().get('close')]
351 351
352 352 def contains(repo, subset, x):
353 353 """``contains(pattern)``
354 354 Revision contains a file matching pattern. See :hg:`help patterns`
355 355 for information about file patterns.
356 356 """
357 357 # i18n: "contains" is a keyword
358 358 pat = getstring(x, _("contains requires a pattern"))
359 359 m = None
360 360 s = []
361 361 if not matchmod.patkind(pat):
362 362 for r in subset:
363 363 if pat in repo[r]:
364 364 s.append(r)
365 365 else:
366 366 for r in subset:
367 367 c = repo[r]
368 368 if not m or matchmod.patkind(pat) == 'set':
369 369 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
370 370 for f in c.manifest():
371 371 if m(f):
372 372 s.append(r)
373 373 break
374 374 return s
375 375
376 376 def date(repo, subset, x):
377 377 """``date(interval)``
378 378 Changesets within the interval, see :hg:`help dates`.
379 379 """
380 380 # i18n: "date" is a keyword
381 381 ds = getstring(x, _("date requires a string"))
382 382 dm = util.matchdate(ds)
383 383 return [r for r in subset if dm(repo[r].date()[0])]
384 384
385 385 def desc(repo, subset, x):
386 386 """``desc(string)``
387 387 Search commit message for string. The match is case-insensitive.
388 388 """
389 389 # i18n: "desc" is a keyword
390 390 ds = encoding.lower(getstring(x, _("desc requires a string")))
391 391 l = []
392 392 for r in subset:
393 393 c = repo[r]
394 394 if ds in encoding.lower(c.description()):
395 395 l.append(r)
396 396 return l
397 397
398 398 def descendants(repo, subset, x):
399 399 """``descendants(set)``
400 400 Changesets which are descendants of changesets in set.
401 401 """
402 402 args = getset(repo, range(len(repo)), x)
403 403 if not args:
404 404 return []
405 405 s = set(repo.changelog.descendants(*args)) | set(args)
406 406 return [r for r in subset if r in s]
407 407
408 408 def draft(repo, subset, x):
409 409 """``draft()``
410 410 Changeset in draft phase."""
411 411 getargs(x, 0, 0, _("draft takes no arguments"))
412 412 return [r for r in subset if repo._phaserev[r] == phases.draft]
413 413
414 414 def filelog(repo, subset, x):
415 415 """``filelog(pattern)``
416 416 Changesets connected to the specified filelog.
417 417 """
418 418
419 419 pat = getstring(x, _("filelog requires a pattern"))
420 420 m = matchmod.match(repo.root, repo.getcwd(), [pat], default='relpath',
421 421 ctx=repo[None])
422 422 s = set()
423 423
424 424 if not matchmod.patkind(pat):
425 425 for f in m.files():
426 426 fl = repo.file(f)
427 427 for fr in fl:
428 428 s.add(fl.linkrev(fr))
429 429 else:
430 430 for f in repo[None]:
431 431 if m(f):
432 432 fl = repo.file(f)
433 433 for fr in fl:
434 434 s.add(fl.linkrev(fr))
435 435
436 436 return [r for r in subset if r in s]
437 437
438 438 def first(repo, subset, x):
439 439 """``first(set, [n])``
440 440 An alias for limit().
441 441 """
442 442 return limit(repo, subset, x)
443 443
444 444 def follow(repo, subset, x):
445 445 """``follow([file])``
446 446 An alias for ``::.`` (ancestors of the working copy's first parent).
447 447 If a filename is specified, the history of the given file is followed,
448 448 including copies.
449 449 """
450 450 # i18n: "follow" is a keyword
451 451 l = getargs(x, 0, 1, _("follow takes no arguments or a filename"))
452 452 c = repo['.']
453 453 if l:
454 454 x = getstring(l[0], _("follow expected a filename"))
455 455 if x in c:
456 456 cx = c[x]
457 457 s = set(ctx.rev() for ctx in cx.ancestors())
458 458 # include the revision responsible for the most recent version
459 459 s.add(cx.linkrev())
460 460 else:
461 461 return []
462 462 else:
463 463 s = set(repo.changelog.ancestors(c.rev()))
464 464 s.add(c.rev())
465 465
466 466 return [r for r in subset if r in s]
467 467
468 468 def _followfirst(repo, subset, x):
469 469 # ``followfirst([file])``
470 470 # Like ``follow([file])`` but follows only the first parent of
471 471 # every revision or file revision.
472 472 # i18n: "_followfirst" is a keyword
473 473 l = getargs(x, 0, 1, _("_followfirst takes no arguments or a filename"))
474 474 c = repo['.']
475 475 if l:
476 476 x = getstring(l[0], _("_followfirst expected a filename"))
477 477 if x not in c:
478 478 return []
479 479 cx = c[x]
480 480 visit = {}
481 481 s = set([cx.linkrev()])
482 482 while True:
483 483 for p in cx.parents()[:1]:
484 484 visit[(p.rev(), p.node())] = p
485 485 if not visit:
486 486 break
487 487 cx = visit.pop(max(visit))
488 488 s.add(cx.rev())
489 489 else:
490 490 cl = repo.changelog
491 491 s = set()
492 492 visit = [c.rev()]
493 493 while visit:
494 494 for prev in cl.parentrevs(visit.pop(0))[:1]:
495 495 if prev not in s and prev != nodemod.nullrev:
496 496 visit.append(prev)
497 497 s.add(prev)
498 498 s.add(c.rev())
499 499
500 500 return [r for r in subset if r in s]
501 501
502 502 def getall(repo, subset, x):
503 503 """``all()``
504 504 All changesets, the same as ``0:tip``.
505 505 """
506 506 # i18n: "all" is a keyword
507 507 getargs(x, 0, 0, _("all takes no arguments"))
508 508 return subset
509 509
510 510 def grep(repo, subset, x):
511 511 """``grep(regex)``
512 512 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
513 513 to ensure special escape characters are handled correctly. Unlike
514 514 ``keyword(string)``, the match is case-sensitive.
515 515 """
516 516 try:
517 517 # i18n: "grep" is a keyword
518 518 gr = re.compile(getstring(x, _("grep requires a string")))
519 519 except re.error, e:
520 520 raise error.ParseError(_('invalid match pattern: %s') % e)
521 521 l = []
522 522 for r in subset:
523 523 c = repo[r]
524 524 for e in c.files() + [c.user(), c.description()]:
525 525 if gr.search(e):
526 526 l.append(r)
527 527 break
528 528 return l
529 529
530 530 def _matchfiles(repo, subset, x):
531 531 # _matchfiles takes a revset list of prefixed arguments:
532 532 #
533 533 # [p:foo, i:bar, x:baz]
534 534 #
535 535 # builds a match object from them and filters subset. Allowed
536 536 # prefixes are 'p:' for regular patterns, 'i:' for include
537 # patterns and 'x:' for exclude patterns.
537 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
538 # a revision identifier, or the empty string to reference the
539 # working directory, from which the match object is
540 # initialized. At most one 'r:' argument can be passed.
538 541
539 542 # i18n: "_matchfiles" is a keyword
540 543 l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
541 544 pats, inc, exc = [], [], []
542 545 hasset = False
546 rev = None
543 547 for arg in l:
544 548 s = getstring(arg, _("_matchfiles requires string arguments"))
545 549 prefix, value = s[:2], s[2:]
546 550 if prefix == 'p:':
547 551 pats.append(value)
548 552 elif prefix == 'i:':
549 553 inc.append(value)
550 554 elif prefix == 'x:':
551 555 exc.append(value)
556 elif prefix == 'r:':
557 if rev is not None:
558 raise error.ParseError(_('_matchfiles expected at most one '
559 'revision'))
560 rev = value
552 561 else:
553 562 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
554 563 if not hasset and matchmod.patkind(value) == 'set':
555 564 hasset = True
556 565 m = None
557 566 s = []
558 567 for r in subset:
559 568 c = repo[r]
560 if not m or hasset:
569 if not m or (hasset and rev is None):
570 ctx = c
571 if rev is not None:
572 ctx = repo[rev or None]
561 573 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
562 exclude=exc, ctx=c)
574 exclude=exc, ctx=ctx)
563 575 for f in c.files():
564 576 if m(f):
565 577 s.append(r)
566 578 break
567 579 return s
568 580
569 581 def hasfile(repo, subset, x):
570 582 """``file(pattern)``
571 583 Changesets affecting files matched by pattern.
572 584 """
573 585 # i18n: "file" is a keyword
574 586 pat = getstring(x, _("file requires a pattern"))
575 587 return _matchfiles(repo, subset, ('string', 'p:' + pat))
576 588
577 589 def head(repo, subset, x):
578 590 """``head()``
579 591 Changeset is a named branch head.
580 592 """
581 593 # i18n: "head" is a keyword
582 594 getargs(x, 0, 0, _("head takes no arguments"))
583 595 hs = set()
584 596 for b, ls in repo.branchmap().iteritems():
585 597 hs.update(repo[h].rev() for h in ls)
586 598 return [r for r in subset if r in hs]
587 599
588 600 def heads(repo, subset, x):
589 601 """``heads(set)``
590 602 Members of set with no children in set.
591 603 """
592 604 s = getset(repo, subset, x)
593 605 ps = set(parents(repo, subset, x))
594 606 return [r for r in s if r not in ps]
595 607
596 608 def keyword(repo, subset, x):
597 609 """``keyword(string)``
598 610 Search commit message, user name, and names of changed files for
599 611 string. The match is case-insensitive.
600 612 """
601 613 # i18n: "keyword" is a keyword
602 614 kw = encoding.lower(getstring(x, _("keyword requires a string")))
603 615 l = []
604 616 for r in subset:
605 617 c = repo[r]
606 618 t = " ".join(c.files() + [c.user(), c.description()])
607 619 if kw in encoding.lower(t):
608 620 l.append(r)
609 621 return l
610 622
611 623 def limit(repo, subset, x):
612 624 """``limit(set, [n])``
613 625 First n members of set, defaulting to 1.
614 626 """
615 627 # i18n: "limit" is a keyword
616 628 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
617 629 try:
618 630 lim = 1
619 631 if len(l) == 2:
620 632 # i18n: "limit" is a keyword
621 633 lim = int(getstring(l[1], _("limit requires a number")))
622 634 except (TypeError, ValueError):
623 635 # i18n: "limit" is a keyword
624 636 raise error.ParseError(_("limit expects a number"))
625 637 ss = set(subset)
626 638 os = getset(repo, range(len(repo)), l[0])[:lim]
627 639 return [r for r in os if r in ss]
628 640
629 641 def last(repo, subset, x):
630 642 """``last(set, [n])``
631 643 Last n members of set, defaulting to 1.
632 644 """
633 645 # i18n: "last" is a keyword
634 646 l = getargs(x, 1, 2, _("last requires one or two arguments"))
635 647 try:
636 648 lim = 1
637 649 if len(l) == 2:
638 650 # i18n: "last" is a keyword
639 651 lim = int(getstring(l[1], _("last requires a number")))
640 652 except (TypeError, ValueError):
641 653 # i18n: "last" is a keyword
642 654 raise error.ParseError(_("last expects a number"))
643 655 ss = set(subset)
644 656 os = getset(repo, range(len(repo)), l[0])[-lim:]
645 657 return [r for r in os if r in ss]
646 658
647 659 def maxrev(repo, subset, x):
648 660 """``max(set)``
649 661 Changeset with highest revision number in set.
650 662 """
651 663 os = getset(repo, range(len(repo)), x)
652 664 if os:
653 665 m = max(os)
654 666 if m in subset:
655 667 return [m]
656 668 return []
657 669
658 670 def merge(repo, subset, x):
659 671 """``merge()``
660 672 Changeset is a merge changeset.
661 673 """
662 674 # i18n: "merge" is a keyword
663 675 getargs(x, 0, 0, _("merge takes no arguments"))
664 676 cl = repo.changelog
665 677 return [r for r in subset if cl.parentrevs(r)[1] != -1]
666 678
667 679 def minrev(repo, subset, x):
668 680 """``min(set)``
669 681 Changeset with lowest revision number in set.
670 682 """
671 683 os = getset(repo, range(len(repo)), x)
672 684 if os:
673 685 m = min(os)
674 686 if m in subset:
675 687 return [m]
676 688 return []
677 689
678 690 def modifies(repo, subset, x):
679 691 """``modifies(pattern)``
680 692 Changesets modifying files matched by pattern.
681 693 """
682 694 # i18n: "modifies" is a keyword
683 695 pat = getstring(x, _("modifies requires a pattern"))
684 696 return checkstatus(repo, subset, pat, 0)
685 697
686 698 def node(repo, subset, x):
687 699 """``id(string)``
688 700 Revision non-ambiguously specified by the given hex string prefix.
689 701 """
690 702 # i18n: "id" is a keyword
691 703 l = getargs(x, 1, 1, _("id requires one argument"))
692 704 # i18n: "id" is a keyword
693 705 n = getstring(l[0], _("id requires a string"))
694 706 if len(n) == 40:
695 707 rn = repo[n].rev()
696 708 else:
697 709 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
698 710 return [r for r in subset if r == rn]
699 711
700 712 def outgoing(repo, subset, x):
701 713 """``outgoing([path])``
702 714 Changesets not found in the specified destination repository, or the
703 715 default push location.
704 716 """
705 717 import hg # avoid start-up nasties
706 718 # i18n: "outgoing" is a keyword
707 719 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
708 720 # i18n: "outgoing" is a keyword
709 721 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
710 722 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
711 723 dest, branches = hg.parseurl(dest)
712 724 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
713 725 if revs:
714 726 revs = [repo.lookup(rev) for rev in revs]
715 727 other = hg.peer(repo, {}, dest)
716 728 repo.ui.pushbuffer()
717 729 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
718 730 repo.ui.popbuffer()
719 731 cl = repo.changelog
720 732 o = set([cl.rev(r) for r in outgoing.missing])
721 733 return [r for r in subset if r in o]
722 734
723 735 def p1(repo, subset, x):
724 736 """``p1([set])``
725 737 First parent of changesets in set, or the working directory.
726 738 """
727 739 if x is None:
728 740 p = repo[x].p1().rev()
729 741 return [r for r in subset if r == p]
730 742
731 743 ps = set()
732 744 cl = repo.changelog
733 745 for r in getset(repo, range(len(repo)), x):
734 746 ps.add(cl.parentrevs(r)[0])
735 747 return [r for r in subset if r in ps]
736 748
737 749 def p2(repo, subset, x):
738 750 """``p2([set])``
739 751 Second parent of changesets in set, or the working directory.
740 752 """
741 753 if x is None:
742 754 ps = repo[x].parents()
743 755 try:
744 756 p = ps[1].rev()
745 757 return [r for r in subset if r == p]
746 758 except IndexError:
747 759 return []
748 760
749 761 ps = set()
750 762 cl = repo.changelog
751 763 for r in getset(repo, range(len(repo)), x):
752 764 ps.add(cl.parentrevs(r)[1])
753 765 return [r for r in subset if r in ps]
754 766
755 767 def parents(repo, subset, x):
756 768 """``parents([set])``
757 769 The set of all parents for all changesets in set, or the working directory.
758 770 """
759 771 if x is None:
760 772 ps = tuple(p.rev() for p in repo[x].parents())
761 773 return [r for r in subset if r in ps]
762 774
763 775 ps = set()
764 776 cl = repo.changelog
765 777 for r in getset(repo, range(len(repo)), x):
766 778 ps.update(cl.parentrevs(r))
767 779 return [r for r in subset if r in ps]
768 780
769 781 def parentspec(repo, subset, x, n):
770 782 """``set^0``
771 783 The set.
772 784 ``set^1`` (or ``set^``), ``set^2``
773 785 First or second parent, respectively, of all changesets in set.
774 786 """
775 787 try:
776 788 n = int(n[1])
777 789 if n not in (0, 1, 2):
778 790 raise ValueError
779 791 except (TypeError, ValueError):
780 792 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
781 793 ps = set()
782 794 cl = repo.changelog
783 795 for r in getset(repo, subset, x):
784 796 if n == 0:
785 797 ps.add(r)
786 798 elif n == 1:
787 799 ps.add(cl.parentrevs(r)[0])
788 800 elif n == 2:
789 801 parents = cl.parentrevs(r)
790 802 if len(parents) > 1:
791 803 ps.add(parents[1])
792 804 return [r for r in subset if r in ps]
793 805
794 806 def present(repo, subset, x):
795 807 """``present(set)``
796 808 An empty set, if any revision in set isn't found; otherwise,
797 809 all revisions in set.
798 810 """
799 811 try:
800 812 return getset(repo, subset, x)
801 813 except error.RepoLookupError:
802 814 return []
803 815
804 816 def public(repo, subset, x):
805 817 """``public()``
806 818 Changeset in public phase."""
807 819 getargs(x, 0, 0, _("public takes no arguments"))
808 820 return [r for r in subset if repo._phaserev[r] == phases.public]
809 821
810 822 def remote(repo, subset, x):
811 823 """``remote([id [,path]])``
812 824 Local revision that corresponds to the given identifier in a
813 825 remote repository, if present. Here, the '.' identifier is a
814 826 synonym for the current local branch.
815 827 """
816 828
817 829 import hg # avoid start-up nasties
818 830 # i18n: "remote" is a keyword
819 831 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
820 832
821 833 q = '.'
822 834 if len(l) > 0:
823 835 # i18n: "remote" is a keyword
824 836 q = getstring(l[0], _("remote requires a string id"))
825 837 if q == '.':
826 838 q = repo['.'].branch()
827 839
828 840 dest = ''
829 841 if len(l) > 1:
830 842 # i18n: "remote" is a keyword
831 843 dest = getstring(l[1], _("remote requires a repository path"))
832 844 dest = repo.ui.expandpath(dest or 'default')
833 845 dest, branches = hg.parseurl(dest)
834 846 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
835 847 if revs:
836 848 revs = [repo.lookup(rev) for rev in revs]
837 849 other = hg.peer(repo, {}, dest)
838 850 n = other.lookup(q)
839 851 if n in repo:
840 852 r = repo[n].rev()
841 853 if r in subset:
842 854 return [r]
843 855 return []
844 856
845 857 def removes(repo, subset, x):
846 858 """``removes(pattern)``
847 859 Changesets which remove files matching pattern.
848 860 """
849 861 # i18n: "removes" is a keyword
850 862 pat = getstring(x, _("removes requires a pattern"))
851 863 return checkstatus(repo, subset, pat, 2)
852 864
853 865 def rev(repo, subset, x):
854 866 """``rev(number)``
855 867 Revision with the given numeric identifier.
856 868 """
857 869 # i18n: "rev" is a keyword
858 870 l = getargs(x, 1, 1, _("rev requires one argument"))
859 871 try:
860 872 # i18n: "rev" is a keyword
861 873 l = int(getstring(l[0], _("rev requires a number")))
862 874 except (TypeError, ValueError):
863 875 # i18n: "rev" is a keyword
864 876 raise error.ParseError(_("rev expects a number"))
865 877 return [r for r in subset if r == l]
866 878
867 879 def reverse(repo, subset, x):
868 880 """``reverse(set)``
869 881 Reverse order of set.
870 882 """
871 883 l = getset(repo, subset, x)
872 884 l.reverse()
873 885 return l
874 886
875 887 def roots(repo, subset, x):
876 888 """``roots(set)``
877 889 Changesets with no parent changeset in set.
878 890 """
879 891 s = getset(repo, xrange(len(repo)), x)
880 892 cs = _children(repo, s, s)
881 893 return [r for r in s if r not in cs]
882 894
883 895 def secret(repo, subset, x):
884 896 """``secret()``
885 897 Changeset in secret phase."""
886 898 getargs(x, 0, 0, _("secret takes no arguments"))
887 899 return [r for r in subset if repo._phaserev[r] == phases.secret]
888 900
889 901 def sort(repo, subset, x):
890 902 """``sort(set[, [-]key...])``
891 903 Sort set by keys. The default sort order is ascending, specify a key
892 904 as ``-key`` to sort in descending order.
893 905
894 906 The keys can be:
895 907
896 908 - ``rev`` for the revision number,
897 909 - ``branch`` for the branch name,
898 910 - ``desc`` for the commit message (description),
899 911 - ``user`` for user name (``author`` can be used as an alias),
900 912 - ``date`` for the commit date
901 913 """
902 914 # i18n: "sort" is a keyword
903 915 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
904 916 keys = "rev"
905 917 if len(l) == 2:
906 918 keys = getstring(l[1], _("sort spec must be a string"))
907 919
908 920 s = l[0]
909 921 keys = keys.split()
910 922 l = []
911 923 def invert(s):
912 924 return "".join(chr(255 - ord(c)) for c in s)
913 925 for r in getset(repo, subset, s):
914 926 c = repo[r]
915 927 e = []
916 928 for k in keys:
917 929 if k == 'rev':
918 930 e.append(r)
919 931 elif k == '-rev':
920 932 e.append(-r)
921 933 elif k == 'branch':
922 934 e.append(c.branch())
923 935 elif k == '-branch':
924 936 e.append(invert(c.branch()))
925 937 elif k == 'desc':
926 938 e.append(c.description())
927 939 elif k == '-desc':
928 940 e.append(invert(c.description()))
929 941 elif k in 'user author':
930 942 e.append(c.user())
931 943 elif k in '-user -author':
932 944 e.append(invert(c.user()))
933 945 elif k == 'date':
934 946 e.append(c.date()[0])
935 947 elif k == '-date':
936 948 e.append(-c.date()[0])
937 949 else:
938 950 raise error.ParseError(_("unknown sort key %r") % k)
939 951 e.append(r)
940 952 l.append(e)
941 953 l.sort()
942 954 return [e[-1] for e in l]
943 955
944 956 def tag(repo, subset, x):
945 957 """``tag([name])``
946 958 The specified tag by name, or all tagged revisions if no name is given.
947 959 """
948 960 # i18n: "tag" is a keyword
949 961 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
950 962 cl = repo.changelog
951 963 if args:
952 964 tn = getstring(args[0],
953 965 # i18n: "tag" is a keyword
954 966 _('the argument to tag must be a string'))
955 967 if not repo.tags().get(tn, None):
956 968 raise util.Abort(_("tag '%s' does not exist") % tn)
957 969 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
958 970 else:
959 971 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
960 972 return [r for r in subset if r in s]
961 973
962 974 def tagged(repo, subset, x):
963 975 return tag(repo, subset, x)
964 976
965 977 def user(repo, subset, x):
966 978 """``user(string)``
967 979 User name contains string. The match is case-insensitive.
968 980 """
969 981 return author(repo, subset, x)
970 982
971 983 # for internal use
972 984 def _list(repo, subset, x):
973 985 s = getstring(x, "internal error")
974 986 if not s:
975 987 return []
976 988 if not isinstance(subset, set):
977 989 subset = set(subset)
978 990 ls = [repo[r].rev() for r in s.split('\0')]
979 991 return [r for r in ls if r in subset]
980 992
981 993 symbols = {
982 994 "adds": adds,
983 995 "all": getall,
984 996 "ancestor": ancestor,
985 997 "ancestors": ancestors,
986 998 "author": author,
987 999 "bisect": bisect,
988 1000 "bisected": bisected,
989 1001 "bookmark": bookmark,
990 1002 "branch": branch,
991 1003 "children": children,
992 1004 "closed": closed,
993 1005 "contains": contains,
994 1006 "date": date,
995 1007 "desc": desc,
996 1008 "descendants": descendants,
997 1009 "draft": draft,
998 1010 "file": hasfile,
999 1011 "filelog": filelog,
1000 1012 "first": first,
1001 1013 "follow": follow,
1002 1014 "_followfirst": _followfirst,
1003 1015 "grep": grep,
1004 1016 "head": head,
1005 1017 "heads": heads,
1006 1018 "id": node,
1007 1019 "keyword": keyword,
1008 1020 "last": last,
1009 1021 "limit": limit,
1010 1022 "_matchfiles": _matchfiles,
1011 1023 "max": maxrev,
1012 1024 "merge": merge,
1013 1025 "min": minrev,
1014 1026 "modifies": modifies,
1015 1027 "outgoing": outgoing,
1016 1028 "p1": p1,
1017 1029 "p2": p2,
1018 1030 "parents": parents,
1019 1031 "present": present,
1020 1032 "public": public,
1021 1033 "remote": remote,
1022 1034 "removes": removes,
1023 1035 "rev": rev,
1024 1036 "reverse": reverse,
1025 1037 "roots": roots,
1026 1038 "sort": sort,
1027 1039 "secret": secret,
1028 1040 "tag": tag,
1029 1041 "tagged": tagged,
1030 1042 "user": user,
1031 1043 "_list": _list,
1032 1044 }
1033 1045
1034 1046 methods = {
1035 1047 "range": rangeset,
1036 1048 "string": stringset,
1037 1049 "symbol": symbolset,
1038 1050 "and": andset,
1039 1051 "or": orset,
1040 1052 "not": notset,
1041 1053 "list": listset,
1042 1054 "func": func,
1043 1055 "ancestor": ancestorspec,
1044 1056 "parent": parentspec,
1045 1057 "parentpost": p1,
1046 1058 }
1047 1059
1048 1060 def optimize(x, small):
1049 1061 if x is None:
1050 1062 return 0, x
1051 1063
1052 1064 smallbonus = 1
1053 1065 if small:
1054 1066 smallbonus = .5
1055 1067
1056 1068 op = x[0]
1057 1069 if op == 'minus':
1058 1070 return optimize(('and', x[1], ('not', x[2])), small)
1059 1071 elif op == 'dagrange':
1060 1072 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
1061 1073 ('func', ('symbol', 'ancestors'), x[2])), small)
1062 1074 elif op == 'dagrangepre':
1063 1075 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
1064 1076 elif op == 'dagrangepost':
1065 1077 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
1066 1078 elif op == 'rangepre':
1067 1079 return optimize(('range', ('string', '0'), x[1]), small)
1068 1080 elif op == 'rangepost':
1069 1081 return optimize(('range', x[1], ('string', 'tip')), small)
1070 1082 elif op == 'negate':
1071 1083 return optimize(('string',
1072 1084 '-' + getstring(x[1], _("can't negate that"))), small)
1073 1085 elif op in 'string symbol negate':
1074 1086 return smallbonus, x # single revisions are small
1075 1087 elif op == 'and' or op == 'dagrange':
1076 1088 wa, ta = optimize(x[1], True)
1077 1089 wb, tb = optimize(x[2], True)
1078 1090 w = min(wa, wb)
1079 1091 if wa > wb:
1080 1092 return w, (op, tb, ta)
1081 1093 return w, (op, ta, tb)
1082 1094 elif op == 'or':
1083 1095 wa, ta = optimize(x[1], False)
1084 1096 wb, tb = optimize(x[2], False)
1085 1097 if wb < wa:
1086 1098 wb, wa = wa, wb
1087 1099 return max(wa, wb), (op, ta, tb)
1088 1100 elif op == 'not':
1089 1101 o = optimize(x[1], not small)
1090 1102 return o[0], (op, o[1])
1091 1103 elif op == 'parentpost':
1092 1104 o = optimize(x[1], small)
1093 1105 return o[0], (op, o[1])
1094 1106 elif op == 'group':
1095 1107 return optimize(x[1], small)
1096 1108 elif op in 'range list parent ancestorspec':
1097 1109 if op == 'parent':
1098 1110 # x^:y means (x^) : y, not x ^ (:y)
1099 1111 post = ('parentpost', x[1])
1100 1112 if x[2][0] == 'dagrangepre':
1101 1113 return optimize(('dagrange', post, x[2][1]), small)
1102 1114 elif x[2][0] == 'rangepre':
1103 1115 return optimize(('range', post, x[2][1]), small)
1104 1116
1105 1117 wa, ta = optimize(x[1], small)
1106 1118 wb, tb = optimize(x[2], small)
1107 1119 return wa + wb, (op, ta, tb)
1108 1120 elif op == 'func':
1109 1121 f = getstring(x[1], _("not a symbol"))
1110 1122 wa, ta = optimize(x[2], small)
1111 1123 if f in ("author branch closed date desc file grep keyword "
1112 1124 "outgoing user"):
1113 1125 w = 10 # slow
1114 1126 elif f in "modifies adds removes":
1115 1127 w = 30 # slower
1116 1128 elif f == "contains":
1117 1129 w = 100 # very slow
1118 1130 elif f == "ancestor":
1119 1131 w = 1 * smallbonus
1120 1132 elif f in "reverse limit first":
1121 1133 w = 0
1122 1134 elif f in "sort":
1123 1135 w = 10 # assume most sorts look at changelog
1124 1136 else:
1125 1137 w = 1
1126 1138 return w + wa, (op, x[1], ta)
1127 1139 return 1, x
1128 1140
1129 1141 class revsetalias(object):
1130 1142 funcre = re.compile('^([^(]+)\(([^)]+)\)$')
1131 1143 args = None
1132 1144
1133 1145 def __init__(self, name, value):
1134 1146 '''Aliases like:
1135 1147
1136 1148 h = heads(default)
1137 1149 b($1) = ancestors($1) - ancestors(default)
1138 1150 '''
1139 1151 m = self.funcre.search(name)
1140 1152 if m:
1141 1153 self.name = m.group(1)
1142 1154 self.tree = ('func', ('symbol', m.group(1)))
1143 1155 self.args = [x.strip() for x in m.group(2).split(',')]
1144 1156 for arg in self.args:
1145 1157 value = value.replace(arg, repr(arg))
1146 1158 else:
1147 1159 self.name = name
1148 1160 self.tree = ('symbol', name)
1149 1161
1150 1162 self.replacement, pos = parse(value)
1151 1163 if pos != len(value):
1152 1164 raise error.ParseError(_('invalid token'), pos)
1153 1165
1154 1166 def _getalias(aliases, tree):
1155 1167 """If tree looks like an unexpanded alias, return it. Return None
1156 1168 otherwise.
1157 1169 """
1158 1170 if isinstance(tree, tuple) and tree:
1159 1171 if tree[0] == 'symbol' and len(tree) == 2:
1160 1172 name = tree[1]
1161 1173 alias = aliases.get(name)
1162 1174 if alias and alias.args is None and alias.tree == tree:
1163 1175 return alias
1164 1176 if tree[0] == 'func' and len(tree) > 1:
1165 1177 if tree[1][0] == 'symbol' and len(tree[1]) == 2:
1166 1178 name = tree[1][1]
1167 1179 alias = aliases.get(name)
1168 1180 if alias and alias.args is not None and alias.tree == tree[:2]:
1169 1181 return alias
1170 1182 return None
1171 1183
1172 1184 def _expandargs(tree, args):
1173 1185 """Replace all occurences of ('string', name) with the
1174 1186 substitution value of the same name in args, recursively.
1175 1187 """
1176 1188 if not isinstance(tree, tuple):
1177 1189 return tree
1178 1190 if len(tree) == 2 and tree[0] == 'string':
1179 1191 return args.get(tree[1], tree)
1180 1192 return tuple(_expandargs(t, args) for t in tree)
1181 1193
1182 1194 def _expandaliases(aliases, tree, expanding):
1183 1195 """Expand aliases in tree, recursively.
1184 1196
1185 1197 'aliases' is a dictionary mapping user defined aliases to
1186 1198 revsetalias objects.
1187 1199 """
1188 1200 if not isinstance(tree, tuple):
1189 1201 # Do not expand raw strings
1190 1202 return tree
1191 1203 alias = _getalias(aliases, tree)
1192 1204 if alias is not None:
1193 1205 if alias in expanding:
1194 1206 raise error.ParseError(_('infinite expansion of revset alias "%s" '
1195 1207 'detected') % alias.name)
1196 1208 expanding.append(alias)
1197 1209 result = alias.replacement
1198 1210 if alias.args is not None:
1199 1211 l = getlist(tree[2])
1200 1212 if len(l) != len(alias.args):
1201 1213 raise error.ParseError(
1202 1214 _('invalid number of arguments: %s') % len(l))
1203 1215 result = _expandargs(result, dict(zip(alias.args, l)))
1204 1216 # Recurse in place, the base expression may have been rewritten
1205 1217 result = _expandaliases(aliases, result, expanding)
1206 1218 expanding.pop()
1207 1219 else:
1208 1220 result = tuple(_expandaliases(aliases, t, expanding)
1209 1221 for t in tree)
1210 1222 return result
1211 1223
1212 1224 def findaliases(ui, tree):
1213 1225 aliases = {}
1214 1226 for k, v in ui.configitems('revsetalias'):
1215 1227 alias = revsetalias(k, v)
1216 1228 aliases[alias.name] = alias
1217 1229 return _expandaliases(aliases, tree, [])
1218 1230
1219 1231 parse = parser.parser(tokenize, elements).parse
1220 1232
1221 1233 def match(ui, spec):
1222 1234 if not spec:
1223 1235 raise error.ParseError(_("empty query"))
1224 1236 tree, pos = parse(spec)
1225 1237 if (pos != len(spec)):
1226 1238 raise error.ParseError(_("invalid token"), pos)
1227 1239 if ui:
1228 1240 tree = findaliases(ui, tree)
1229 1241 weight, tree = optimize(tree, True)
1230 1242 def mfunc(repo, subset):
1231 1243 return getset(repo, subset, tree)
1232 1244 return mfunc
1233 1245
1234 1246 def formatspec(expr, *args):
1235 1247 '''
1236 1248 This is a convenience function for using revsets internally, and
1237 1249 escapes arguments appropriately. Aliases are intentionally ignored
1238 1250 so that intended expression behavior isn't accidentally subverted.
1239 1251
1240 1252 Supported arguments:
1241 1253
1242 1254 %r = revset expression, parenthesized
1243 1255 %d = int(arg), no quoting
1244 1256 %s = string(arg), escaped and single-quoted
1245 1257 %b = arg.branch(), escaped and single-quoted
1246 1258 %n = hex(arg), single-quoted
1247 1259 %% = a literal '%'
1248 1260
1249 1261 Prefixing the type with 'l' specifies a parenthesized list of that type.
1250 1262
1251 1263 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
1252 1264 '(10 or 11):: and ((this()) or (that()))'
1253 1265 >>> formatspec('%d:: and not %d::', 10, 20)
1254 1266 '10:: and not 20::'
1255 1267 >>> formatspec('%ld or %ld', [], [1])
1256 1268 "_list('') or 1"
1257 1269 >>> formatspec('keyword(%s)', 'foo\\xe9')
1258 1270 "keyword('foo\\\\xe9')"
1259 1271 >>> b = lambda: 'default'
1260 1272 >>> b.branch = b
1261 1273 >>> formatspec('branch(%b)', b)
1262 1274 "branch('default')"
1263 1275 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
1264 1276 "root(_list('a\\x00b\\x00c\\x00d'))"
1265 1277 '''
1266 1278
1267 1279 def quote(s):
1268 1280 return repr(str(s))
1269 1281
1270 1282 def argtype(c, arg):
1271 1283 if c == 'd':
1272 1284 return str(int(arg))
1273 1285 elif c == 's':
1274 1286 return quote(arg)
1275 1287 elif c == 'r':
1276 1288 parse(arg) # make sure syntax errors are confined
1277 1289 return '(%s)' % arg
1278 1290 elif c == 'n':
1279 1291 return quote(nodemod.hex(arg))
1280 1292 elif c == 'b':
1281 1293 return quote(arg.branch())
1282 1294
1283 1295 def listexp(s, t):
1284 1296 l = len(s)
1285 1297 if l == 0:
1286 1298 return "_list('')"
1287 1299 elif l == 1:
1288 1300 return argtype(t, s[0])
1289 1301 elif t == 'd':
1290 1302 return "_list('%s')" % "\0".join(str(int(a)) for a in s)
1291 1303 elif t == 's':
1292 1304 return "_list('%s')" % "\0".join(s)
1293 1305 elif t == 'n':
1294 1306 return "_list('%s')" % "\0".join(nodemod.hex(a) for a in s)
1295 1307 elif t == 'b':
1296 1308 return "_list('%s')" % "\0".join(a.branch() for a in s)
1297 1309
1298 1310 m = l // 2
1299 1311 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
1300 1312
1301 1313 ret = ''
1302 1314 pos = 0
1303 1315 arg = 0
1304 1316 while pos < len(expr):
1305 1317 c = expr[pos]
1306 1318 if c == '%':
1307 1319 pos += 1
1308 1320 d = expr[pos]
1309 1321 if d == '%':
1310 1322 ret += d
1311 1323 elif d in 'dsnbr':
1312 1324 ret += argtype(d, args[arg])
1313 1325 arg += 1
1314 1326 elif d == 'l':
1315 1327 # a list of some type
1316 1328 pos += 1
1317 1329 d = expr[pos]
1318 1330 ret += listexp(list(args[arg]), d)
1319 1331 arg += 1
1320 1332 else:
1321 1333 raise util.Abort('unexpected revspec format character %s' % d)
1322 1334 else:
1323 1335 ret += c
1324 1336 pos += 1
1325 1337
1326 1338 return ret
1327 1339
1328 1340 # tell hggettext to extract docstrings from these functions:
1329 1341 i18nfunctions = symbols.values()
@@ -1,1662 +1,1669 b''
1 1 @ (34) head
2 2 |
3 3 | o (33) head
4 4 | |
5 5 o | (32) expand
6 6 |\ \
7 7 | o \ (31) expand
8 8 | |\ \
9 9 | | o \ (30) expand
10 10 | | |\ \
11 11 | | | o | (29) regular commit
12 12 | | | | |
13 13 | | o | | (28) merge zero known
14 14 | | |\ \ \
15 15 o | | | | | (27) collapse
16 16 |/ / / / /
17 17 | | o---+ (26) merge one known; far right
18 18 | | | | |
19 19 +---o | | (25) merge one known; far left
20 20 | | | | |
21 21 | | o | | (24) merge one known; immediate right
22 22 | | |\| |
23 23 | | o | | (23) merge one known; immediate left
24 24 | |/| | |
25 25 +---o---+ (22) merge two known; one far left, one far right
26 26 | | / /
27 27 o | | | (21) expand
28 28 |\ \ \ \
29 29 | o---+-+ (20) merge two known; two far right
30 30 | / / /
31 31 o | | | (19) expand
32 32 |\ \ \ \
33 33 +---+---o (18) merge two known; two far left
34 34 | | | |
35 35 | o | | (17) expand
36 36 | |\ \ \
37 37 | | o---+ (16) merge two known; one immediate right, one near right
38 38 | | |/ /
39 39 o | | | (15) expand
40 40 |\ \ \ \
41 41 | o-----+ (14) merge two known; one immediate right, one far right
42 42 | |/ / /
43 43 o | | | (13) expand
44 44 |\ \ \ \
45 45 +---o | | (12) merge two known; one immediate right, one far left
46 46 | | |/ /
47 47 | o | | (11) expand
48 48 | |\ \ \
49 49 | | o---+ (10) merge two known; one immediate left, one near right
50 50 | |/ / /
51 51 o | | | (9) expand
52 52 |\ \ \ \
53 53 | o-----+ (8) merge two known; one immediate left, one far right
54 54 |/ / / /
55 55 o | | | (7) expand
56 56 |\ \ \ \
57 57 +---o | | (6) merge two known; one immediate left, one far left
58 58 | |/ / /
59 59 | o | | (5) expand
60 60 | |\ \ \
61 61 | | o | | (4) merge two known; one immediate left, one immediate right
62 62 | |/|/ /
63 63 | o / / (3) collapse
64 64 |/ / /
65 65 o / / (2) collapse
66 66 |/ /
67 67 o / (1) collapse
68 68 |/
69 69 o (0) root
70 70
71 71
72 72 $ "$TESTDIR/hghave" no-outer-repo || exit 80
73 73
74 74 $ commit()
75 75 > {
76 76 > rev=$1
77 77 > msg=$2
78 78 > shift 2
79 79 > if [ "$#" -gt 0 ]; then
80 80 > hg debugsetparents "$@"
81 81 > fi
82 82 > echo $rev > a
83 83 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
84 84 > }
85 85
86 86 $ cat > printrevset.py <<EOF
87 87 > from mercurial import extensions, revset, commands
88 88 > from hgext import graphlog
89 89 >
90 90 > def uisetup(ui):
91 91 > def printrevset(orig, ui, repo, *pats, **opts):
92 92 > if opts.get('print_revset'):
93 93 > expr = graphlog.revset(repo, pats, opts)
94 94 > tree = revset.parse(expr)[0]
95 95 > ui.write(tree, "\n")
96 96 > return 0
97 97 > return orig(ui, repo, *pats, **opts)
98 98 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
99 99 > entry[1].append(('', 'print-revset', False,
100 100 > 'print generated revset and exit (DEPRECATED)'))
101 101 > EOF
102 102
103 103 $ echo "[extensions]" >> $HGRCPATH
104 104 $ echo "graphlog=" >> $HGRCPATH
105 105 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
106 106
107 107 $ hg init repo
108 108 $ cd repo
109 109
110 110 Empty repo:
111 111
112 112 $ hg glog
113 113
114 114
115 115 Building DAG:
116 116
117 117 $ commit 0 "root"
118 118 $ commit 1 "collapse" 0
119 119 $ commit 2 "collapse" 1
120 120 $ commit 3 "collapse" 2
121 121 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
122 122 $ commit 5 "expand" 3 4
123 123 $ commit 6 "merge two known; one immediate left, one far left" 2 5
124 124 $ commit 7 "expand" 2 5
125 125 $ commit 8 "merge two known; one immediate left, one far right" 0 7
126 126 $ commit 9 "expand" 7 8
127 127 $ commit 10 "merge two known; one immediate left, one near right" 0 6
128 128 $ commit 11 "expand" 6 10
129 129 $ commit 12 "merge two known; one immediate right, one far left" 1 9
130 130 $ commit 13 "expand" 9 11
131 131 $ commit 14 "merge two known; one immediate right, one far right" 0 12
132 132 $ commit 15 "expand" 13 14
133 133 $ commit 16 "merge two known; one immediate right, one near right" 0 1
134 134 $ commit 17 "expand" 12 16
135 135 $ commit 18 "merge two known; two far left" 1 15
136 136 $ commit 19 "expand" 15 17
137 137 $ commit 20 "merge two known; two far right" 0 18
138 138 $ commit 21 "expand" 19 20
139 139 $ commit 22 "merge two known; one far left, one far right" 18 21
140 140 $ commit 23 "merge one known; immediate left" 1 22
141 141 $ commit 24 "merge one known; immediate right" 0 23
142 142 $ commit 25 "merge one known; far left" 21 24
143 143 $ commit 26 "merge one known; far right" 18 25
144 144 $ commit 27 "collapse" 21
145 145 $ commit 28 "merge zero known" 1 26
146 146 $ commit 29 "regular commit" 0
147 147 $ commit 30 "expand" 28 29
148 148 $ commit 31 "expand" 21 30
149 149 $ commit 32 "expand" 27 31
150 150 $ commit 33 "head" 18
151 151 $ commit 34 "head" 32
152 152
153 153
154 154 $ hg glog -q
155 155 @ 34:fea3ac5810e0
156 156 |
157 157 | o 33:68608f5145f9
158 158 | |
159 159 o | 32:d06dffa21a31
160 160 |\ \
161 161 | o \ 31:621d83e11f67
162 162 | |\ \
163 163 | | o \ 30:6e11cd4b648f
164 164 | | |\ \
165 165 | | | o | 29:cd9bb2be7593
166 166 | | | | |
167 167 | | o | | 28:44ecd0b9ae99
168 168 | | |\ \ \
169 169 o | | | | | 27:886ed638191b
170 170 |/ / / / /
171 171 | | o---+ 26:7f25b6c2f0b9
172 172 | | | | |
173 173 +---o | | 25:91da8ed57247
174 174 | | | | |
175 175 | | o | | 24:a9c19a3d96b7
176 176 | | |\| |
177 177 | | o | | 23:a01cddf0766d
178 178 | |/| | |
179 179 +---o---+ 22:e0d9cccacb5d
180 180 | | / /
181 181 o | | | 21:d42a756af44d
182 182 |\ \ \ \
183 183 | o---+-+ 20:d30ed6450e32
184 184 | / / /
185 185 o | | | 19:31ddc2c1573b
186 186 |\ \ \ \
187 187 +---+---o 18:1aa84d96232a
188 188 | | | |
189 189 | o | | 17:44765d7c06e0
190 190 | |\ \ \
191 191 | | o---+ 16:3677d192927d
192 192 | | |/ /
193 193 o | | | 15:1dda3f72782d
194 194 |\ \ \ \
195 195 | o-----+ 14:8eac370358ef
196 196 | |/ / /
197 197 o | | | 13:22d8966a97e3
198 198 |\ \ \ \
199 199 +---o | | 12:86b91144a6e9
200 200 | | |/ /
201 201 | o | | 11:832d76e6bdf2
202 202 | |\ \ \
203 203 | | o---+ 10:74c64d036d72
204 204 | |/ / /
205 205 o | | | 9:7010c0af0a35
206 206 |\ \ \ \
207 207 | o-----+ 8:7a0b11f71937
208 208 |/ / / /
209 209 o | | | 7:b632bb1b1224
210 210 |\ \ \ \
211 211 +---o | | 6:b105a072e251
212 212 | |/ / /
213 213 | o | | 5:4409d547b708
214 214 | |\ \ \
215 215 | | o | | 4:26a8bac39d9f
216 216 | |/|/ /
217 217 | o / / 3:27eef8ed80b4
218 218 |/ / /
219 219 o / / 2:3d9a33b8d1e1
220 220 |/ /
221 221 o / 1:6db2ef61d156
222 222 |/
223 223 o 0:e6eb3150255d
224 224
225 225
226 226 $ hg glog
227 227 @ changeset: 34:fea3ac5810e0
228 228 | tag: tip
229 229 | parent: 32:d06dffa21a31
230 230 | user: test
231 231 | date: Thu Jan 01 00:00:34 1970 +0000
232 232 | summary: (34) head
233 233 |
234 234 | o changeset: 33:68608f5145f9
235 235 | | parent: 18:1aa84d96232a
236 236 | | user: test
237 237 | | date: Thu Jan 01 00:00:33 1970 +0000
238 238 | | summary: (33) head
239 239 | |
240 240 o | changeset: 32:d06dffa21a31
241 241 |\ \ parent: 27:886ed638191b
242 242 | | | parent: 31:621d83e11f67
243 243 | | | user: test
244 244 | | | date: Thu Jan 01 00:00:32 1970 +0000
245 245 | | | summary: (32) expand
246 246 | | |
247 247 | o | changeset: 31:621d83e11f67
248 248 | |\ \ parent: 21:d42a756af44d
249 249 | | | | parent: 30:6e11cd4b648f
250 250 | | | | user: test
251 251 | | | | date: Thu Jan 01 00:00:31 1970 +0000
252 252 | | | | summary: (31) expand
253 253 | | | |
254 254 | | o | changeset: 30:6e11cd4b648f
255 255 | | |\ \ parent: 28:44ecd0b9ae99
256 256 | | | | | parent: 29:cd9bb2be7593
257 257 | | | | | user: test
258 258 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
259 259 | | | | | summary: (30) expand
260 260 | | | | |
261 261 | | | o | changeset: 29:cd9bb2be7593
262 262 | | | | | parent: 0:e6eb3150255d
263 263 | | | | | user: test
264 264 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
265 265 | | | | | summary: (29) regular commit
266 266 | | | | |
267 267 | | o | | changeset: 28:44ecd0b9ae99
268 268 | | |\ \ \ parent: 1:6db2ef61d156
269 269 | | | | | | parent: 26:7f25b6c2f0b9
270 270 | | | | | | user: test
271 271 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
272 272 | | | | | | summary: (28) merge zero known
273 273 | | | | | |
274 274 o | | | | | changeset: 27:886ed638191b
275 275 |/ / / / / parent: 21:d42a756af44d
276 276 | | | | | user: test
277 277 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
278 278 | | | | | summary: (27) collapse
279 279 | | | | |
280 280 | | o---+ changeset: 26:7f25b6c2f0b9
281 281 | | | | | parent: 18:1aa84d96232a
282 282 | | | | | parent: 25:91da8ed57247
283 283 | | | | | user: test
284 284 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
285 285 | | | | | summary: (26) merge one known; far right
286 286 | | | | |
287 287 +---o | | changeset: 25:91da8ed57247
288 288 | | | | | parent: 21:d42a756af44d
289 289 | | | | | parent: 24:a9c19a3d96b7
290 290 | | | | | user: test
291 291 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
292 292 | | | | | summary: (25) merge one known; far left
293 293 | | | | |
294 294 | | o | | changeset: 24:a9c19a3d96b7
295 295 | | |\| | parent: 0:e6eb3150255d
296 296 | | | | | parent: 23:a01cddf0766d
297 297 | | | | | user: test
298 298 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
299 299 | | | | | summary: (24) merge one known; immediate right
300 300 | | | | |
301 301 | | o | | changeset: 23:a01cddf0766d
302 302 | |/| | | parent: 1:6db2ef61d156
303 303 | | | | | parent: 22:e0d9cccacb5d
304 304 | | | | | user: test
305 305 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
306 306 | | | | | summary: (23) merge one known; immediate left
307 307 | | | | |
308 308 +---o---+ changeset: 22:e0d9cccacb5d
309 309 | | | | parent: 18:1aa84d96232a
310 310 | | / / parent: 21:d42a756af44d
311 311 | | | | user: test
312 312 | | | | date: Thu Jan 01 00:00:22 1970 +0000
313 313 | | | | summary: (22) merge two known; one far left, one far right
314 314 | | | |
315 315 o | | | changeset: 21:d42a756af44d
316 316 |\ \ \ \ parent: 19:31ddc2c1573b
317 317 | | | | | parent: 20:d30ed6450e32
318 318 | | | | | user: test
319 319 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
320 320 | | | | | summary: (21) expand
321 321 | | | | |
322 322 | o---+-+ changeset: 20:d30ed6450e32
323 323 | | | | parent: 0:e6eb3150255d
324 324 | / / / parent: 18:1aa84d96232a
325 325 | | | | user: test
326 326 | | | | date: Thu Jan 01 00:00:20 1970 +0000
327 327 | | | | summary: (20) merge two known; two far right
328 328 | | | |
329 329 o | | | changeset: 19:31ddc2c1573b
330 330 |\ \ \ \ parent: 15:1dda3f72782d
331 331 | | | | | parent: 17:44765d7c06e0
332 332 | | | | | user: test
333 333 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
334 334 | | | | | summary: (19) expand
335 335 | | | | |
336 336 +---+---o changeset: 18:1aa84d96232a
337 337 | | | | parent: 1:6db2ef61d156
338 338 | | | | parent: 15:1dda3f72782d
339 339 | | | | user: test
340 340 | | | | date: Thu Jan 01 00:00:18 1970 +0000
341 341 | | | | summary: (18) merge two known; two far left
342 342 | | | |
343 343 | o | | changeset: 17:44765d7c06e0
344 344 | |\ \ \ parent: 12:86b91144a6e9
345 345 | | | | | parent: 16:3677d192927d
346 346 | | | | | user: test
347 347 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
348 348 | | | | | summary: (17) expand
349 349 | | | | |
350 350 | | o---+ changeset: 16:3677d192927d
351 351 | | | | | parent: 0:e6eb3150255d
352 352 | | |/ / parent: 1:6db2ef61d156
353 353 | | | | user: test
354 354 | | | | date: Thu Jan 01 00:00:16 1970 +0000
355 355 | | | | summary: (16) merge two known; one immediate right, one near right
356 356 | | | |
357 357 o | | | changeset: 15:1dda3f72782d
358 358 |\ \ \ \ parent: 13:22d8966a97e3
359 359 | | | | | parent: 14:8eac370358ef
360 360 | | | | | user: test
361 361 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
362 362 | | | | | summary: (15) expand
363 363 | | | | |
364 364 | o-----+ changeset: 14:8eac370358ef
365 365 | | | | | parent: 0:e6eb3150255d
366 366 | |/ / / parent: 12:86b91144a6e9
367 367 | | | | user: test
368 368 | | | | date: Thu Jan 01 00:00:14 1970 +0000
369 369 | | | | summary: (14) merge two known; one immediate right, one far right
370 370 | | | |
371 371 o | | | changeset: 13:22d8966a97e3
372 372 |\ \ \ \ parent: 9:7010c0af0a35
373 373 | | | | | parent: 11:832d76e6bdf2
374 374 | | | | | user: test
375 375 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
376 376 | | | | | summary: (13) expand
377 377 | | | | |
378 378 +---o | | changeset: 12:86b91144a6e9
379 379 | | |/ / parent: 1:6db2ef61d156
380 380 | | | | parent: 9:7010c0af0a35
381 381 | | | | user: test
382 382 | | | | date: Thu Jan 01 00:00:12 1970 +0000
383 383 | | | | summary: (12) merge two known; one immediate right, one far left
384 384 | | | |
385 385 | o | | changeset: 11:832d76e6bdf2
386 386 | |\ \ \ parent: 6:b105a072e251
387 387 | | | | | parent: 10:74c64d036d72
388 388 | | | | | user: test
389 389 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
390 390 | | | | | summary: (11) expand
391 391 | | | | |
392 392 | | o---+ changeset: 10:74c64d036d72
393 393 | | | | | parent: 0:e6eb3150255d
394 394 | |/ / / parent: 6:b105a072e251
395 395 | | | | user: test
396 396 | | | | date: Thu Jan 01 00:00:10 1970 +0000
397 397 | | | | summary: (10) merge two known; one immediate left, one near right
398 398 | | | |
399 399 o | | | changeset: 9:7010c0af0a35
400 400 |\ \ \ \ parent: 7:b632bb1b1224
401 401 | | | | | parent: 8:7a0b11f71937
402 402 | | | | | user: test
403 403 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
404 404 | | | | | summary: (9) expand
405 405 | | | | |
406 406 | o-----+ changeset: 8:7a0b11f71937
407 407 | | | | | parent: 0:e6eb3150255d
408 408 |/ / / / parent: 7:b632bb1b1224
409 409 | | | | user: test
410 410 | | | | date: Thu Jan 01 00:00:08 1970 +0000
411 411 | | | | summary: (8) merge two known; one immediate left, one far right
412 412 | | | |
413 413 o | | | changeset: 7:b632bb1b1224
414 414 |\ \ \ \ parent: 2:3d9a33b8d1e1
415 415 | | | | | parent: 5:4409d547b708
416 416 | | | | | user: test
417 417 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
418 418 | | | | | summary: (7) expand
419 419 | | | | |
420 420 +---o | | changeset: 6:b105a072e251
421 421 | |/ / / parent: 2:3d9a33b8d1e1
422 422 | | | | parent: 5:4409d547b708
423 423 | | | | user: test
424 424 | | | | date: Thu Jan 01 00:00:06 1970 +0000
425 425 | | | | summary: (6) merge two known; one immediate left, one far left
426 426 | | | |
427 427 | o | | changeset: 5:4409d547b708
428 428 | |\ \ \ parent: 3:27eef8ed80b4
429 429 | | | | | parent: 4:26a8bac39d9f
430 430 | | | | | user: test
431 431 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
432 432 | | | | | summary: (5) expand
433 433 | | | | |
434 434 | | o | | changeset: 4:26a8bac39d9f
435 435 | |/|/ / parent: 1:6db2ef61d156
436 436 | | | | parent: 3:27eef8ed80b4
437 437 | | | | user: test
438 438 | | | | date: Thu Jan 01 00:00:04 1970 +0000
439 439 | | | | summary: (4) merge two known; one immediate left, one immediate right
440 440 | | | |
441 441 | o | | changeset: 3:27eef8ed80b4
442 442 |/ / / user: test
443 443 | | | date: Thu Jan 01 00:00:03 1970 +0000
444 444 | | | summary: (3) collapse
445 445 | | |
446 446 o | | changeset: 2:3d9a33b8d1e1
447 447 |/ / user: test
448 448 | | date: Thu Jan 01 00:00:02 1970 +0000
449 449 | | summary: (2) collapse
450 450 | |
451 451 o | changeset: 1:6db2ef61d156
452 452 |/ user: test
453 453 | date: Thu Jan 01 00:00:01 1970 +0000
454 454 | summary: (1) collapse
455 455 |
456 456 o changeset: 0:e6eb3150255d
457 457 user: test
458 458 date: Thu Jan 01 00:00:00 1970 +0000
459 459 summary: (0) root
460 460
461 461
462 462 File glog:
463 463 $ hg glog a
464 464 @ changeset: 34:fea3ac5810e0
465 465 | tag: tip
466 466 | parent: 32:d06dffa21a31
467 467 | user: test
468 468 | date: Thu Jan 01 00:00:34 1970 +0000
469 469 | summary: (34) head
470 470 |
471 471 | o changeset: 33:68608f5145f9
472 472 | | parent: 18:1aa84d96232a
473 473 | | user: test
474 474 | | date: Thu Jan 01 00:00:33 1970 +0000
475 475 | | summary: (33) head
476 476 | |
477 477 o | changeset: 32:d06dffa21a31
478 478 |\ \ parent: 27:886ed638191b
479 479 | | | parent: 31:621d83e11f67
480 480 | | | user: test
481 481 | | | date: Thu Jan 01 00:00:32 1970 +0000
482 482 | | | summary: (32) expand
483 483 | | |
484 484 | o | changeset: 31:621d83e11f67
485 485 | |\ \ parent: 21:d42a756af44d
486 486 | | | | parent: 30:6e11cd4b648f
487 487 | | | | user: test
488 488 | | | | date: Thu Jan 01 00:00:31 1970 +0000
489 489 | | | | summary: (31) expand
490 490 | | | |
491 491 | | o | changeset: 30:6e11cd4b648f
492 492 | | |\ \ parent: 28:44ecd0b9ae99
493 493 | | | | | parent: 29:cd9bb2be7593
494 494 | | | | | user: test
495 495 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
496 496 | | | | | summary: (30) expand
497 497 | | | | |
498 498 | | | o | changeset: 29:cd9bb2be7593
499 499 | | | | | parent: 0:e6eb3150255d
500 500 | | | | | user: test
501 501 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
502 502 | | | | | summary: (29) regular commit
503 503 | | | | |
504 504 | | o | | changeset: 28:44ecd0b9ae99
505 505 | | |\ \ \ parent: 1:6db2ef61d156
506 506 | | | | | | parent: 26:7f25b6c2f0b9
507 507 | | | | | | user: test
508 508 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
509 509 | | | | | | summary: (28) merge zero known
510 510 | | | | | |
511 511 o | | | | | changeset: 27:886ed638191b
512 512 |/ / / / / parent: 21:d42a756af44d
513 513 | | | | | user: test
514 514 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
515 515 | | | | | summary: (27) collapse
516 516 | | | | |
517 517 | | o---+ changeset: 26:7f25b6c2f0b9
518 518 | | | | | parent: 18:1aa84d96232a
519 519 | | | | | parent: 25:91da8ed57247
520 520 | | | | | user: test
521 521 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
522 522 | | | | | summary: (26) merge one known; far right
523 523 | | | | |
524 524 +---o | | changeset: 25:91da8ed57247
525 525 | | | | | parent: 21:d42a756af44d
526 526 | | | | | parent: 24:a9c19a3d96b7
527 527 | | | | | user: test
528 528 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
529 529 | | | | | summary: (25) merge one known; far left
530 530 | | | | |
531 531 | | o | | changeset: 24:a9c19a3d96b7
532 532 | | |\| | parent: 0:e6eb3150255d
533 533 | | | | | parent: 23:a01cddf0766d
534 534 | | | | | user: test
535 535 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
536 536 | | | | | summary: (24) merge one known; immediate right
537 537 | | | | |
538 538 | | o | | changeset: 23:a01cddf0766d
539 539 | |/| | | parent: 1:6db2ef61d156
540 540 | | | | | parent: 22:e0d9cccacb5d
541 541 | | | | | user: test
542 542 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
543 543 | | | | | summary: (23) merge one known; immediate left
544 544 | | | | |
545 545 +---o---+ changeset: 22:e0d9cccacb5d
546 546 | | | | parent: 18:1aa84d96232a
547 547 | | / / parent: 21:d42a756af44d
548 548 | | | | user: test
549 549 | | | | date: Thu Jan 01 00:00:22 1970 +0000
550 550 | | | | summary: (22) merge two known; one far left, one far right
551 551 | | | |
552 552 o | | | changeset: 21:d42a756af44d
553 553 |\ \ \ \ parent: 19:31ddc2c1573b
554 554 | | | | | parent: 20:d30ed6450e32
555 555 | | | | | user: test
556 556 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
557 557 | | | | | summary: (21) expand
558 558 | | | | |
559 559 | o---+-+ changeset: 20:d30ed6450e32
560 560 | | | | parent: 0:e6eb3150255d
561 561 | / / / parent: 18:1aa84d96232a
562 562 | | | | user: test
563 563 | | | | date: Thu Jan 01 00:00:20 1970 +0000
564 564 | | | | summary: (20) merge two known; two far right
565 565 | | | |
566 566 o | | | changeset: 19:31ddc2c1573b
567 567 |\ \ \ \ parent: 15:1dda3f72782d
568 568 | | | | | parent: 17:44765d7c06e0
569 569 | | | | | user: test
570 570 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
571 571 | | | | | summary: (19) expand
572 572 | | | | |
573 573 +---+---o changeset: 18:1aa84d96232a
574 574 | | | | parent: 1:6db2ef61d156
575 575 | | | | parent: 15:1dda3f72782d
576 576 | | | | user: test
577 577 | | | | date: Thu Jan 01 00:00:18 1970 +0000
578 578 | | | | summary: (18) merge two known; two far left
579 579 | | | |
580 580 | o | | changeset: 17:44765d7c06e0
581 581 | |\ \ \ parent: 12:86b91144a6e9
582 582 | | | | | parent: 16:3677d192927d
583 583 | | | | | user: test
584 584 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
585 585 | | | | | summary: (17) expand
586 586 | | | | |
587 587 | | o---+ changeset: 16:3677d192927d
588 588 | | | | | parent: 0:e6eb3150255d
589 589 | | |/ / parent: 1:6db2ef61d156
590 590 | | | | user: test
591 591 | | | | date: Thu Jan 01 00:00:16 1970 +0000
592 592 | | | | summary: (16) merge two known; one immediate right, one near right
593 593 | | | |
594 594 o | | | changeset: 15:1dda3f72782d
595 595 |\ \ \ \ parent: 13:22d8966a97e3
596 596 | | | | | parent: 14:8eac370358ef
597 597 | | | | | user: test
598 598 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
599 599 | | | | | summary: (15) expand
600 600 | | | | |
601 601 | o-----+ changeset: 14:8eac370358ef
602 602 | | | | | parent: 0:e6eb3150255d
603 603 | |/ / / parent: 12:86b91144a6e9
604 604 | | | | user: test
605 605 | | | | date: Thu Jan 01 00:00:14 1970 +0000
606 606 | | | | summary: (14) merge two known; one immediate right, one far right
607 607 | | | |
608 608 o | | | changeset: 13:22d8966a97e3
609 609 |\ \ \ \ parent: 9:7010c0af0a35
610 610 | | | | | parent: 11:832d76e6bdf2
611 611 | | | | | user: test
612 612 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
613 613 | | | | | summary: (13) expand
614 614 | | | | |
615 615 +---o | | changeset: 12:86b91144a6e9
616 616 | | |/ / parent: 1:6db2ef61d156
617 617 | | | | parent: 9:7010c0af0a35
618 618 | | | | user: test
619 619 | | | | date: Thu Jan 01 00:00:12 1970 +0000
620 620 | | | | summary: (12) merge two known; one immediate right, one far left
621 621 | | | |
622 622 | o | | changeset: 11:832d76e6bdf2
623 623 | |\ \ \ parent: 6:b105a072e251
624 624 | | | | | parent: 10:74c64d036d72
625 625 | | | | | user: test
626 626 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
627 627 | | | | | summary: (11) expand
628 628 | | | | |
629 629 | | o---+ changeset: 10:74c64d036d72
630 630 | | | | | parent: 0:e6eb3150255d
631 631 | |/ / / parent: 6:b105a072e251
632 632 | | | | user: test
633 633 | | | | date: Thu Jan 01 00:00:10 1970 +0000
634 634 | | | | summary: (10) merge two known; one immediate left, one near right
635 635 | | | |
636 636 o | | | changeset: 9:7010c0af0a35
637 637 |\ \ \ \ parent: 7:b632bb1b1224
638 638 | | | | | parent: 8:7a0b11f71937
639 639 | | | | | user: test
640 640 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
641 641 | | | | | summary: (9) expand
642 642 | | | | |
643 643 | o-----+ changeset: 8:7a0b11f71937
644 644 | | | | | parent: 0:e6eb3150255d
645 645 |/ / / / parent: 7:b632bb1b1224
646 646 | | | | user: test
647 647 | | | | date: Thu Jan 01 00:00:08 1970 +0000
648 648 | | | | summary: (8) merge two known; one immediate left, one far right
649 649 | | | |
650 650 o | | | changeset: 7:b632bb1b1224
651 651 |\ \ \ \ parent: 2:3d9a33b8d1e1
652 652 | | | | | parent: 5:4409d547b708
653 653 | | | | | user: test
654 654 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
655 655 | | | | | summary: (7) expand
656 656 | | | | |
657 657 +---o | | changeset: 6:b105a072e251
658 658 | |/ / / parent: 2:3d9a33b8d1e1
659 659 | | | | parent: 5:4409d547b708
660 660 | | | | user: test
661 661 | | | | date: Thu Jan 01 00:00:06 1970 +0000
662 662 | | | | summary: (6) merge two known; one immediate left, one far left
663 663 | | | |
664 664 | o | | changeset: 5:4409d547b708
665 665 | |\ \ \ parent: 3:27eef8ed80b4
666 666 | | | | | parent: 4:26a8bac39d9f
667 667 | | | | | user: test
668 668 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
669 669 | | | | | summary: (5) expand
670 670 | | | | |
671 671 | | o | | changeset: 4:26a8bac39d9f
672 672 | |/|/ / parent: 1:6db2ef61d156
673 673 | | | | parent: 3:27eef8ed80b4
674 674 | | | | user: test
675 675 | | | | date: Thu Jan 01 00:00:04 1970 +0000
676 676 | | | | summary: (4) merge two known; one immediate left, one immediate right
677 677 | | | |
678 678 | o | | changeset: 3:27eef8ed80b4
679 679 |/ / / user: test
680 680 | | | date: Thu Jan 01 00:00:03 1970 +0000
681 681 | | | summary: (3) collapse
682 682 | | |
683 683 o | | changeset: 2:3d9a33b8d1e1
684 684 |/ / user: test
685 685 | | date: Thu Jan 01 00:00:02 1970 +0000
686 686 | | summary: (2) collapse
687 687 | |
688 688 o | changeset: 1:6db2ef61d156
689 689 |/ user: test
690 690 | date: Thu Jan 01 00:00:01 1970 +0000
691 691 | summary: (1) collapse
692 692 |
693 693 o changeset: 0:e6eb3150255d
694 694 user: test
695 695 date: Thu Jan 01 00:00:00 1970 +0000
696 696 summary: (0) root
697 697
698 698
699 699 File glog per revset:
700 700
701 701 $ hg glog -r 'file("a")'
702 702 @ changeset: 34:fea3ac5810e0
703 703 | tag: tip
704 704 | parent: 32:d06dffa21a31
705 705 | user: test
706 706 | date: Thu Jan 01 00:00:34 1970 +0000
707 707 | summary: (34) head
708 708 |
709 709 | o changeset: 33:68608f5145f9
710 710 | | parent: 18:1aa84d96232a
711 711 | | user: test
712 712 | | date: Thu Jan 01 00:00:33 1970 +0000
713 713 | | summary: (33) head
714 714 | |
715 715 o | changeset: 32:d06dffa21a31
716 716 |\ \ parent: 27:886ed638191b
717 717 | | | parent: 31:621d83e11f67
718 718 | | | user: test
719 719 | | | date: Thu Jan 01 00:00:32 1970 +0000
720 720 | | | summary: (32) expand
721 721 | | |
722 722 | o | changeset: 31:621d83e11f67
723 723 | |\ \ parent: 21:d42a756af44d
724 724 | | | | parent: 30:6e11cd4b648f
725 725 | | | | user: test
726 726 | | | | date: Thu Jan 01 00:00:31 1970 +0000
727 727 | | | | summary: (31) expand
728 728 | | | |
729 729 | | o | changeset: 30:6e11cd4b648f
730 730 | | |\ \ parent: 28:44ecd0b9ae99
731 731 | | | | | parent: 29:cd9bb2be7593
732 732 | | | | | user: test
733 733 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
734 734 | | | | | summary: (30) expand
735 735 | | | | |
736 736 | | | o | changeset: 29:cd9bb2be7593
737 737 | | | | | parent: 0:e6eb3150255d
738 738 | | | | | user: test
739 739 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
740 740 | | | | | summary: (29) regular commit
741 741 | | | | |
742 742 | | o | | changeset: 28:44ecd0b9ae99
743 743 | | |\ \ \ parent: 1:6db2ef61d156
744 744 | | | | | | parent: 26:7f25b6c2f0b9
745 745 | | | | | | user: test
746 746 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
747 747 | | | | | | summary: (28) merge zero known
748 748 | | | | | |
749 749 o | | | | | changeset: 27:886ed638191b
750 750 |/ / / / / parent: 21:d42a756af44d
751 751 | | | | | user: test
752 752 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
753 753 | | | | | summary: (27) collapse
754 754 | | | | |
755 755 | | o---+ changeset: 26:7f25b6c2f0b9
756 756 | | | | | parent: 18:1aa84d96232a
757 757 | | | | | parent: 25:91da8ed57247
758 758 | | | | | user: test
759 759 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
760 760 | | | | | summary: (26) merge one known; far right
761 761 | | | | |
762 762 +---o | | changeset: 25:91da8ed57247
763 763 | | | | | parent: 21:d42a756af44d
764 764 | | | | | parent: 24:a9c19a3d96b7
765 765 | | | | | user: test
766 766 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
767 767 | | | | | summary: (25) merge one known; far left
768 768 | | | | |
769 769 | | o | | changeset: 24:a9c19a3d96b7
770 770 | | |\| | parent: 0:e6eb3150255d
771 771 | | | | | parent: 23:a01cddf0766d
772 772 | | | | | user: test
773 773 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
774 774 | | | | | summary: (24) merge one known; immediate right
775 775 | | | | |
776 776 | | o | | changeset: 23:a01cddf0766d
777 777 | |/| | | parent: 1:6db2ef61d156
778 778 | | | | | parent: 22:e0d9cccacb5d
779 779 | | | | | user: test
780 780 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
781 781 | | | | | summary: (23) merge one known; immediate left
782 782 | | | | |
783 783 +---o---+ changeset: 22:e0d9cccacb5d
784 784 | | | | parent: 18:1aa84d96232a
785 785 | | / / parent: 21:d42a756af44d
786 786 | | | | user: test
787 787 | | | | date: Thu Jan 01 00:00:22 1970 +0000
788 788 | | | | summary: (22) merge two known; one far left, one far right
789 789 | | | |
790 790 o | | | changeset: 21:d42a756af44d
791 791 |\ \ \ \ parent: 19:31ddc2c1573b
792 792 | | | | | parent: 20:d30ed6450e32
793 793 | | | | | user: test
794 794 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
795 795 | | | | | summary: (21) expand
796 796 | | | | |
797 797 | o---+-+ changeset: 20:d30ed6450e32
798 798 | | | | parent: 0:e6eb3150255d
799 799 | / / / parent: 18:1aa84d96232a
800 800 | | | | user: test
801 801 | | | | date: Thu Jan 01 00:00:20 1970 +0000
802 802 | | | | summary: (20) merge two known; two far right
803 803 | | | |
804 804 o | | | changeset: 19:31ddc2c1573b
805 805 |\ \ \ \ parent: 15:1dda3f72782d
806 806 | | | | | parent: 17:44765d7c06e0
807 807 | | | | | user: test
808 808 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
809 809 | | | | | summary: (19) expand
810 810 | | | | |
811 811 +---+---o changeset: 18:1aa84d96232a
812 812 | | | | parent: 1:6db2ef61d156
813 813 | | | | parent: 15:1dda3f72782d
814 814 | | | | user: test
815 815 | | | | date: Thu Jan 01 00:00:18 1970 +0000
816 816 | | | | summary: (18) merge two known; two far left
817 817 | | | |
818 818 | o | | changeset: 17:44765d7c06e0
819 819 | |\ \ \ parent: 12:86b91144a6e9
820 820 | | | | | parent: 16:3677d192927d
821 821 | | | | | user: test
822 822 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
823 823 | | | | | summary: (17) expand
824 824 | | | | |
825 825 | | o---+ changeset: 16:3677d192927d
826 826 | | | | | parent: 0:e6eb3150255d
827 827 | | |/ / parent: 1:6db2ef61d156
828 828 | | | | user: test
829 829 | | | | date: Thu Jan 01 00:00:16 1970 +0000
830 830 | | | | summary: (16) merge two known; one immediate right, one near right
831 831 | | | |
832 832 o | | | changeset: 15:1dda3f72782d
833 833 |\ \ \ \ parent: 13:22d8966a97e3
834 834 | | | | | parent: 14:8eac370358ef
835 835 | | | | | user: test
836 836 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
837 837 | | | | | summary: (15) expand
838 838 | | | | |
839 839 | o-----+ changeset: 14:8eac370358ef
840 840 | | | | | parent: 0:e6eb3150255d
841 841 | |/ / / parent: 12:86b91144a6e9
842 842 | | | | user: test
843 843 | | | | date: Thu Jan 01 00:00:14 1970 +0000
844 844 | | | | summary: (14) merge two known; one immediate right, one far right
845 845 | | | |
846 846 o | | | changeset: 13:22d8966a97e3
847 847 |\ \ \ \ parent: 9:7010c0af0a35
848 848 | | | | | parent: 11:832d76e6bdf2
849 849 | | | | | user: test
850 850 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
851 851 | | | | | summary: (13) expand
852 852 | | | | |
853 853 +---o | | changeset: 12:86b91144a6e9
854 854 | | |/ / parent: 1:6db2ef61d156
855 855 | | | | parent: 9:7010c0af0a35
856 856 | | | | user: test
857 857 | | | | date: Thu Jan 01 00:00:12 1970 +0000
858 858 | | | | summary: (12) merge two known; one immediate right, one far left
859 859 | | | |
860 860 | o | | changeset: 11:832d76e6bdf2
861 861 | |\ \ \ parent: 6:b105a072e251
862 862 | | | | | parent: 10:74c64d036d72
863 863 | | | | | user: test
864 864 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
865 865 | | | | | summary: (11) expand
866 866 | | | | |
867 867 | | o---+ changeset: 10:74c64d036d72
868 868 | | | | | parent: 0:e6eb3150255d
869 869 | |/ / / parent: 6:b105a072e251
870 870 | | | | user: test
871 871 | | | | date: Thu Jan 01 00:00:10 1970 +0000
872 872 | | | | summary: (10) merge two known; one immediate left, one near right
873 873 | | | |
874 874 o | | | changeset: 9:7010c0af0a35
875 875 |\ \ \ \ parent: 7:b632bb1b1224
876 876 | | | | | parent: 8:7a0b11f71937
877 877 | | | | | user: test
878 878 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
879 879 | | | | | summary: (9) expand
880 880 | | | | |
881 881 | o-----+ changeset: 8:7a0b11f71937
882 882 | | | | | parent: 0:e6eb3150255d
883 883 |/ / / / parent: 7:b632bb1b1224
884 884 | | | | user: test
885 885 | | | | date: Thu Jan 01 00:00:08 1970 +0000
886 886 | | | | summary: (8) merge two known; one immediate left, one far right
887 887 | | | |
888 888 o | | | changeset: 7:b632bb1b1224
889 889 |\ \ \ \ parent: 2:3d9a33b8d1e1
890 890 | | | | | parent: 5:4409d547b708
891 891 | | | | | user: test
892 892 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
893 893 | | | | | summary: (7) expand
894 894 | | | | |
895 895 +---o | | changeset: 6:b105a072e251
896 896 | |/ / / parent: 2:3d9a33b8d1e1
897 897 | | | | parent: 5:4409d547b708
898 898 | | | | user: test
899 899 | | | | date: Thu Jan 01 00:00:06 1970 +0000
900 900 | | | | summary: (6) merge two known; one immediate left, one far left
901 901 | | | |
902 902 | o | | changeset: 5:4409d547b708
903 903 | |\ \ \ parent: 3:27eef8ed80b4
904 904 | | | | | parent: 4:26a8bac39d9f
905 905 | | | | | user: test
906 906 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
907 907 | | | | | summary: (5) expand
908 908 | | | | |
909 909 | | o | | changeset: 4:26a8bac39d9f
910 910 | |/|/ / parent: 1:6db2ef61d156
911 911 | | | | parent: 3:27eef8ed80b4
912 912 | | | | user: test
913 913 | | | | date: Thu Jan 01 00:00:04 1970 +0000
914 914 | | | | summary: (4) merge two known; one immediate left, one immediate right
915 915 | | | |
916 916 | o | | changeset: 3:27eef8ed80b4
917 917 |/ / / user: test
918 918 | | | date: Thu Jan 01 00:00:03 1970 +0000
919 919 | | | summary: (3) collapse
920 920 | | |
921 921 o | | changeset: 2:3d9a33b8d1e1
922 922 |/ / user: test
923 923 | | date: Thu Jan 01 00:00:02 1970 +0000
924 924 | | summary: (2) collapse
925 925 | |
926 926 o | changeset: 1:6db2ef61d156
927 927 |/ user: test
928 928 | date: Thu Jan 01 00:00:01 1970 +0000
929 929 | summary: (1) collapse
930 930 |
931 931 o changeset: 0:e6eb3150255d
932 932 user: test
933 933 date: Thu Jan 01 00:00:00 1970 +0000
934 934 summary: (0) root
935 935
936 936
937 937
938 938 File glog per revset (only merges):
939 939
940 940 $ hg log -G -r 'file("a")' -m
941 941 o changeset: 32:d06dffa21a31
942 942 |\ parent: 27:886ed638191b
943 943 | | parent: 31:621d83e11f67
944 944 | | user: test
945 945 | | date: Thu Jan 01 00:00:32 1970 +0000
946 946 | | summary: (32) expand
947 947 | |
948 948 o | changeset: 31:621d83e11f67
949 949 |\| parent: 21:d42a756af44d
950 950 | | parent: 30:6e11cd4b648f
951 951 | | user: test
952 952 | | date: Thu Jan 01 00:00:31 1970 +0000
953 953 | | summary: (31) expand
954 954 | |
955 955 o | changeset: 30:6e11cd4b648f
956 956 |\ \ parent: 28:44ecd0b9ae99
957 957 | | | parent: 29:cd9bb2be7593
958 958 | | | user: test
959 959 | | | date: Thu Jan 01 00:00:30 1970 +0000
960 960 | | | summary: (30) expand
961 961 | | |
962 962 o | | changeset: 28:44ecd0b9ae99
963 963 |\ \ \ parent: 1:6db2ef61d156
964 964 | | | | parent: 26:7f25b6c2f0b9
965 965 | | | | user: test
966 966 | | | | date: Thu Jan 01 00:00:28 1970 +0000
967 967 | | | | summary: (28) merge zero known
968 968 | | | |
969 969 o | | | changeset: 26:7f25b6c2f0b9
970 970 |\ \ \ \ parent: 18:1aa84d96232a
971 971 | | | | | parent: 25:91da8ed57247
972 972 | | | | | user: test
973 973 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
974 974 | | | | | summary: (26) merge one known; far right
975 975 | | | | |
976 976 | o-----+ changeset: 25:91da8ed57247
977 977 | | | | | parent: 21:d42a756af44d
978 978 | | | | | parent: 24:a9c19a3d96b7
979 979 | | | | | user: test
980 980 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
981 981 | | | | | summary: (25) merge one known; far left
982 982 | | | | |
983 983 | o | | | changeset: 24:a9c19a3d96b7
984 984 | |\ \ \ \ parent: 0:e6eb3150255d
985 985 | | | | | | parent: 23:a01cddf0766d
986 986 | | | | | | user: test
987 987 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
988 988 | | | | | | summary: (24) merge one known; immediate right
989 989 | | | | | |
990 990 | o---+ | | changeset: 23:a01cddf0766d
991 991 | | | | | | parent: 1:6db2ef61d156
992 992 | | | | | | parent: 22:e0d9cccacb5d
993 993 | | | | | | user: test
994 994 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
995 995 | | | | | | summary: (23) merge one known; immediate left
996 996 | | | | | |
997 997 | o-------+ changeset: 22:e0d9cccacb5d
998 998 | | | | | | parent: 18:1aa84d96232a
999 999 |/ / / / / parent: 21:d42a756af44d
1000 1000 | | | | | user: test
1001 1001 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1002 1002 | | | | | summary: (22) merge two known; one far left, one far right
1003 1003 | | | | |
1004 1004 | | | | o changeset: 21:d42a756af44d
1005 1005 | | | | |\ parent: 19:31ddc2c1573b
1006 1006 | | | | | | parent: 20:d30ed6450e32
1007 1007 | | | | | | user: test
1008 1008 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1009 1009 | | | | | | summary: (21) expand
1010 1010 | | | | | |
1011 1011 +-+-------o changeset: 20:d30ed6450e32
1012 1012 | | | | | parent: 0:e6eb3150255d
1013 1013 | | | | | parent: 18:1aa84d96232a
1014 1014 | | | | | user: test
1015 1015 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1016 1016 | | | | | summary: (20) merge two known; two far right
1017 1017 | | | | |
1018 1018 | | | | o changeset: 19:31ddc2c1573b
1019 1019 | | | | |\ parent: 15:1dda3f72782d
1020 1020 | | | | | | parent: 17:44765d7c06e0
1021 1021 | | | | | | user: test
1022 1022 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1023 1023 | | | | | | summary: (19) expand
1024 1024 | | | | | |
1025 1025 o---+---+ | changeset: 18:1aa84d96232a
1026 1026 | | | | | parent: 1:6db2ef61d156
1027 1027 / / / / / parent: 15:1dda3f72782d
1028 1028 | | | | | user: test
1029 1029 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1030 1030 | | | | | summary: (18) merge two known; two far left
1031 1031 | | | | |
1032 1032 | | | | o changeset: 17:44765d7c06e0
1033 1033 | | | | |\ parent: 12:86b91144a6e9
1034 1034 | | | | | | parent: 16:3677d192927d
1035 1035 | | | | | | user: test
1036 1036 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1037 1037 | | | | | | summary: (17) expand
1038 1038 | | | | | |
1039 1039 +-+-------o changeset: 16:3677d192927d
1040 1040 | | | | | parent: 0:e6eb3150255d
1041 1041 | | | | | parent: 1:6db2ef61d156
1042 1042 | | | | | user: test
1043 1043 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1044 1044 | | | | | summary: (16) merge two known; one immediate right, one near right
1045 1045 | | | | |
1046 1046 | | | o | changeset: 15:1dda3f72782d
1047 1047 | | | |\ \ parent: 13:22d8966a97e3
1048 1048 | | | | | | parent: 14:8eac370358ef
1049 1049 | | | | | | user: test
1050 1050 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1051 1051 | | | | | | summary: (15) expand
1052 1052 | | | | | |
1053 1053 +-------o | changeset: 14:8eac370358ef
1054 1054 | | | | |/ parent: 0:e6eb3150255d
1055 1055 | | | | | parent: 12:86b91144a6e9
1056 1056 | | | | | user: test
1057 1057 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1058 1058 | | | | | summary: (14) merge two known; one immediate right, one far right
1059 1059 | | | | |
1060 1060 | | | o | changeset: 13:22d8966a97e3
1061 1061 | | | |\ \ parent: 9:7010c0af0a35
1062 1062 | | | | | | parent: 11:832d76e6bdf2
1063 1063 | | | | | | user: test
1064 1064 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1065 1065 | | | | | | summary: (13) expand
1066 1066 | | | | | |
1067 1067 | +---+---o changeset: 12:86b91144a6e9
1068 1068 | | | | | parent: 1:6db2ef61d156
1069 1069 | | | | | parent: 9:7010c0af0a35
1070 1070 | | | | | user: test
1071 1071 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1072 1072 | | | | | summary: (12) merge two known; one immediate right, one far left
1073 1073 | | | | |
1074 1074 | | | | o changeset: 11:832d76e6bdf2
1075 1075 | | | | |\ parent: 6:b105a072e251
1076 1076 | | | | | | parent: 10:74c64d036d72
1077 1077 | | | | | | user: test
1078 1078 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1079 1079 | | | | | | summary: (11) expand
1080 1080 | | | | | |
1081 1081 +---------o changeset: 10:74c64d036d72
1082 1082 | | | | |/ parent: 0:e6eb3150255d
1083 1083 | | | | | parent: 6:b105a072e251
1084 1084 | | | | | user: test
1085 1085 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1086 1086 | | | | | summary: (10) merge two known; one immediate left, one near right
1087 1087 | | | | |
1088 1088 | | | o | changeset: 9:7010c0af0a35
1089 1089 | | | |\ \ parent: 7:b632bb1b1224
1090 1090 | | | | | | parent: 8:7a0b11f71937
1091 1091 | | | | | | user: test
1092 1092 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1093 1093 | | | | | | summary: (9) expand
1094 1094 | | | | | |
1095 1095 +-------o | changeset: 8:7a0b11f71937
1096 1096 | | | |/ / parent: 0:e6eb3150255d
1097 1097 | | | | | parent: 7:b632bb1b1224
1098 1098 | | | | | user: test
1099 1099 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1100 1100 | | | | | summary: (8) merge two known; one immediate left, one far right
1101 1101 | | | | |
1102 1102 | | | o | changeset: 7:b632bb1b1224
1103 1103 | | | |\ \ parent: 2:3d9a33b8d1e1
1104 1104 | | | | | | parent: 5:4409d547b708
1105 1105 | | | | | | user: test
1106 1106 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1107 1107 | | | | | | summary: (7) expand
1108 1108 | | | | | |
1109 1109 | | | +---o changeset: 6:b105a072e251
1110 1110 | | | | |/ parent: 2:3d9a33b8d1e1
1111 1111 | | | | | parent: 5:4409d547b708
1112 1112 | | | | | user: test
1113 1113 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1114 1114 | | | | | summary: (6) merge two known; one immediate left, one far left
1115 1115 | | | | |
1116 1116 | | | o | changeset: 5:4409d547b708
1117 1117 | | | |\ \ parent: 3:27eef8ed80b4
1118 1118 | | | | | | parent: 4:26a8bac39d9f
1119 1119 | | | | | | user: test
1120 1120 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1121 1121 | | | | | | summary: (5) expand
1122 1122 | | | | | |
1123 1123 | +---o | | changeset: 4:26a8bac39d9f
1124 1124 | | | |/ / parent: 1:6db2ef61d156
1125 1125 | | | | | parent: 3:27eef8ed80b4
1126 1126 | | | | | user: test
1127 1127 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1128 1128 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1129 1129 | | | | |
1130 1130
1131 1131
1132 1132 Empty revision range - display nothing:
1133 1133 $ hg glog -r 1..0
1134 1134
1135 1135 From outer space:
1136 1136 $ cd ..
1137 1137 $ hg glog -l1 repo
1138 1138 @ changeset: 34:fea3ac5810e0
1139 1139 | tag: tip
1140 1140 | parent: 32:d06dffa21a31
1141 1141 | user: test
1142 1142 | date: Thu Jan 01 00:00:34 1970 +0000
1143 1143 | summary: (34) head
1144 1144 |
1145 1145 $ hg glog -l1 repo/a
1146 1146 @ changeset: 34:fea3ac5810e0
1147 1147 | tag: tip
1148 1148 | parent: 32:d06dffa21a31
1149 1149 | user: test
1150 1150 | date: Thu Jan 01 00:00:34 1970 +0000
1151 1151 | summary: (34) head
1152 1152 |
1153 1153 $ hg glog -l1 repo/missing
1154 1154
1155 1155 File log with revs != cset revs:
1156 1156 $ hg init flog
1157 1157 $ cd flog
1158 1158 $ echo one >one
1159 1159 $ hg add one
1160 1160 $ hg commit -mone
1161 1161 $ echo two >two
1162 1162 $ hg add two
1163 1163 $ hg commit -mtwo
1164 1164 $ echo more >two
1165 1165 $ hg commit -mmore
1166 1166 $ hg glog two
1167 1167 @ changeset: 2:12c28321755b
1168 1168 | tag: tip
1169 1169 | user: test
1170 1170 | date: Thu Jan 01 00:00:00 1970 +0000
1171 1171 | summary: more
1172 1172 |
1173 1173 o changeset: 1:5ac72c0599bf
1174 1174 | user: test
1175 1175 | date: Thu Jan 01 00:00:00 1970 +0000
1176 1176 | summary: two
1177 1177 |
1178 1178
1179 1179 Issue1896: File log with explicit style
1180 1180 $ hg glog --style=default one
1181 1181 o changeset: 0:3d578b4a1f53
1182 1182 user: test
1183 1183 date: Thu Jan 01 00:00:00 1970 +0000
1184 1184 summary: one
1185 1185
1186 1186 Issue2395: glog --style header and footer
1187 1187 $ hg glog --style=xml one
1188 1188 <?xml version="1.0"?>
1189 1189 <log>
1190 1190 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1191 1191 <author email="test">test</author>
1192 1192 <date>1970-01-01T00:00:00+00:00</date>
1193 1193 <msg xml:space="preserve">one</msg>
1194 1194 </logentry>
1195 1195 </log>
1196 1196
1197 1197 $ cd ..
1198 1198
1199 1199 Incoming and outgoing:
1200 1200
1201 1201 $ hg clone -U -r31 repo repo2
1202 1202 adding changesets
1203 1203 adding manifests
1204 1204 adding file changes
1205 1205 added 31 changesets with 31 changes to 1 files
1206 1206 $ cd repo2
1207 1207
1208 1208 $ hg incoming --graph ../repo
1209 1209 comparing with ../repo
1210 1210 searching for changes
1211 1211 o changeset: 34:fea3ac5810e0
1212 1212 | tag: tip
1213 1213 | parent: 32:d06dffa21a31
1214 1214 | user: test
1215 1215 | date: Thu Jan 01 00:00:34 1970 +0000
1216 1216 | summary: (34) head
1217 1217 |
1218 1218 | o changeset: 33:68608f5145f9
1219 1219 | parent: 18:1aa84d96232a
1220 1220 | user: test
1221 1221 | date: Thu Jan 01 00:00:33 1970 +0000
1222 1222 | summary: (33) head
1223 1223 |
1224 1224 o changeset: 32:d06dffa21a31
1225 1225 | parent: 27:886ed638191b
1226 1226 | parent: 31:621d83e11f67
1227 1227 | user: test
1228 1228 | date: Thu Jan 01 00:00:32 1970 +0000
1229 1229 | summary: (32) expand
1230 1230 |
1231 1231 o changeset: 27:886ed638191b
1232 1232 parent: 21:d42a756af44d
1233 1233 user: test
1234 1234 date: Thu Jan 01 00:00:27 1970 +0000
1235 1235 summary: (27) collapse
1236 1236
1237 1237 $ cd ..
1238 1238
1239 1239 $ hg -R repo outgoing --graph repo2
1240 1240 comparing with repo2
1241 1241 searching for changes
1242 1242 @ changeset: 34:fea3ac5810e0
1243 1243 | tag: tip
1244 1244 | parent: 32:d06dffa21a31
1245 1245 | user: test
1246 1246 | date: Thu Jan 01 00:00:34 1970 +0000
1247 1247 | summary: (34) head
1248 1248 |
1249 1249 | o changeset: 33:68608f5145f9
1250 1250 | parent: 18:1aa84d96232a
1251 1251 | user: test
1252 1252 | date: Thu Jan 01 00:00:33 1970 +0000
1253 1253 | summary: (33) head
1254 1254 |
1255 1255 o changeset: 32:d06dffa21a31
1256 1256 | parent: 27:886ed638191b
1257 1257 | parent: 31:621d83e11f67
1258 1258 | user: test
1259 1259 | date: Thu Jan 01 00:00:32 1970 +0000
1260 1260 | summary: (32) expand
1261 1261 |
1262 1262 o changeset: 27:886ed638191b
1263 1263 parent: 21:d42a756af44d
1264 1264 user: test
1265 1265 date: Thu Jan 01 00:00:27 1970 +0000
1266 1266 summary: (27) collapse
1267 1267
1268 1268
1269 1269 File + limit with revs != cset revs:
1270 1270 $ cd repo
1271 1271 $ touch b
1272 1272 $ hg ci -Aqm0
1273 1273 $ hg glog -l2 a
1274 1274 o changeset: 34:fea3ac5810e0
1275 1275 | parent: 32:d06dffa21a31
1276 1276 | user: test
1277 1277 | date: Thu Jan 01 00:00:34 1970 +0000
1278 1278 | summary: (34) head
1279 1279 |
1280 1280 | o changeset: 33:68608f5145f9
1281 1281 | | parent: 18:1aa84d96232a
1282 1282 | | user: test
1283 1283 | | date: Thu Jan 01 00:00:33 1970 +0000
1284 1284 | | summary: (33) head
1285 1285 | |
1286 1286
1287 1287 File + limit + -ra:b, (b - a) < limit:
1288 1288 $ hg glog -l3000 -r32:tip a
1289 1289 o changeset: 34:fea3ac5810e0
1290 1290 | parent: 32:d06dffa21a31
1291 1291 | user: test
1292 1292 | date: Thu Jan 01 00:00:34 1970 +0000
1293 1293 | summary: (34) head
1294 1294 |
1295 1295 | o changeset: 33:68608f5145f9
1296 1296 | | parent: 18:1aa84d96232a
1297 1297 | | user: test
1298 1298 | | date: Thu Jan 01 00:00:33 1970 +0000
1299 1299 | | summary: (33) head
1300 1300 | |
1301 1301 o | changeset: 32:d06dffa21a31
1302 1302 |\ \ parent: 27:886ed638191b
1303 1303 | | | parent: 31:621d83e11f67
1304 1304 | | | user: test
1305 1305 | | | date: Thu Jan 01 00:00:32 1970 +0000
1306 1306 | | | summary: (32) expand
1307 1307 | | |
1308 1308
1309 1309 Point out a common and an uncommon unshown parent
1310 1310
1311 1311 $ hg glog -r 'rev(8) or rev(9)'
1312 1312 o changeset: 9:7010c0af0a35
1313 1313 |\ parent: 7:b632bb1b1224
1314 1314 | | parent: 8:7a0b11f71937
1315 1315 | | user: test
1316 1316 | | date: Thu Jan 01 00:00:09 1970 +0000
1317 1317 | | summary: (9) expand
1318 1318 | |
1319 1319 o | changeset: 8:7a0b11f71937
1320 1320 |\| parent: 0:e6eb3150255d
1321 1321 | | parent: 7:b632bb1b1224
1322 1322 | | user: test
1323 1323 | | date: Thu Jan 01 00:00:08 1970 +0000
1324 1324 | | summary: (8) merge two known; one immediate left, one far right
1325 1325 | |
1326 1326
1327 1327 File + limit + -ra:b, b < tip:
1328 1328
1329 1329 $ hg glog -l1 -r32:34 a
1330 1330 o changeset: 34:fea3ac5810e0
1331 1331 | parent: 32:d06dffa21a31
1332 1332 | user: test
1333 1333 | date: Thu Jan 01 00:00:34 1970 +0000
1334 1334 | summary: (34) head
1335 1335 |
1336 1336
1337 1337 file(File) + limit + -ra:b, b < tip:
1338 1338
1339 1339 $ hg glog -l1 -r32:34 -r 'file("a")'
1340 1340 o changeset: 34:fea3ac5810e0
1341 1341 | parent: 32:d06dffa21a31
1342 1342 | user: test
1343 1343 | date: Thu Jan 01 00:00:34 1970 +0000
1344 1344 | summary: (34) head
1345 1345 |
1346 1346
1347 1347 limit(file(File) and a::b), b < tip:
1348 1348
1349 1349 $ hg glog -r 'limit(file("a") and 32::34, 1)'
1350 1350 o changeset: 32:d06dffa21a31
1351 1351 |\ parent: 27:886ed638191b
1352 1352 | | parent: 31:621d83e11f67
1353 1353 | | user: test
1354 1354 | | date: Thu Jan 01 00:00:32 1970 +0000
1355 1355 | | summary: (32) expand
1356 1356 | |
1357 1357
1358 1358 File + limit + -ra:b, b < tip:
1359 1359
1360 1360 $ hg glog -r 'limit(file("a") and 34::32, 1)'
1361 1361
1362 1362 File + limit + -ra:b, b < tip, (b - a) < limit:
1363 1363
1364 1364 $ hg glog -l10 -r33:34 a
1365 1365 o changeset: 34:fea3ac5810e0
1366 1366 | parent: 32:d06dffa21a31
1367 1367 | user: test
1368 1368 | date: Thu Jan 01 00:00:34 1970 +0000
1369 1369 | summary: (34) head
1370 1370 |
1371 1371 | o changeset: 33:68608f5145f9
1372 1372 | | parent: 18:1aa84d96232a
1373 1373 | | user: test
1374 1374 | | date: Thu Jan 01 00:00:33 1970 +0000
1375 1375 | | summary: (33) head
1376 1376 | |
1377 1377
1378 1378 Do not crash or produce strange graphs if history is buggy
1379 1379
1380 1380 $ hg branch branch
1381 1381 marked working directory as branch branch
1382 1382 (branches are permanent and global, did you want a bookmark?)
1383 1383 $ commit 36 "buggy merge: identical parents" 35 35
1384 1384 $ hg glog -l5
1385 1385 @ changeset: 36:08a19a744424
1386 1386 | branch: branch
1387 1387 | tag: tip
1388 1388 | parent: 35:9159c3644c5e
1389 1389 | parent: 35:9159c3644c5e
1390 1390 | user: test
1391 1391 | date: Thu Jan 01 00:00:36 1970 +0000
1392 1392 | summary: (36) buggy merge: identical parents
1393 1393 |
1394 1394 o changeset: 35:9159c3644c5e
1395 1395 | user: test
1396 1396 | date: Thu Jan 01 00:00:00 1970 +0000
1397 1397 | summary: 0
1398 1398 |
1399 1399 o changeset: 34:fea3ac5810e0
1400 1400 | parent: 32:d06dffa21a31
1401 1401 | user: test
1402 1402 | date: Thu Jan 01 00:00:34 1970 +0000
1403 1403 | summary: (34) head
1404 1404 |
1405 1405 | o changeset: 33:68608f5145f9
1406 1406 | | parent: 18:1aa84d96232a
1407 1407 | | user: test
1408 1408 | | date: Thu Jan 01 00:00:33 1970 +0000
1409 1409 | | summary: (33) head
1410 1410 | |
1411 1411 o | changeset: 32:d06dffa21a31
1412 1412 |\ \ parent: 27:886ed638191b
1413 1413 | | | parent: 31:621d83e11f67
1414 1414 | | | user: test
1415 1415 | | | date: Thu Jan 01 00:00:32 1970 +0000
1416 1416 | | | summary: (32) expand
1417 1417 | | |
1418 1418
1419 1419 Test log -G options
1420 1420
1421 1421 $ testlog() {
1422 1422 > hg log -G --print-revset "$@"
1423 1423 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1424 1424 > | sed 's/.*nodetag/nodetag/' > log.nodes
1425 1425 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1426 1426 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1427 1427 > diff -u log.nodes glog.nodes
1428 1428 > }
1429 1429
1430 1430 glog always reorders nodes which explains the difference with log
1431 1431
1432 1432 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1433 1433 ('group', ('group', ('or', ('or', ('or', ('or', ('or', ('symbol', '27'), ('symbol', '25')), ('symbol', '21')), ('symbol', '34')), ('symbol', '32')), ('symbol', '31'))))
1434 1434 --- log.nodes * (glob)
1435 1435 +++ glog.nodes * (glob)
1436 1436 @@ -1,6 +1,6 @@
1437 1437 -nodetag 27
1438 1438 -nodetag 25
1439 1439 -nodetag 21
1440 1440 nodetag 34
1441 1441 nodetag 32
1442 1442 nodetag 31
1443 1443 +nodetag 27
1444 1444 +nodetag 25
1445 1445 +nodetag 21
1446 1446 [1]
1447 1447 $ testlog -u test -u not-a-user
1448 1448 ('group', ('group', ('or', ('func', ('symbol', 'user'), ('string', 'test')), ('func', ('symbol', 'user'), ('string', 'not-a-user')))))
1449 1449 $ testlog -b not-a-branch
1450 1450 ('group', ('group', ('func', ('symbol', 'branch'), ('string', 'not-a-branch'))))
1451 1451 abort: unknown revision 'not-a-branch'!
1452 1452 abort: unknown revision 'not-a-branch'!
1453 1453 $ testlog -b default -b branch --only-branch branch
1454 1454 ('group', ('group', ('or', ('or', ('func', ('symbol', 'branch'), ('string', 'default')), ('func', ('symbol', 'branch'), ('string', 'branch'))), ('func', ('symbol', 'branch'), ('string', 'branch')))))
1455 1455 $ testlog -k expand -k merge
1456 1456 ('group', ('group', ('or', ('func', ('symbol', 'keyword'), ('string', 'expand')), ('func', ('symbol', 'keyword'), ('string', 'merge')))))
1457 1457 $ hg log -G --removed --template 'nodetag {rev}\n' | grep nodetag | wc -l
1458 1458 \s*0 (re)
1459 1459 $ hg log -G --only-merges --template 'nodetag {rev}\n' | grep nodetag | wc -l
1460 1460 \s*28 (re)
1461 1461 $ hg log -G --no-merges --template 'nodetag {rev}\n'
1462 1462 o nodetag 35
1463 1463 |
1464 1464 o nodetag 34
1465 1465 |\
1466 1466 | \
1467 1467 | |\
1468 1468 | | \
1469 1469 | | |\
1470 1470 | | | \
1471 1471 | | | |\
1472 1472 | | | | \
1473 1473 | | | | |\
1474 1474 +-+-+-+-----o nodetag 33
1475 1475 | | | | | |
1476 1476 +---------o nodetag 29
1477 1477 | | | | |
1478 1478 +-+-+---o nodetag 27
1479 1479 | | | |/
1480 1480 | | | o nodetag 3
1481 1481 | | |/
1482 1482 | | o nodetag 2
1483 1483 | |/
1484 1484 | o nodetag 1
1485 1485 |/
1486 1486 o nodetag 0
1487 1487
1488 1488 $ hg log -G -d 'brace ) in a date'
1489 1489 abort: invalid date: 'brace ) in a date'
1490 1490 [255]
1491 1491 $ testlog --prune 31 --prune 32
1492 1492 ('group', ('group', ('and', ('not', ('group', ('or', ('string', '31'), ('func', ('symbol', 'ancestors'), ('string', '31'))))), ('not', ('group', ('or', ('string', '32'), ('func', ('symbol', 'ancestors'), ('string', '32'))))))))
1493 1493
1494 1494 Dedicated repo for --follow and paths filtering. The g is crafted to
1495 1495 have 2 filelog topological heads in a linear changeset graph.
1496 1496
1497 1497 $ cd ..
1498 1498 $ hg init follow
1499 1499 $ cd follow
1500 1500 $ echo a > a
1501 1501 $ echo aa > aa
1502 1502 $ echo f > f
1503 1503 $ hg ci -Am "add a"
1504 1504 adding a
1505 1505 adding aa
1506 1506 adding f
1507 1507 $ hg cp a b
1508 1508 $ hg cp f g
1509 1509 $ hg ci -m "copy a b"
1510 1510 $ mkdir dir
1511 1511 $ hg mv b dir
1512 1512 $ echo g >> g
1513 1513 $ echo f >> f
1514 1514 $ hg ci -m "mv b dir/b"
1515 1515 $ hg mv a b
1516 1516 $ hg cp -f f g
1517 1517 $ echo a > d
1518 1518 $ hg add d
1519 1519 $ hg ci -m "mv a b; add d"
1520 1520 $ hg mv dir/b e
1521 1521 $ hg ci -m "mv dir/b e"
1522 1522 $ hg glog --template '({rev}) {desc|firstline}\n'
1523 1523 @ (4) mv dir/b e
1524 1524 |
1525 1525 o (3) mv a b; add d
1526 1526 |
1527 1527 o (2) mv b dir/b
1528 1528 |
1529 1529 o (1) copy a b
1530 1530 |
1531 1531 o (0) add a
1532 1532
1533 1533
1534 1534 $ testlog a
1535 1535 ('group', ('group', ('func', ('symbol', 'filelog'), ('string', 'a'))))
1536 1536 $ testlog a b
1537 1537 ('group', ('group', ('or', ('func', ('symbol', 'filelog'), ('string', 'a')), ('func', ('symbol', 'filelog'), ('string', 'b')))))
1538 1538
1539 1539 Test falling back to slow path for non-existing files
1540 1540
1541 1541 $ testlog a c
1542 ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('string', 'p:a'), ('string', 'p:c')))))
1542 ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('string', 'r:'), ('string', 'p:a')), ('string', 'p:c')))))
1543 1543
1544 1544 Test multiple --include/--exclude/paths
1545 1545
1546 1546 $ testlog --include a --include e --exclude b --exclude e a e
1547 ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('list', ('list', ('list', ('string', 'p:a'), ('string', 'p:e')), ('string', 'i:a')), ('string', 'i:e')), ('string', 'x:b')), ('string', 'x:e')))))
1547 ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('list', ('list', ('list', ('list', ('list', ('string', 'r:'), ('string', 'p:a')), ('string', 'p:e')), ('string', 'i:a')), ('string', 'i:e')), ('string', 'x:b')), ('string', 'x:e')))))
1548 1548
1549 1549 Test glob expansion of pats
1550 1550
1551 1551 $ expandglobs=`python -c "import mercurial.util; \
1552 1552 > print mercurial.util.expandglobs and 'true' or 'false'"`
1553 1553 $ if [ $expandglobs = "true" ]; then
1554 1554 > testlog 'a*';
1555 1555 > else
1556 1556 > testlog a*;
1557 1557 > fi;
1558 1558 ('group', ('group', ('func', ('symbol', 'filelog'), ('string', 'aa'))))
1559 1559
1560 1560 Test --follow on a directory
1561 1561
1562 1562 $ testlog -f dir
1563 1563 abort: cannot follow file not in parent revision: "dir"
1564 1564 abort: cannot follow file not in parent revision: "dir"
1565 1565 abort: cannot follow file not in parent revision: "dir"
1566 1566
1567 1567 Test --follow on file not in parent revision
1568 1568
1569 1569 $ testlog -f a
1570 1570 abort: cannot follow file not in parent revision: "a"
1571 1571 abort: cannot follow file not in parent revision: "a"
1572 1572 abort: cannot follow file not in parent revision: "a"
1573 1573
1574 1574 Test --follow and patterns
1575 1575
1576 1576 $ testlog -f 'glob:*'
1577 1577 abort: can only follow copies/renames for explicit filenames
1578 1578 abort: can only follow copies/renames for explicit filenames
1579 1579 abort: can only follow copies/renames for explicit filenames
1580 1580
1581 1581 Test --follow on a single rename
1582 1582
1583 1583 $ hg up -q 2
1584 1584 $ testlog -f a
1585 1585 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'a'))))
1586 1586
1587 1587 Test --follow and multiple renames
1588 1588
1589 1589 $ hg up -q tip
1590 1590 $ testlog -f e
1591 1591 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'e'))))
1592 1592
1593 1593 Test --follow and multiple filelog heads
1594 1594
1595 1595 $ hg up -q 2
1596 1596 $ testlog -f g
1597 1597 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g'))))
1598 1598 $ cat log.nodes
1599 1599 nodetag 2
1600 1600 nodetag 1
1601 1601 nodetag 0
1602 1602 $ hg up -q tip
1603 1603 $ testlog -f g
1604 1604 ('group', ('group', ('func', ('symbol', 'follow'), ('string', 'g'))))
1605 1605 $ cat log.nodes
1606 1606 nodetag 3
1607 1607 nodetag 2
1608 1608 nodetag 0
1609 1609
1610 1610 Test --follow and multiple files
1611 1611
1612 1612 $ testlog -f g e
1613 1613 ('group', ('group', ('or', ('func', ('symbol', 'follow'), ('string', 'g')), ('func', ('symbol', 'follow'), ('string', 'e')))))
1614 1614 $ cat log.nodes
1615 1615 nodetag 4
1616 1616 nodetag 3
1617 1617 nodetag 2
1618 1618 nodetag 1
1619 1619 nodetag 0
1620 1620
1621 1621 Test --follow-first
1622 1622
1623 1623 $ hg up -q 3
1624 1624 $ echo ee > e
1625 1625 $ hg ci -Am "add another e" e
1626 1626 created new head
1627 1627 $ hg merge --tool internal:other 4
1628 1628 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1629 1629 (branch merge, don't forget to commit)
1630 1630 $ echo merge > e
1631 1631 $ hg ci -m "merge 5 and 4"
1632 1632 $ testlog --follow-first
1633 1633 ('group', ('func', ('symbol', '_followfirst'), None))
1634 1634
1635 1635 Cannot compare with log --follow-first FILE as it never worked
1636 1636
1637 1637 $ hg log -G --print-revset --follow-first e
1638 1638 ('group', ('group', ('func', ('symbol', '_followfirst'), ('string', 'e'))))
1639 1639 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1640 1640 @ 6 merge 5 and 4
1641 1641 |\
1642 1642 o | 5 add another e
1643 1643 | |
1644 1644
1645 1645 Test --copies
1646 1646
1647 1647 $ hg log -G --copies --template "{rev} {desc|firstline} \
1648 1648 > copies: {file_copies_switch}\n"
1649 1649 @ 6 merge 5 and 4 copies:
1650 1650 |\
1651 1651 | o 5 add another e copies:
1652 1652 | |
1653 1653 o | 4 mv dir/b e copies: e (dir/b)
1654 1654 |/
1655 1655 o 3 mv a b; add d copies: b (a)g (f)
1656 1656 |
1657 1657 o 2 mv b dir/b copies: dir/b (b)
1658 1658 |
1659 1659 o 1 copy a b copies: b (a)g (f)
1660 1660 |
1661 1661 o 0 add a copies:
1662 1662
1663 Test "set:..." and parent revision
1664
1665 $ hg up -q 4
1666 $ testlog --include "set:copied()"
1667 ('group', ('group', ('func', ('symbol', '_matchfiles'), ('list', ('string', 'r:'), ('string', 'i:set:copied()')))))
1668 $ testlog -r "sort(file('set:copied()'), -rev)"
1669 ('group', ('group', ('func', ('symbol', 'sort'), ('list', ('func', ('symbol', 'file'), ('string', 'set:copied()')), ('negate', ('symbol', 'rev'))))))
General Comments 0
You need to be logged in to leave comments. Login now