##// END OF EJS Templates
revlog: fix a regression with null revision...
Alexander Plavin -
r19060:c010cb6f default
parent child Browse files
Show More
@@ -1,1344 +1,1340 b''
1 1 # revlog.py - storage back-end for mercurial
2 2 #
3 3 # Copyright 2005-2007 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 """Storage back-end for Mercurial.
9 9
10 10 This provides efficient delta storage with O(1) retrieve and append
11 11 and O(changes) merge between branches.
12 12 """
13 13
14 14 # import stuff from node for others to import from revlog
15 15 from node import bin, hex, nullid, nullrev
16 16 from i18n import _
17 17 import ancestor, mdiff, parsers, error, util, dagutil
18 18 import struct, zlib, errno
19 19
20 20 _pack = struct.pack
21 21 _unpack = struct.unpack
22 22 _compress = zlib.compress
23 23 _decompress = zlib.decompress
24 24 _sha = util.sha1
25 25
26 26 # revlog header flags
27 27 REVLOGV0 = 0
28 28 REVLOGNG = 1
29 29 REVLOGNGINLINEDATA = (1 << 16)
30 30 REVLOGGENERALDELTA = (1 << 17)
31 31 REVLOG_DEFAULT_FLAGS = REVLOGNGINLINEDATA
32 32 REVLOG_DEFAULT_FORMAT = REVLOGNG
33 33 REVLOG_DEFAULT_VERSION = REVLOG_DEFAULT_FORMAT | REVLOG_DEFAULT_FLAGS
34 34 REVLOGNG_FLAGS = REVLOGNGINLINEDATA | REVLOGGENERALDELTA
35 35
36 36 # revlog index flags
37 37 REVIDX_KNOWN_FLAGS = 0
38 38
39 39 # max size of revlog with inline data
40 40 _maxinline = 131072
41 41 _chunksize = 1048576
42 42
43 43 RevlogError = error.RevlogError
44 44 LookupError = error.LookupError
45 45
46 46 def getoffset(q):
47 47 return int(q >> 16)
48 48
49 49 def gettype(q):
50 50 return int(q & 0xFFFF)
51 51
52 52 def offset_type(offset, type):
53 53 return long(long(offset) << 16 | type)
54 54
55 55 nullhash = _sha(nullid)
56 56
57 57 def hash(text, p1, p2):
58 58 """generate a hash from the given text and its parent hashes
59 59
60 60 This hash combines both the current file contents and its history
61 61 in a manner that makes it easy to distinguish nodes with the same
62 62 content in the revision graph.
63 63 """
64 64 # As of now, if one of the parent node is null, p2 is null
65 65 if p2 == nullid:
66 66 # deep copy of a hash is faster than creating one
67 67 s = nullhash.copy()
68 68 s.update(p1)
69 69 else:
70 70 # none of the parent nodes are nullid
71 71 l = [p1, p2]
72 72 l.sort()
73 73 s = _sha(l[0])
74 74 s.update(l[1])
75 75 s.update(text)
76 76 return s.digest()
77 77
78 78 def decompress(bin):
79 79 """ decompress the given input """
80 80 if not bin:
81 81 return bin
82 82 t = bin[0]
83 83 if t == '\0':
84 84 return bin
85 85 if t == 'x':
86 86 try:
87 87 return _decompress(bin)
88 88 except zlib.error, e:
89 89 raise RevlogError(_("revlog decompress error: %s") % str(e))
90 90 if t == 'u':
91 91 return bin[1:]
92 92 raise RevlogError(_("unknown compression type %r") % t)
93 93
94 94 # index v0:
95 95 # 4 bytes: offset
96 96 # 4 bytes: compressed length
97 97 # 4 bytes: base rev
98 98 # 4 bytes: link rev
99 99 # 32 bytes: parent 1 nodeid
100 100 # 32 bytes: parent 2 nodeid
101 101 # 32 bytes: nodeid
102 102 indexformatv0 = ">4l20s20s20s"
103 103 v0shaoffset = 56
104 104
105 105 class revlogoldio(object):
106 106 def __init__(self):
107 107 self.size = struct.calcsize(indexformatv0)
108 108
109 109 def parseindex(self, data, inline):
110 110 s = self.size
111 111 index = []
112 112 nodemap = {nullid: nullrev}
113 113 n = off = 0
114 114 l = len(data)
115 115 while off + s <= l:
116 116 cur = data[off:off + s]
117 117 off += s
118 118 e = _unpack(indexformatv0, cur)
119 119 # transform to revlogv1 format
120 120 e2 = (offset_type(e[0], 0), e[1], -1, e[2], e[3],
121 121 nodemap.get(e[4], nullrev), nodemap.get(e[5], nullrev), e[6])
122 122 index.append(e2)
123 123 nodemap[e[6]] = n
124 124 n += 1
125 125
126 126 # add the magic null revision at -1
127 127 index.append((0, 0, 0, -1, -1, -1, -1, nullid))
128 128
129 129 return index, nodemap, None
130 130
131 131 def packentry(self, entry, node, version, rev):
132 132 if gettype(entry[0]):
133 133 raise RevlogError(_("index entry flags need RevlogNG"))
134 134 e2 = (getoffset(entry[0]), entry[1], entry[3], entry[4],
135 135 node(entry[5]), node(entry[6]), entry[7])
136 136 return _pack(indexformatv0, *e2)
137 137
138 138 # index ng:
139 139 # 6 bytes: offset
140 140 # 2 bytes: flags
141 141 # 4 bytes: compressed length
142 142 # 4 bytes: uncompressed length
143 143 # 4 bytes: base rev
144 144 # 4 bytes: link rev
145 145 # 4 bytes: parent 1 rev
146 146 # 4 bytes: parent 2 rev
147 147 # 32 bytes: nodeid
148 148 indexformatng = ">Qiiiiii20s12x"
149 149 ngshaoffset = 32
150 150 versionformat = ">I"
151 151
152 152 class revlogio(object):
153 153 def __init__(self):
154 154 self.size = struct.calcsize(indexformatng)
155 155
156 156 def parseindex(self, data, inline):
157 157 # call the C implementation to parse the index data
158 158 index, cache = parsers.parse_index2(data, inline)
159 159 return index, getattr(index, 'nodemap', None), cache
160 160
161 161 def packentry(self, entry, node, version, rev):
162 162 p = _pack(indexformatng, *entry)
163 163 if rev == 0:
164 164 p = _pack(versionformat, version) + p[4:]
165 165 return p
166 166
167 167 class revlog(object):
168 168 """
169 169 the underlying revision storage object
170 170
171 171 A revlog consists of two parts, an index and the revision data.
172 172
173 173 The index is a file with a fixed record size containing
174 174 information on each revision, including its nodeid (hash), the
175 175 nodeids of its parents, the position and offset of its data within
176 176 the data file, and the revision it's based on. Finally, each entry
177 177 contains a linkrev entry that can serve as a pointer to external
178 178 data.
179 179
180 180 The revision data itself is a linear collection of data chunks.
181 181 Each chunk represents a revision and is usually represented as a
182 182 delta against the previous chunk. To bound lookup time, runs of
183 183 deltas are limited to about 2 times the length of the original
184 184 version data. This makes retrieval of a version proportional to
185 185 its size, or O(1) relative to the number of revisions.
186 186
187 187 Both pieces of the revlog are written to in an append-only
188 188 fashion, which means we never need to rewrite a file to insert or
189 189 remove data, and can use some simple techniques to avoid the need
190 190 for locking while reading.
191 191 """
192 192 def __init__(self, opener, indexfile):
193 193 """
194 194 create a revlog object
195 195
196 196 opener is a function that abstracts the file opening operation
197 197 and can be used to implement COW semantics or the like.
198 198 """
199 199 self.indexfile = indexfile
200 200 self.datafile = indexfile[:-2] + ".d"
201 201 self.opener = opener
202 202 self._cache = None
203 203 self._basecache = (0, 0)
204 204 self._chunkcache = (0, '')
205 205 self.index = []
206 206 self._pcache = {}
207 207 self._nodecache = {nullid: nullrev}
208 208 self._nodepos = None
209 209
210 210 v = REVLOG_DEFAULT_VERSION
211 211 opts = getattr(opener, 'options', None)
212 212 if opts is not None:
213 213 if 'revlogv1' in opts:
214 214 if 'generaldelta' in opts:
215 215 v |= REVLOGGENERALDELTA
216 216 else:
217 217 v = 0
218 218
219 219 i = ''
220 220 self._initempty = True
221 221 try:
222 222 f = self.opener(self.indexfile)
223 223 i = f.read()
224 224 f.close()
225 225 if len(i) > 0:
226 226 v = struct.unpack(versionformat, i[:4])[0]
227 227 self._initempty = False
228 228 except IOError, inst:
229 229 if inst.errno != errno.ENOENT:
230 230 raise
231 231
232 232 self.version = v
233 233 self._inline = v & REVLOGNGINLINEDATA
234 234 self._generaldelta = v & REVLOGGENERALDELTA
235 235 flags = v & ~0xFFFF
236 236 fmt = v & 0xFFFF
237 237 if fmt == REVLOGV0 and flags:
238 238 raise RevlogError(_("index %s unknown flags %#04x for format v0")
239 239 % (self.indexfile, flags >> 16))
240 240 elif fmt == REVLOGNG and flags & ~REVLOGNG_FLAGS:
241 241 raise RevlogError(_("index %s unknown flags %#04x for revlogng")
242 242 % (self.indexfile, flags >> 16))
243 243 elif fmt > REVLOGNG:
244 244 raise RevlogError(_("index %s unknown format %d")
245 245 % (self.indexfile, fmt))
246 246
247 247 self._io = revlogio()
248 248 if self.version == REVLOGV0:
249 249 self._io = revlogoldio()
250 250 try:
251 251 d = self._io.parseindex(i, self._inline)
252 252 except (ValueError, IndexError):
253 253 raise RevlogError(_("index %s is corrupted") % (self.indexfile))
254 254 self.index, nodemap, self._chunkcache = d
255 255 if nodemap is not None:
256 256 self.nodemap = self._nodecache = nodemap
257 257 if not self._chunkcache:
258 258 self._chunkclear()
259 259
260 260 def tip(self):
261 261 return self.node(len(self.index) - 2)
262 262 def __len__(self):
263 263 return len(self.index) - 1
264 264 def __iter__(self):
265 265 return iter(xrange(len(self)))
266 266 def revs(self, start=0, stop=None):
267 267 """iterate over all rev in this revlog (from start to stop)"""
268 268 step = 1
269 269 if stop is not None:
270 270 if start > stop:
271 271 step = -1
272 272 stop += step
273 273 else:
274 274 stop = len(self)
275 275 return xrange(start, stop, step)
276 276
277 277 @util.propertycache
278 278 def nodemap(self):
279 279 self.rev(self.node(0))
280 280 return self._nodecache
281 281
282 282 def hasnode(self, node):
283 283 try:
284 284 self.rev(node)
285 285 return True
286 286 except KeyError:
287 287 return False
288 288
289 289 def clearcaches(self):
290 290 try:
291 291 self._nodecache.clearcaches()
292 292 except AttributeError:
293 293 self._nodecache = {nullid: nullrev}
294 294 self._nodepos = None
295 295
296 296 def rev(self, node):
297 297 try:
298 298 return self._nodecache[node]
299 299 except RevlogError:
300 300 # parsers.c radix tree lookup failed
301 301 raise LookupError(node, self.indexfile, _('no node'))
302 302 except KeyError:
303 303 # pure python cache lookup failed
304 304 n = self._nodecache
305 305 i = self.index
306 306 p = self._nodepos
307 307 if p is None:
308 308 p = len(i) - 2
309 309 for r in xrange(p, -1, -1):
310 310 v = i[r][7]
311 311 n[v] = r
312 312 if v == node:
313 313 self._nodepos = r - 1
314 314 return r
315 315 raise LookupError(node, self.indexfile, _('no node'))
316 316
317 317 def node(self, rev):
318 318 return self.index[rev][7]
319 319 def linkrev(self, rev):
320 320 return self.index[rev][4]
321 321 def parents(self, node):
322 322 i = self.index
323 323 d = i[self.rev(node)]
324 324 return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
325 325 def parentrevs(self, rev):
326 326 return self.index[rev][5:7]
327 327 def start(self, rev):
328 328 return int(self.index[rev][0] >> 16)
329 329 def end(self, rev):
330 330 return self.start(rev) + self.length(rev)
331 331 def length(self, rev):
332 332 return self.index[rev][1]
333 333 def chainbase(self, rev):
334 334 index = self.index
335 335 base = index[rev][3]
336 336 while base != rev:
337 337 rev = base
338 338 base = index[rev][3]
339 339 return base
340 340 def flags(self, rev):
341 341 return self.index[rev][0] & 0xFFFF
342 342 def rawsize(self, rev):
343 343 """return the length of the uncompressed text for a given revision"""
344 344 l = self.index[rev][2]
345 345 if l >= 0:
346 346 return l
347 347
348 348 t = self.revision(self.node(rev))
349 349 return len(t)
350 350 size = rawsize
351 351
352 352 def ancestors(self, revs, stoprev=0, inclusive=False):
353 353 """Generate the ancestors of 'revs' in reverse topological order.
354 354 Does not generate revs lower than stoprev.
355 355
356 356 See the documentation for ancestor.lazyancestors for more details."""
357 357
358 358 return ancestor.lazyancestors(self, revs, stoprev=stoprev,
359 359 inclusive=inclusive)
360 360
361 361 def descendants(self, revs):
362 362 """Generate the descendants of 'revs' in revision order.
363 363
364 364 Yield a sequence of revision numbers starting with a child of
365 365 some rev in revs, i.e., each revision is *not* considered a
366 366 descendant of itself. Results are ordered by revision number (a
367 367 topological sort)."""
368 368 first = min(revs)
369 369 if first == nullrev:
370 370 for i in self:
371 371 yield i
372 372 return
373 373
374 374 seen = set(revs)
375 375 for i in self.revs(start=first + 1):
376 376 for x in self.parentrevs(i):
377 377 if x != nullrev and x in seen:
378 378 seen.add(i)
379 379 yield i
380 380 break
381 381
382 382 def findcommonmissing(self, common=None, heads=None):
383 383 """Return a tuple of the ancestors of common and the ancestors of heads
384 384 that are not ancestors of common. In revset terminology, we return the
385 385 tuple:
386 386
387 387 ::common, (::heads) - (::common)
388 388
389 389 The list is sorted by revision number, meaning it is
390 390 topologically sorted.
391 391
392 392 'heads' and 'common' are both lists of node IDs. If heads is
393 393 not supplied, uses all of the revlog's heads. If common is not
394 394 supplied, uses nullid."""
395 395 if common is None:
396 396 common = [nullid]
397 397 if heads is None:
398 398 heads = self.heads()
399 399
400 400 common = [self.rev(n) for n in common]
401 401 heads = [self.rev(n) for n in heads]
402 402
403 403 # we want the ancestors, but inclusive
404 404 has = set(self.ancestors(common))
405 405 has.add(nullrev)
406 406 has.update(common)
407 407
408 408 # take all ancestors from heads that aren't in has
409 409 missing = set()
410 410 visit = util.deque(r for r in heads if r not in has)
411 411 while visit:
412 412 r = visit.popleft()
413 413 if r in missing:
414 414 continue
415 415 else:
416 416 missing.add(r)
417 417 for p in self.parentrevs(r):
418 418 if p not in has:
419 419 visit.append(p)
420 420 missing = list(missing)
421 421 missing.sort()
422 422 return has, [self.node(r) for r in missing]
423 423
424 424 def findmissingrevs(self, common=None, heads=None):
425 425 """Return the revision numbers of the ancestors of heads that
426 426 are not ancestors of common.
427 427
428 428 More specifically, return a list of revision numbers corresponding to
429 429 nodes N such that every N satisfies the following constraints:
430 430
431 431 1. N is an ancestor of some node in 'heads'
432 432 2. N is not an ancestor of any node in 'common'
433 433
434 434 The list is sorted by revision number, meaning it is
435 435 topologically sorted.
436 436
437 437 'heads' and 'common' are both lists of revision numbers. If heads is
438 438 not supplied, uses all of the revlog's heads. If common is not
439 439 supplied, uses nullid."""
440 440 if common is None:
441 441 common = [nullrev]
442 442 if heads is None:
443 443 heads = self.headrevs()
444 444
445 445 return ancestor.missingancestors(heads, common, self.parentrevs)
446 446
447 447 def findmissing(self, common=None, heads=None):
448 448 """Return the ancestors of heads that are not ancestors of common.
449 449
450 450 More specifically, return a list of nodes N such that every N
451 451 satisfies the following constraints:
452 452
453 453 1. N is an ancestor of some node in 'heads'
454 454 2. N is not an ancestor of any node in 'common'
455 455
456 456 The list is sorted by revision number, meaning it is
457 457 topologically sorted.
458 458
459 459 'heads' and 'common' are both lists of node IDs. If heads is
460 460 not supplied, uses all of the revlog's heads. If common is not
461 461 supplied, uses nullid."""
462 462 if common is None:
463 463 common = [nullid]
464 464 if heads is None:
465 465 heads = self.heads()
466 466
467 467 common = [self.rev(n) for n in common]
468 468 heads = [self.rev(n) for n in heads]
469 469
470 470 return [self.node(r) for r in
471 471 ancestor.missingancestors(heads, common, self.parentrevs)]
472 472
473 473 def nodesbetween(self, roots=None, heads=None):
474 474 """Return a topological path from 'roots' to 'heads'.
475 475
476 476 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
477 477 topologically sorted list of all nodes N that satisfy both of
478 478 these constraints:
479 479
480 480 1. N is a descendant of some node in 'roots'
481 481 2. N is an ancestor of some node in 'heads'
482 482
483 483 Every node is considered to be both a descendant and an ancestor
484 484 of itself, so every reachable node in 'roots' and 'heads' will be
485 485 included in 'nodes'.
486 486
487 487 'outroots' is the list of reachable nodes in 'roots', i.e., the
488 488 subset of 'roots' that is returned in 'nodes'. Likewise,
489 489 'outheads' is the subset of 'heads' that is also in 'nodes'.
490 490
491 491 'roots' and 'heads' are both lists of node IDs. If 'roots' is
492 492 unspecified, uses nullid as the only root. If 'heads' is
493 493 unspecified, uses list of all of the revlog's heads."""
494 494 nonodes = ([], [], [])
495 495 if roots is not None:
496 496 roots = list(roots)
497 497 if not roots:
498 498 return nonodes
499 499 lowestrev = min([self.rev(n) for n in roots])
500 500 else:
501 501 roots = [nullid] # Everybody's a descendant of nullid
502 502 lowestrev = nullrev
503 503 if (lowestrev == nullrev) and (heads is None):
504 504 # We want _all_ the nodes!
505 505 return ([self.node(r) for r in self], [nullid], list(self.heads()))
506 506 if heads is None:
507 507 # All nodes are ancestors, so the latest ancestor is the last
508 508 # node.
509 509 highestrev = len(self) - 1
510 510 # Set ancestors to None to signal that every node is an ancestor.
511 511 ancestors = None
512 512 # Set heads to an empty dictionary for later discovery of heads
513 513 heads = {}
514 514 else:
515 515 heads = list(heads)
516 516 if not heads:
517 517 return nonodes
518 518 ancestors = set()
519 519 # Turn heads into a dictionary so we can remove 'fake' heads.
520 520 # Also, later we will be using it to filter out the heads we can't
521 521 # find from roots.
522 522 heads = dict.fromkeys(heads, False)
523 523 # Start at the top and keep marking parents until we're done.
524 524 nodestotag = set(heads)
525 525 # Remember where the top was so we can use it as a limit later.
526 526 highestrev = max([self.rev(n) for n in nodestotag])
527 527 while nodestotag:
528 528 # grab a node to tag
529 529 n = nodestotag.pop()
530 530 # Never tag nullid
531 531 if n == nullid:
532 532 continue
533 533 # A node's revision number represents its place in a
534 534 # topologically sorted list of nodes.
535 535 r = self.rev(n)
536 536 if r >= lowestrev:
537 537 if n not in ancestors:
538 538 # If we are possibly a descendant of one of the roots
539 539 # and we haven't already been marked as an ancestor
540 540 ancestors.add(n) # Mark as ancestor
541 541 # Add non-nullid parents to list of nodes to tag.
542 542 nodestotag.update([p for p in self.parents(n) if
543 543 p != nullid])
544 544 elif n in heads: # We've seen it before, is it a fake head?
545 545 # So it is, real heads should not be the ancestors of
546 546 # any other heads.
547 547 heads.pop(n)
548 548 if not ancestors:
549 549 return nonodes
550 550 # Now that we have our set of ancestors, we want to remove any
551 551 # roots that are not ancestors.
552 552
553 553 # If one of the roots was nullid, everything is included anyway.
554 554 if lowestrev > nullrev:
555 555 # But, since we weren't, let's recompute the lowest rev to not
556 556 # include roots that aren't ancestors.
557 557
558 558 # Filter out roots that aren't ancestors of heads
559 559 roots = [n for n in roots if n in ancestors]
560 560 # Recompute the lowest revision
561 561 if roots:
562 562 lowestrev = min([self.rev(n) for n in roots])
563 563 else:
564 564 # No more roots? Return empty list
565 565 return nonodes
566 566 else:
567 567 # We are descending from nullid, and don't need to care about
568 568 # any other roots.
569 569 lowestrev = nullrev
570 570 roots = [nullid]
571 571 # Transform our roots list into a set.
572 572 descendants = set(roots)
573 573 # Also, keep the original roots so we can filter out roots that aren't
574 574 # 'real' roots (i.e. are descended from other roots).
575 575 roots = descendants.copy()
576 576 # Our topologically sorted list of output nodes.
577 577 orderedout = []
578 578 # Don't start at nullid since we don't want nullid in our output list,
579 579 # and if nullid shows up in descendants, empty parents will look like
580 580 # they're descendants.
581 581 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
582 582 n = self.node(r)
583 583 isdescendant = False
584 584 if lowestrev == nullrev: # Everybody is a descendant of nullid
585 585 isdescendant = True
586 586 elif n in descendants:
587 587 # n is already a descendant
588 588 isdescendant = True
589 589 # This check only needs to be done here because all the roots
590 590 # will start being marked is descendants before the loop.
591 591 if n in roots:
592 592 # If n was a root, check if it's a 'real' root.
593 593 p = tuple(self.parents(n))
594 594 # If any of its parents are descendants, it's not a root.
595 595 if (p[0] in descendants) or (p[1] in descendants):
596 596 roots.remove(n)
597 597 else:
598 598 p = tuple(self.parents(n))
599 599 # A node is a descendant if either of its parents are
600 600 # descendants. (We seeded the dependents list with the roots
601 601 # up there, remember?)
602 602 if (p[0] in descendants) or (p[1] in descendants):
603 603 descendants.add(n)
604 604 isdescendant = True
605 605 if isdescendant and ((ancestors is None) or (n in ancestors)):
606 606 # Only include nodes that are both descendants and ancestors.
607 607 orderedout.append(n)
608 608 if (ancestors is not None) and (n in heads):
609 609 # We're trying to figure out which heads are reachable
610 610 # from roots.
611 611 # Mark this head as having been reached
612 612 heads[n] = True
613 613 elif ancestors is None:
614 614 # Otherwise, we're trying to discover the heads.
615 615 # Assume this is a head because if it isn't, the next step
616 616 # will eventually remove it.
617 617 heads[n] = True
618 618 # But, obviously its parents aren't.
619 619 for p in self.parents(n):
620 620 heads.pop(p, None)
621 621 heads = [n for n, flag in heads.iteritems() if flag]
622 622 roots = list(roots)
623 623 assert orderedout
624 624 assert roots
625 625 assert heads
626 626 return (orderedout, roots, heads)
627 627
628 628 def headrevs(self):
629 629 try:
630 630 return self.index.headrevs()
631 631 except AttributeError:
632 632 return self._headrevs()
633 633
634 634 def _headrevs(self):
635 635 count = len(self)
636 636 if not count:
637 637 return [nullrev]
638 638 # we won't iter over filtered rev so nobody is a head at start
639 639 ishead = [0] * (count + 1)
640 640 index = self.index
641 641 for r in self:
642 642 ishead[r] = 1 # I may be an head
643 643 e = index[r]
644 644 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
645 645 return [r for r, val in enumerate(ishead) if val]
646 646
647 647 def heads(self, start=None, stop=None):
648 648 """return the list of all nodes that have no children
649 649
650 650 if start is specified, only heads that are descendants of
651 651 start will be returned
652 652 if stop is specified, it will consider all the revs from stop
653 653 as if they had no children
654 654 """
655 655 if start is None and stop is None:
656 656 if not len(self):
657 657 return [nullid]
658 658 return [self.node(r) for r in self.headrevs()]
659 659
660 660 if start is None:
661 661 start = nullid
662 662 if stop is None:
663 663 stop = []
664 664 stoprevs = set([self.rev(n) for n in stop])
665 665 startrev = self.rev(start)
666 666 reachable = set((startrev,))
667 667 heads = set((startrev,))
668 668
669 669 parentrevs = self.parentrevs
670 670 for r in self.revs(start=startrev + 1):
671 671 for p in parentrevs(r):
672 672 if p in reachable:
673 673 if r not in stoprevs:
674 674 reachable.add(r)
675 675 heads.add(r)
676 676 if p in heads and p not in stoprevs:
677 677 heads.remove(p)
678 678
679 679 return [self.node(r) for r in heads]
680 680
681 681 def children(self, node):
682 682 """find the children of a given node"""
683 683 c = []
684 684 p = self.rev(node)
685 685 for r in self.revs(start=p + 1):
686 686 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
687 687 if prevs:
688 688 for pr in prevs:
689 689 if pr == p:
690 690 c.append(self.node(r))
691 691 elif p == nullrev:
692 692 c.append(self.node(r))
693 693 return c
694 694
695 695 def descendant(self, start, end):
696 696 if start == nullrev:
697 697 return True
698 698 for i in self.descendants([start]):
699 699 if i == end:
700 700 return True
701 701 elif i > end:
702 702 break
703 703 return False
704 704
705 705 def ancestor(self, a, b):
706 706 """calculate the least common ancestor of nodes a and b"""
707 707
708 708 a, b = self.rev(a), self.rev(b)
709 709 try:
710 710 ancs = self.index.ancestors(a, b)
711 711 except (AttributeError, OverflowError):
712 712 ancs = ancestor.ancestors(self.parentrevs, a, b)
713 713 if ancs:
714 714 # choose a consistent winner when there's a tie
715 715 return min(map(self.node, ancs))
716 716 return nullid
717 717
718 718 def _match(self, id):
719 719 if isinstance(id, int):
720 720 # rev
721 721 return self.node(id)
722 722 if len(id) == 20:
723 723 # possibly a binary node
724 724 # odds of a binary node being all hex in ASCII are 1 in 10**25
725 725 try:
726 726 node = id
727 727 self.rev(node) # quick search the index
728 728 return node
729 729 except LookupError:
730 730 pass # may be partial hex id
731 731 try:
732 732 # str(rev)
733 733 rev = int(id)
734 734 if str(rev) != id:
735 735 raise ValueError
736 736 if rev < 0:
737 737 rev = len(self) + rev
738 738 if rev < 0 or rev >= len(self):
739 739 raise ValueError
740 740 return self.node(rev)
741 741 except (ValueError, OverflowError):
742 742 pass
743 743 if len(id) == 40:
744 744 try:
745 745 # a full hex nodeid?
746 746 node = bin(id)
747 747 self.rev(node)
748 748 return node
749 749 except (TypeError, LookupError):
750 750 pass
751 751
752 752 def _partialmatch(self, id):
753 753 try:
754 754 return self.index.partialmatch(id)
755 755 except RevlogError:
756 756 # parsers.c radix tree lookup gave multiple matches
757 757 raise LookupError(id, self.indexfile, _("ambiguous identifier"))
758 758 except (AttributeError, ValueError):
759 759 # we are pure python, or key was too short to search radix tree
760 760 pass
761 761
762 762 if id in self._pcache:
763 763 return self._pcache[id]
764 764
765 765 if len(id) < 40:
766 766 try:
767 767 # hex(node)[:...]
768 768 l = len(id) // 2 # grab an even number of digits
769 769 prefix = bin(id[:l * 2])
770 770 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
771 771 nl = [n for n in nl if hex(n).startswith(id)]
772 772 if len(nl) > 0:
773 773 if len(nl) == 1:
774 if nl[0] == nullid:
775 # dummy null revision always exists,
776 # it shouldn't be returned here
777 return None
778 774 self._pcache[id] = nl[0]
779 775 return nl[0]
780 776 raise LookupError(id, self.indexfile,
781 777 _('ambiguous identifier'))
782 778 return None
783 779 except TypeError:
784 780 pass
785 781
786 782 def lookup(self, id):
787 783 """locate a node based on:
788 784 - revision number or str(revision number)
789 785 - nodeid or subset of hex nodeid
790 786 """
791 787 n = self._match(id)
792 788 if n is not None:
793 789 return n
794 790 n = self._partialmatch(id)
795 791 if n:
796 792 return n
797 793
798 794 raise LookupError(id, self.indexfile, _('no match found'))
799 795
800 796 def cmp(self, node, text):
801 797 """compare text with a given file revision
802 798
803 799 returns True if text is different than what is stored.
804 800 """
805 801 p1, p2 = self.parents(node)
806 802 return hash(text, p1, p2) != node
807 803
808 804 def _addchunk(self, offset, data):
809 805 o, d = self._chunkcache
810 806 # try to add to existing cache
811 807 if o + len(d) == offset and len(d) + len(data) < _chunksize:
812 808 self._chunkcache = o, d + data
813 809 else:
814 810 self._chunkcache = offset, data
815 811
816 812 def _loadchunk(self, offset, length):
817 813 if self._inline:
818 814 df = self.opener(self.indexfile)
819 815 else:
820 816 df = self.opener(self.datafile)
821 817
822 818 readahead = max(65536, length)
823 819 df.seek(offset)
824 820 d = df.read(readahead)
825 821 df.close()
826 822 self._addchunk(offset, d)
827 823 if readahead > length:
828 824 return util.buffer(d, 0, length)
829 825 return d
830 826
831 827 def _getchunk(self, offset, length):
832 828 o, d = self._chunkcache
833 829 l = len(d)
834 830
835 831 # is it in the cache?
836 832 cachestart = offset - o
837 833 cacheend = cachestart + length
838 834 if cachestart >= 0 and cacheend <= l:
839 835 if cachestart == 0 and cacheend == l:
840 836 return d # avoid a copy
841 837 return util.buffer(d, cachestart, cacheend - cachestart)
842 838
843 839 return self._loadchunk(offset, length)
844 840
845 841 def _chunkraw(self, startrev, endrev):
846 842 start = self.start(startrev)
847 843 length = self.end(endrev) - start
848 844 if self._inline:
849 845 start += (startrev + 1) * self._io.size
850 846 return self._getchunk(start, length)
851 847
852 848 def _chunk(self, rev):
853 849 return decompress(self._chunkraw(rev, rev))
854 850
855 851 def _chunkbase(self, rev):
856 852 return self._chunk(rev)
857 853
858 854 def _chunkclear(self):
859 855 self._chunkcache = (0, '')
860 856
861 857 def deltaparent(self, rev):
862 858 """return deltaparent of the given revision"""
863 859 base = self.index[rev][3]
864 860 if base == rev:
865 861 return nullrev
866 862 elif self._generaldelta:
867 863 return base
868 864 else:
869 865 return rev - 1
870 866
871 867 def revdiff(self, rev1, rev2):
872 868 """return or calculate a delta between two revisions"""
873 869 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
874 870 return str(self._chunk(rev2))
875 871
876 872 return mdiff.textdiff(self.revision(rev1),
877 873 self.revision(rev2))
878 874
879 875 def revision(self, nodeorrev):
880 876 """return an uncompressed revision of a given node or revision
881 877 number.
882 878 """
883 879 if isinstance(nodeorrev, int):
884 880 rev = nodeorrev
885 881 node = self.node(rev)
886 882 else:
887 883 node = nodeorrev
888 884 rev = None
889 885
890 886 cachedrev = None
891 887 if node == nullid:
892 888 return ""
893 889 if self._cache:
894 890 if self._cache[0] == node:
895 891 return self._cache[2]
896 892 cachedrev = self._cache[1]
897 893
898 894 # look up what we need to read
899 895 text = None
900 896 if rev is None:
901 897 rev = self.rev(node)
902 898
903 899 # check rev flags
904 900 if self.flags(rev) & ~REVIDX_KNOWN_FLAGS:
905 901 raise RevlogError(_('incompatible revision flag %x') %
906 902 (self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
907 903
908 904 # build delta chain
909 905 chain = []
910 906 index = self.index # for performance
911 907 generaldelta = self._generaldelta
912 908 iterrev = rev
913 909 e = index[iterrev]
914 910 while iterrev != e[3] and iterrev != cachedrev:
915 911 chain.append(iterrev)
916 912 if generaldelta:
917 913 iterrev = e[3]
918 914 else:
919 915 iterrev -= 1
920 916 e = index[iterrev]
921 917 chain.reverse()
922 918 base = iterrev
923 919
924 920 if iterrev == cachedrev:
925 921 # cache hit
926 922 text = self._cache[2]
927 923
928 924 # drop cache to save memory
929 925 self._cache = None
930 926
931 927 self._chunkraw(base, rev)
932 928 if text is None:
933 929 text = str(self._chunkbase(base))
934 930
935 931 bins = [self._chunk(r) for r in chain]
936 932 text = mdiff.patches(text, bins)
937 933
938 934 text = self._checkhash(text, node, rev)
939 935
940 936 self._cache = (node, rev, text)
941 937 return text
942 938
943 939 def _checkhash(self, text, node, rev):
944 940 p1, p2 = self.parents(node)
945 941 if node != hash(text, p1, p2):
946 942 raise RevlogError(_("integrity check failed on %s:%d")
947 943 % (self.indexfile, rev))
948 944 return text
949 945
950 946 def checkinlinesize(self, tr, fp=None):
951 947 if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline:
952 948 return
953 949
954 950 trinfo = tr.find(self.indexfile)
955 951 if trinfo is None:
956 952 raise RevlogError(_("%s not found in the transaction")
957 953 % self.indexfile)
958 954
959 955 trindex = trinfo[2]
960 956 dataoff = self.start(trindex)
961 957
962 958 tr.add(self.datafile, dataoff)
963 959
964 960 if fp:
965 961 fp.flush()
966 962 fp.close()
967 963
968 964 df = self.opener(self.datafile, 'w')
969 965 try:
970 966 for r in self:
971 967 df.write(self._chunkraw(r, r))
972 968 finally:
973 969 df.close()
974 970
975 971 fp = self.opener(self.indexfile, 'w', atomictemp=True)
976 972 self.version &= ~(REVLOGNGINLINEDATA)
977 973 self._inline = False
978 974 for i in self:
979 975 e = self._io.packentry(self.index[i], self.node, self.version, i)
980 976 fp.write(e)
981 977
982 978 # if we don't call close, the temp file will never replace the
983 979 # real index
984 980 fp.close()
985 981
986 982 tr.replace(self.indexfile, trindex * self._io.size)
987 983 self._chunkclear()
988 984
989 985 def addrevision(self, text, transaction, link, p1, p2, cachedelta=None):
990 986 """add a revision to the log
991 987
992 988 text - the revision data to add
993 989 transaction - the transaction object used for rollback
994 990 link - the linkrev data to add
995 991 p1, p2 - the parent nodeids of the revision
996 992 cachedelta - an optional precomputed delta
997 993 """
998 994 node = hash(text, p1, p2)
999 995 if node in self.nodemap:
1000 996 return node
1001 997
1002 998 dfh = None
1003 999 if not self._inline:
1004 1000 dfh = self.opener(self.datafile, "a")
1005 1001 ifh = self.opener(self.indexfile, "a+")
1006 1002 try:
1007 1003 return self._addrevision(node, text, transaction, link, p1, p2,
1008 1004 cachedelta, ifh, dfh)
1009 1005 finally:
1010 1006 if dfh:
1011 1007 dfh.close()
1012 1008 ifh.close()
1013 1009
1014 1010 def compress(self, text):
1015 1011 """ generate a possibly-compressed representation of text """
1016 1012 if not text:
1017 1013 return ("", text)
1018 1014 l = len(text)
1019 1015 bin = None
1020 1016 if l < 44:
1021 1017 pass
1022 1018 elif l > 1000000:
1023 1019 # zlib makes an internal copy, thus doubling memory usage for
1024 1020 # large files, so lets do this in pieces
1025 1021 z = zlib.compressobj()
1026 1022 p = []
1027 1023 pos = 0
1028 1024 while pos < l:
1029 1025 pos2 = pos + 2**20
1030 1026 p.append(z.compress(text[pos:pos2]))
1031 1027 pos = pos2
1032 1028 p.append(z.flush())
1033 1029 if sum(map(len, p)) < l:
1034 1030 bin = "".join(p)
1035 1031 else:
1036 1032 bin = _compress(text)
1037 1033 if bin is None or len(bin) > l:
1038 1034 if text[0] == '\0':
1039 1035 return ("", text)
1040 1036 return ('u', text)
1041 1037 return ("", bin)
1042 1038
1043 1039 def _addrevision(self, node, text, transaction, link, p1, p2,
1044 1040 cachedelta, ifh, dfh):
1045 1041 """internal function to add revisions to the log
1046 1042
1047 1043 see addrevision for argument descriptions.
1048 1044 invariants:
1049 1045 - text is optional (can be None); if not set, cachedelta must be set.
1050 1046 if both are set, they must correspond to each other.
1051 1047 """
1052 1048 btext = [text]
1053 1049 def buildtext():
1054 1050 if btext[0] is not None:
1055 1051 return btext[0]
1056 1052 # flush any pending writes here so we can read it in revision
1057 1053 if dfh:
1058 1054 dfh.flush()
1059 1055 ifh.flush()
1060 1056 basetext = self.revision(self.node(cachedelta[0]))
1061 1057 btext[0] = mdiff.patch(basetext, cachedelta[1])
1062 1058 chk = hash(btext[0], p1, p2)
1063 1059 if chk != node:
1064 1060 raise RevlogError(_("consistency error in delta"))
1065 1061 return btext[0]
1066 1062
1067 1063 def builddelta(rev):
1068 1064 # can we use the cached delta?
1069 1065 if cachedelta and cachedelta[0] == rev:
1070 1066 delta = cachedelta[1]
1071 1067 else:
1072 1068 t = buildtext()
1073 1069 ptext = self.revision(self.node(rev))
1074 1070 delta = mdiff.textdiff(ptext, t)
1075 1071 data = self.compress(delta)
1076 1072 l = len(data[1]) + len(data[0])
1077 1073 if basecache[0] == rev:
1078 1074 chainbase = basecache[1]
1079 1075 else:
1080 1076 chainbase = self.chainbase(rev)
1081 1077 dist = l + offset - self.start(chainbase)
1082 1078 if self._generaldelta:
1083 1079 base = rev
1084 1080 else:
1085 1081 base = chainbase
1086 1082 return dist, l, data, base, chainbase
1087 1083
1088 1084 curr = len(self)
1089 1085 prev = curr - 1
1090 1086 base = chainbase = curr
1091 1087 offset = self.end(prev)
1092 1088 flags = 0
1093 1089 d = None
1094 1090 basecache = self._basecache
1095 1091 p1r, p2r = self.rev(p1), self.rev(p2)
1096 1092
1097 1093 # should we try to build a delta?
1098 1094 if prev != nullrev:
1099 1095 if self._generaldelta:
1100 1096 if p1r >= basecache[1]:
1101 1097 d = builddelta(p1r)
1102 1098 elif p2r >= basecache[1]:
1103 1099 d = builddelta(p2r)
1104 1100 else:
1105 1101 d = builddelta(prev)
1106 1102 else:
1107 1103 d = builddelta(prev)
1108 1104 dist, l, data, base, chainbase = d
1109 1105
1110 1106 # full versions are inserted when the needed deltas
1111 1107 # become comparable to the uncompressed text
1112 1108 if text is None:
1113 1109 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
1114 1110 cachedelta[1])
1115 1111 else:
1116 1112 textlen = len(text)
1117 1113 if d is None or dist > textlen * 2:
1118 1114 text = buildtext()
1119 1115 data = self.compress(text)
1120 1116 l = len(data[1]) + len(data[0])
1121 1117 base = chainbase = curr
1122 1118
1123 1119 e = (offset_type(offset, flags), l, textlen,
1124 1120 base, link, p1r, p2r, node)
1125 1121 self.index.insert(-1, e)
1126 1122 self.nodemap[node] = curr
1127 1123
1128 1124 entry = self._io.packentry(e, self.node, self.version, curr)
1129 1125 if not self._inline:
1130 1126 transaction.add(self.datafile, offset)
1131 1127 transaction.add(self.indexfile, curr * len(entry))
1132 1128 if data[0]:
1133 1129 dfh.write(data[0])
1134 1130 dfh.write(data[1])
1135 1131 dfh.flush()
1136 1132 ifh.write(entry)
1137 1133 else:
1138 1134 offset += curr * self._io.size
1139 1135 transaction.add(self.indexfile, offset, curr)
1140 1136 ifh.write(entry)
1141 1137 ifh.write(data[0])
1142 1138 ifh.write(data[1])
1143 1139 self.checkinlinesize(transaction, ifh)
1144 1140
1145 1141 if type(text) == str: # only accept immutable objects
1146 1142 self._cache = (node, curr, text)
1147 1143 self._basecache = (curr, chainbase)
1148 1144 return node
1149 1145
1150 1146 def group(self, nodelist, bundler, reorder=None):
1151 1147 """Calculate a delta group, yielding a sequence of changegroup chunks
1152 1148 (strings).
1153 1149
1154 1150 Given a list of changeset revs, return a set of deltas and
1155 1151 metadata corresponding to nodes. The first delta is
1156 1152 first parent(nodelist[0]) -> nodelist[0], the receiver is
1157 1153 guaranteed to have this parent as it has all history before
1158 1154 these changesets. In the case firstparent is nullrev the
1159 1155 changegroup starts with a full revision.
1160 1156 """
1161 1157
1162 1158 # if we don't have any revisions touched by these changesets, bail
1163 1159 if len(nodelist) == 0:
1164 1160 yield bundler.close()
1165 1161 return
1166 1162
1167 1163 # for generaldelta revlogs, we linearize the revs; this will both be
1168 1164 # much quicker and generate a much smaller bundle
1169 1165 if (self._generaldelta and reorder is not False) or reorder:
1170 1166 dag = dagutil.revlogdag(self)
1171 1167 revs = set(self.rev(n) for n in nodelist)
1172 1168 revs = dag.linearize(revs)
1173 1169 else:
1174 1170 revs = sorted([self.rev(n) for n in nodelist])
1175 1171
1176 1172 # add the parent of the first rev
1177 1173 p = self.parentrevs(revs[0])[0]
1178 1174 revs.insert(0, p)
1179 1175
1180 1176 # build deltas
1181 1177 for r in xrange(len(revs) - 1):
1182 1178 prev, curr = revs[r], revs[r + 1]
1183 1179 for c in bundler.revchunk(self, curr, prev):
1184 1180 yield c
1185 1181
1186 1182 yield bundler.close()
1187 1183
1188 1184 def addgroup(self, bundle, linkmapper, transaction):
1189 1185 """
1190 1186 add a delta group
1191 1187
1192 1188 given a set of deltas, add them to the revision log. the
1193 1189 first delta is against its parent, which should be in our
1194 1190 log, the rest are against the previous delta.
1195 1191 """
1196 1192
1197 1193 # track the base of the current delta log
1198 1194 content = []
1199 1195 node = None
1200 1196
1201 1197 r = len(self)
1202 1198 end = 0
1203 1199 if r:
1204 1200 end = self.end(r - 1)
1205 1201 ifh = self.opener(self.indexfile, "a+")
1206 1202 isize = r * self._io.size
1207 1203 if self._inline:
1208 1204 transaction.add(self.indexfile, end + isize, r)
1209 1205 dfh = None
1210 1206 else:
1211 1207 transaction.add(self.indexfile, isize, r)
1212 1208 transaction.add(self.datafile, end)
1213 1209 dfh = self.opener(self.datafile, "a")
1214 1210
1215 1211 try:
1216 1212 # loop through our set of deltas
1217 1213 chain = None
1218 1214 while True:
1219 1215 chunkdata = bundle.deltachunk(chain)
1220 1216 if not chunkdata:
1221 1217 break
1222 1218 node = chunkdata['node']
1223 1219 p1 = chunkdata['p1']
1224 1220 p2 = chunkdata['p2']
1225 1221 cs = chunkdata['cs']
1226 1222 deltabase = chunkdata['deltabase']
1227 1223 delta = chunkdata['delta']
1228 1224
1229 1225 content.append(node)
1230 1226
1231 1227 link = linkmapper(cs)
1232 1228 if node in self.nodemap:
1233 1229 # this can happen if two branches make the same change
1234 1230 chain = node
1235 1231 continue
1236 1232
1237 1233 for p in (p1, p2):
1238 1234 if p not in self.nodemap:
1239 1235 raise LookupError(p, self.indexfile,
1240 1236 _('unknown parent'))
1241 1237
1242 1238 if deltabase not in self.nodemap:
1243 1239 raise LookupError(deltabase, self.indexfile,
1244 1240 _('unknown delta base'))
1245 1241
1246 1242 baserev = self.rev(deltabase)
1247 1243 chain = self._addrevision(node, None, transaction, link,
1248 1244 p1, p2, (baserev, delta), ifh, dfh)
1249 1245 if not dfh and not self._inline:
1250 1246 # addrevision switched from inline to conventional
1251 1247 # reopen the index
1252 1248 ifh.close()
1253 1249 dfh = self.opener(self.datafile, "a")
1254 1250 ifh = self.opener(self.indexfile, "a")
1255 1251 finally:
1256 1252 if dfh:
1257 1253 dfh.close()
1258 1254 ifh.close()
1259 1255
1260 1256 return content
1261 1257
1262 1258 def strip(self, minlink, transaction):
1263 1259 """truncate the revlog on the first revision with a linkrev >= minlink
1264 1260
1265 1261 This function is called when we're stripping revision minlink and
1266 1262 its descendants from the repository.
1267 1263
1268 1264 We have to remove all revisions with linkrev >= minlink, because
1269 1265 the equivalent changelog revisions will be renumbered after the
1270 1266 strip.
1271 1267
1272 1268 So we truncate the revlog on the first of these revisions, and
1273 1269 trust that the caller has saved the revisions that shouldn't be
1274 1270 removed and that it'll re-add them after this truncation.
1275 1271 """
1276 1272 if len(self) == 0:
1277 1273 return
1278 1274
1279 1275 for rev in self:
1280 1276 if self.index[rev][4] >= minlink:
1281 1277 break
1282 1278 else:
1283 1279 return
1284 1280
1285 1281 # first truncate the files on disk
1286 1282 end = self.start(rev)
1287 1283 if not self._inline:
1288 1284 transaction.add(self.datafile, end)
1289 1285 end = rev * self._io.size
1290 1286 else:
1291 1287 end += rev * self._io.size
1292 1288
1293 1289 transaction.add(self.indexfile, end)
1294 1290
1295 1291 # then reset internal state in memory to forget those revisions
1296 1292 self._cache = None
1297 1293 self._chunkclear()
1298 1294 for x in xrange(rev, len(self)):
1299 1295 del self.nodemap[self.node(x)]
1300 1296
1301 1297 del self.index[rev:-1]
1302 1298
1303 1299 def checksize(self):
1304 1300 expected = 0
1305 1301 if len(self):
1306 1302 expected = max(0, self.end(len(self) - 1))
1307 1303
1308 1304 try:
1309 1305 f = self.opener(self.datafile)
1310 1306 f.seek(0, 2)
1311 1307 actual = f.tell()
1312 1308 f.close()
1313 1309 dd = actual - expected
1314 1310 except IOError, inst:
1315 1311 if inst.errno != errno.ENOENT:
1316 1312 raise
1317 1313 dd = 0
1318 1314
1319 1315 try:
1320 1316 f = self.opener(self.indexfile)
1321 1317 f.seek(0, 2)
1322 1318 actual = f.tell()
1323 1319 f.close()
1324 1320 s = self._io.size
1325 1321 i = max(0, actual // s)
1326 1322 di = actual - (i * s)
1327 1323 if self._inline:
1328 1324 databytes = 0
1329 1325 for r in self:
1330 1326 databytes += max(0, self.length(r))
1331 1327 dd = 0
1332 1328 di = actual - len(self) * s - databytes
1333 1329 except IOError, inst:
1334 1330 if inst.errno != errno.ENOENT:
1335 1331 raise
1336 1332 di = 0
1337 1333
1338 1334 return (dd, di)
1339 1335
1340 1336 def files(self):
1341 1337 res = [self.indexfile]
1342 1338 if not self._inline:
1343 1339 res.append(self.datafile)
1344 1340 return res
@@ -1,2126 +1,2125 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 $ commit()
73 73 > {
74 74 > rev=$1
75 75 > msg=$2
76 76 > shift 2
77 77 > if [ "$#" -gt 0 ]; then
78 78 > hg debugsetparents "$@"
79 79 > fi
80 80 > echo $rev > a
81 81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
82 82 > }
83 83
84 84 $ cat > printrevset.py <<EOF
85 85 > from mercurial import extensions, revset, commands, cmdutil
86 86 >
87 87 > def uisetup(ui):
88 88 > def printrevset(orig, ui, repo, *pats, **opts):
89 89 > if opts.get('print_revset'):
90 90 > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
91 91 > if expr:
92 92 > tree = revset.parse(expr)[0]
93 93 > else:
94 94 > tree = []
95 95 > ui.write('%r\n' % (opts.get('rev', []),))
96 96 > ui.write(revset.prettyformat(tree) + '\n')
97 97 > return 0
98 98 > return orig(ui, repo, *pats, **opts)
99 99 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
100 100 > entry[1].append(('', 'print-revset', False,
101 101 > 'print generated revset and exit (DEPRECATED)'))
102 102 > EOF
103 103
104 104 $ echo "[extensions]" >> $HGRCPATH
105 105 $ echo "graphlog=" >> $HGRCPATH
106 106 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
107 107
108 108 $ hg init repo
109 109 $ cd repo
110 110
111 111 Empty repo:
112 112
113 113 $ hg glog
114 114
115 115
116 116 Building DAG:
117 117
118 118 $ commit 0 "root"
119 119 $ commit 1 "collapse" 0
120 120 $ commit 2 "collapse" 1
121 121 $ commit 3 "collapse" 2
122 122 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
123 123 $ commit 5 "expand" 3 4
124 124 $ commit 6 "merge two known; one immediate left, one far left" 2 5
125 125 $ commit 7 "expand" 2 5
126 126 $ commit 8 "merge two known; one immediate left, one far right" 0 7
127 127 $ commit 9 "expand" 7 8
128 128 $ commit 10 "merge two known; one immediate left, one near right" 0 6
129 129 $ commit 11 "expand" 6 10
130 130 $ commit 12 "merge two known; one immediate right, one far left" 1 9
131 131 $ commit 13 "expand" 9 11
132 132 $ commit 14 "merge two known; one immediate right, one far right" 0 12
133 133 $ commit 15 "expand" 13 14
134 134 $ commit 16 "merge two known; one immediate right, one near right" 0 1
135 135 $ commit 17 "expand" 12 16
136 136 $ commit 18 "merge two known; two far left" 1 15
137 137 $ commit 19 "expand" 15 17
138 138 $ commit 20 "merge two known; two far right" 0 18
139 139 $ commit 21 "expand" 19 20
140 140 $ commit 22 "merge two known; one far left, one far right" 18 21
141 141 $ commit 23 "merge one known; immediate left" 1 22
142 142 $ commit 24 "merge one known; immediate right" 0 23
143 143 $ commit 25 "merge one known; far left" 21 24
144 144 $ commit 26 "merge one known; far right" 18 25
145 145 $ commit 27 "collapse" 21
146 146 $ commit 28 "merge zero known" 1 26
147 147 $ commit 29 "regular commit" 0
148 148 $ commit 30 "expand" 28 29
149 149 $ commit 31 "expand" 21 30
150 150 $ commit 32 "expand" 27 31
151 151 $ commit 33 "head" 18
152 152 $ commit 34 "head" 32
153 153
154 154
155 155 $ hg glog -q
156 156 @ 34:fea3ac5810e0
157 157 |
158 158 | o 33:68608f5145f9
159 159 | |
160 160 o | 32:d06dffa21a31
161 161 |\ \
162 162 | o \ 31:621d83e11f67
163 163 | |\ \
164 164 | | o \ 30:6e11cd4b648f
165 165 | | |\ \
166 166 | | | o | 29:cd9bb2be7593
167 167 | | | | |
168 168 | | o | | 28:44ecd0b9ae99
169 169 | | |\ \ \
170 170 o | | | | | 27:886ed638191b
171 171 |/ / / / /
172 172 | | o---+ 26:7f25b6c2f0b9
173 173 | | | | |
174 174 +---o | | 25:91da8ed57247
175 175 | | | | |
176 176 | | o | | 24:a9c19a3d96b7
177 177 | | |\| |
178 178 | | o | | 23:a01cddf0766d
179 179 | |/| | |
180 180 +---o---+ 22:e0d9cccacb5d
181 181 | | / /
182 182 o | | | 21:d42a756af44d
183 183 |\ \ \ \
184 184 | o---+-+ 20:d30ed6450e32
185 185 | / / /
186 186 o | | | 19:31ddc2c1573b
187 187 |\ \ \ \
188 188 +---+---o 18:1aa84d96232a
189 189 | | | |
190 190 | o | | 17:44765d7c06e0
191 191 | |\ \ \
192 192 | | o---+ 16:3677d192927d
193 193 | | |/ /
194 194 o | | | 15:1dda3f72782d
195 195 |\ \ \ \
196 196 | o-----+ 14:8eac370358ef
197 197 | |/ / /
198 198 o | | | 13:22d8966a97e3
199 199 |\ \ \ \
200 200 +---o | | 12:86b91144a6e9
201 201 | | |/ /
202 202 | o | | 11:832d76e6bdf2
203 203 | |\ \ \
204 204 | | o---+ 10:74c64d036d72
205 205 | |/ / /
206 206 o | | | 9:7010c0af0a35
207 207 |\ \ \ \
208 208 | o-----+ 8:7a0b11f71937
209 209 |/ / / /
210 210 o | | | 7:b632bb1b1224
211 211 |\ \ \ \
212 212 +---o | | 6:b105a072e251
213 213 | |/ / /
214 214 | o | | 5:4409d547b708
215 215 | |\ \ \
216 216 | | o | | 4:26a8bac39d9f
217 217 | |/|/ /
218 218 | o / / 3:27eef8ed80b4
219 219 |/ / /
220 220 o / / 2:3d9a33b8d1e1
221 221 |/ /
222 222 o / 1:6db2ef61d156
223 223 |/
224 224 o 0:e6eb3150255d
225 225
226 226
227 227 $ hg glog
228 228 @ changeset: 34:fea3ac5810e0
229 229 | tag: tip
230 230 | parent: 32:d06dffa21a31
231 231 | user: test
232 232 | date: Thu Jan 01 00:00:34 1970 +0000
233 233 | summary: (34) head
234 234 |
235 235 | o changeset: 33:68608f5145f9
236 236 | | parent: 18:1aa84d96232a
237 237 | | user: test
238 238 | | date: Thu Jan 01 00:00:33 1970 +0000
239 239 | | summary: (33) head
240 240 | |
241 241 o | changeset: 32:d06dffa21a31
242 242 |\ \ parent: 27:886ed638191b
243 243 | | | parent: 31:621d83e11f67
244 244 | | | user: test
245 245 | | | date: Thu Jan 01 00:00:32 1970 +0000
246 246 | | | summary: (32) expand
247 247 | | |
248 248 | o | changeset: 31:621d83e11f67
249 249 | |\ \ parent: 21:d42a756af44d
250 250 | | | | parent: 30:6e11cd4b648f
251 251 | | | | user: test
252 252 | | | | date: Thu Jan 01 00:00:31 1970 +0000
253 253 | | | | summary: (31) expand
254 254 | | | |
255 255 | | o | changeset: 30:6e11cd4b648f
256 256 | | |\ \ parent: 28:44ecd0b9ae99
257 257 | | | | | parent: 29:cd9bb2be7593
258 258 | | | | | user: test
259 259 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
260 260 | | | | | summary: (30) expand
261 261 | | | | |
262 262 | | | o | changeset: 29:cd9bb2be7593
263 263 | | | | | parent: 0:e6eb3150255d
264 264 | | | | | user: test
265 265 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
266 266 | | | | | summary: (29) regular commit
267 267 | | | | |
268 268 | | o | | changeset: 28:44ecd0b9ae99
269 269 | | |\ \ \ parent: 1:6db2ef61d156
270 270 | | | | | | parent: 26:7f25b6c2f0b9
271 271 | | | | | | user: test
272 272 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
273 273 | | | | | | summary: (28) merge zero known
274 274 | | | | | |
275 275 o | | | | | changeset: 27:886ed638191b
276 276 |/ / / / / parent: 21:d42a756af44d
277 277 | | | | | user: test
278 278 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
279 279 | | | | | summary: (27) collapse
280 280 | | | | |
281 281 | | o---+ changeset: 26:7f25b6c2f0b9
282 282 | | | | | parent: 18:1aa84d96232a
283 283 | | | | | parent: 25:91da8ed57247
284 284 | | | | | user: test
285 285 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
286 286 | | | | | summary: (26) merge one known; far right
287 287 | | | | |
288 288 +---o | | changeset: 25:91da8ed57247
289 289 | | | | | parent: 21:d42a756af44d
290 290 | | | | | parent: 24:a9c19a3d96b7
291 291 | | | | | user: test
292 292 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
293 293 | | | | | summary: (25) merge one known; far left
294 294 | | | | |
295 295 | | o | | changeset: 24:a9c19a3d96b7
296 296 | | |\| | parent: 0:e6eb3150255d
297 297 | | | | | parent: 23:a01cddf0766d
298 298 | | | | | user: test
299 299 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
300 300 | | | | | summary: (24) merge one known; immediate right
301 301 | | | | |
302 302 | | o | | changeset: 23:a01cddf0766d
303 303 | |/| | | parent: 1:6db2ef61d156
304 304 | | | | | parent: 22:e0d9cccacb5d
305 305 | | | | | user: test
306 306 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
307 307 | | | | | summary: (23) merge one known; immediate left
308 308 | | | | |
309 309 +---o---+ changeset: 22:e0d9cccacb5d
310 310 | | | | parent: 18:1aa84d96232a
311 311 | | / / parent: 21:d42a756af44d
312 312 | | | | user: test
313 313 | | | | date: Thu Jan 01 00:00:22 1970 +0000
314 314 | | | | summary: (22) merge two known; one far left, one far right
315 315 | | | |
316 316 o | | | changeset: 21:d42a756af44d
317 317 |\ \ \ \ parent: 19:31ddc2c1573b
318 318 | | | | | parent: 20:d30ed6450e32
319 319 | | | | | user: test
320 320 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
321 321 | | | | | summary: (21) expand
322 322 | | | | |
323 323 | o---+-+ changeset: 20:d30ed6450e32
324 324 | | | | parent: 0:e6eb3150255d
325 325 | / / / parent: 18:1aa84d96232a
326 326 | | | | user: test
327 327 | | | | date: Thu Jan 01 00:00:20 1970 +0000
328 328 | | | | summary: (20) merge two known; two far right
329 329 | | | |
330 330 o | | | changeset: 19:31ddc2c1573b
331 331 |\ \ \ \ parent: 15:1dda3f72782d
332 332 | | | | | parent: 17:44765d7c06e0
333 333 | | | | | user: test
334 334 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
335 335 | | | | | summary: (19) expand
336 336 | | | | |
337 337 +---+---o changeset: 18:1aa84d96232a
338 338 | | | | parent: 1:6db2ef61d156
339 339 | | | | parent: 15:1dda3f72782d
340 340 | | | | user: test
341 341 | | | | date: Thu Jan 01 00:00:18 1970 +0000
342 342 | | | | summary: (18) merge two known; two far left
343 343 | | | |
344 344 | o | | changeset: 17:44765d7c06e0
345 345 | |\ \ \ parent: 12:86b91144a6e9
346 346 | | | | | parent: 16:3677d192927d
347 347 | | | | | user: test
348 348 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
349 349 | | | | | summary: (17) expand
350 350 | | | | |
351 351 | | o---+ changeset: 16:3677d192927d
352 352 | | | | | parent: 0:e6eb3150255d
353 353 | | |/ / parent: 1:6db2ef61d156
354 354 | | | | user: test
355 355 | | | | date: Thu Jan 01 00:00:16 1970 +0000
356 356 | | | | summary: (16) merge two known; one immediate right, one near right
357 357 | | | |
358 358 o | | | changeset: 15:1dda3f72782d
359 359 |\ \ \ \ parent: 13:22d8966a97e3
360 360 | | | | | parent: 14:8eac370358ef
361 361 | | | | | user: test
362 362 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
363 363 | | | | | summary: (15) expand
364 364 | | | | |
365 365 | o-----+ changeset: 14:8eac370358ef
366 366 | | | | | parent: 0:e6eb3150255d
367 367 | |/ / / parent: 12:86b91144a6e9
368 368 | | | | user: test
369 369 | | | | date: Thu Jan 01 00:00:14 1970 +0000
370 370 | | | | summary: (14) merge two known; one immediate right, one far right
371 371 | | | |
372 372 o | | | changeset: 13:22d8966a97e3
373 373 |\ \ \ \ parent: 9:7010c0af0a35
374 374 | | | | | parent: 11:832d76e6bdf2
375 375 | | | | | user: test
376 376 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
377 377 | | | | | summary: (13) expand
378 378 | | | | |
379 379 +---o | | changeset: 12:86b91144a6e9
380 380 | | |/ / parent: 1:6db2ef61d156
381 381 | | | | parent: 9:7010c0af0a35
382 382 | | | | user: test
383 383 | | | | date: Thu Jan 01 00:00:12 1970 +0000
384 384 | | | | summary: (12) merge two known; one immediate right, one far left
385 385 | | | |
386 386 | o | | changeset: 11:832d76e6bdf2
387 387 | |\ \ \ parent: 6:b105a072e251
388 388 | | | | | parent: 10:74c64d036d72
389 389 | | | | | user: test
390 390 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
391 391 | | | | | summary: (11) expand
392 392 | | | | |
393 393 | | o---+ changeset: 10:74c64d036d72
394 394 | | | | | parent: 0:e6eb3150255d
395 395 | |/ / / parent: 6:b105a072e251
396 396 | | | | user: test
397 397 | | | | date: Thu Jan 01 00:00:10 1970 +0000
398 398 | | | | summary: (10) merge two known; one immediate left, one near right
399 399 | | | |
400 400 o | | | changeset: 9:7010c0af0a35
401 401 |\ \ \ \ parent: 7:b632bb1b1224
402 402 | | | | | parent: 8:7a0b11f71937
403 403 | | | | | user: test
404 404 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
405 405 | | | | | summary: (9) expand
406 406 | | | | |
407 407 | o-----+ changeset: 8:7a0b11f71937
408 408 | | | | | parent: 0:e6eb3150255d
409 409 |/ / / / parent: 7:b632bb1b1224
410 410 | | | | user: test
411 411 | | | | date: Thu Jan 01 00:00:08 1970 +0000
412 412 | | | | summary: (8) merge two known; one immediate left, one far right
413 413 | | | |
414 414 o | | | changeset: 7:b632bb1b1224
415 415 |\ \ \ \ parent: 2:3d9a33b8d1e1
416 416 | | | | | parent: 5:4409d547b708
417 417 | | | | | user: test
418 418 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
419 419 | | | | | summary: (7) expand
420 420 | | | | |
421 421 +---o | | changeset: 6:b105a072e251
422 422 | |/ / / parent: 2:3d9a33b8d1e1
423 423 | | | | parent: 5:4409d547b708
424 424 | | | | user: test
425 425 | | | | date: Thu Jan 01 00:00:06 1970 +0000
426 426 | | | | summary: (6) merge two known; one immediate left, one far left
427 427 | | | |
428 428 | o | | changeset: 5:4409d547b708
429 429 | |\ \ \ parent: 3:27eef8ed80b4
430 430 | | | | | parent: 4:26a8bac39d9f
431 431 | | | | | user: test
432 432 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
433 433 | | | | | summary: (5) expand
434 434 | | | | |
435 435 | | o | | changeset: 4:26a8bac39d9f
436 436 | |/|/ / parent: 1:6db2ef61d156
437 437 | | | | parent: 3:27eef8ed80b4
438 438 | | | | user: test
439 439 | | | | date: Thu Jan 01 00:00:04 1970 +0000
440 440 | | | | summary: (4) merge two known; one immediate left, one immediate right
441 441 | | | |
442 442 | o | | changeset: 3:27eef8ed80b4
443 443 |/ / / user: test
444 444 | | | date: Thu Jan 01 00:00:03 1970 +0000
445 445 | | | summary: (3) collapse
446 446 | | |
447 447 o | | changeset: 2:3d9a33b8d1e1
448 448 |/ / user: test
449 449 | | date: Thu Jan 01 00:00:02 1970 +0000
450 450 | | summary: (2) collapse
451 451 | |
452 452 o | changeset: 1:6db2ef61d156
453 453 |/ user: test
454 454 | date: Thu Jan 01 00:00:01 1970 +0000
455 455 | summary: (1) collapse
456 456 |
457 457 o changeset: 0:e6eb3150255d
458 458 user: test
459 459 date: Thu Jan 01 00:00:00 1970 +0000
460 460 summary: (0) root
461 461
462 462
463 463 File glog:
464 464 $ hg glog a
465 465 @ changeset: 34:fea3ac5810e0
466 466 | tag: tip
467 467 | parent: 32:d06dffa21a31
468 468 | user: test
469 469 | date: Thu Jan 01 00:00:34 1970 +0000
470 470 | summary: (34) head
471 471 |
472 472 | o changeset: 33:68608f5145f9
473 473 | | parent: 18:1aa84d96232a
474 474 | | user: test
475 475 | | date: Thu Jan 01 00:00:33 1970 +0000
476 476 | | summary: (33) head
477 477 | |
478 478 o | changeset: 32:d06dffa21a31
479 479 |\ \ parent: 27:886ed638191b
480 480 | | | parent: 31:621d83e11f67
481 481 | | | user: test
482 482 | | | date: Thu Jan 01 00:00:32 1970 +0000
483 483 | | | summary: (32) expand
484 484 | | |
485 485 | o | changeset: 31:621d83e11f67
486 486 | |\ \ parent: 21:d42a756af44d
487 487 | | | | parent: 30:6e11cd4b648f
488 488 | | | | user: test
489 489 | | | | date: Thu Jan 01 00:00:31 1970 +0000
490 490 | | | | summary: (31) expand
491 491 | | | |
492 492 | | o | changeset: 30:6e11cd4b648f
493 493 | | |\ \ parent: 28:44ecd0b9ae99
494 494 | | | | | parent: 29:cd9bb2be7593
495 495 | | | | | user: test
496 496 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
497 497 | | | | | summary: (30) expand
498 498 | | | | |
499 499 | | | o | changeset: 29:cd9bb2be7593
500 500 | | | | | parent: 0:e6eb3150255d
501 501 | | | | | user: test
502 502 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
503 503 | | | | | summary: (29) regular commit
504 504 | | | | |
505 505 | | o | | changeset: 28:44ecd0b9ae99
506 506 | | |\ \ \ parent: 1:6db2ef61d156
507 507 | | | | | | parent: 26:7f25b6c2f0b9
508 508 | | | | | | user: test
509 509 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
510 510 | | | | | | summary: (28) merge zero known
511 511 | | | | | |
512 512 o | | | | | changeset: 27:886ed638191b
513 513 |/ / / / / parent: 21:d42a756af44d
514 514 | | | | | user: test
515 515 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
516 516 | | | | | summary: (27) collapse
517 517 | | | | |
518 518 | | o---+ changeset: 26:7f25b6c2f0b9
519 519 | | | | | parent: 18:1aa84d96232a
520 520 | | | | | parent: 25:91da8ed57247
521 521 | | | | | user: test
522 522 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
523 523 | | | | | summary: (26) merge one known; far right
524 524 | | | | |
525 525 +---o | | changeset: 25:91da8ed57247
526 526 | | | | | parent: 21:d42a756af44d
527 527 | | | | | parent: 24:a9c19a3d96b7
528 528 | | | | | user: test
529 529 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
530 530 | | | | | summary: (25) merge one known; far left
531 531 | | | | |
532 532 | | o | | changeset: 24:a9c19a3d96b7
533 533 | | |\| | parent: 0:e6eb3150255d
534 534 | | | | | parent: 23:a01cddf0766d
535 535 | | | | | user: test
536 536 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
537 537 | | | | | summary: (24) merge one known; immediate right
538 538 | | | | |
539 539 | | o | | changeset: 23:a01cddf0766d
540 540 | |/| | | parent: 1:6db2ef61d156
541 541 | | | | | parent: 22:e0d9cccacb5d
542 542 | | | | | user: test
543 543 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
544 544 | | | | | summary: (23) merge one known; immediate left
545 545 | | | | |
546 546 +---o---+ changeset: 22:e0d9cccacb5d
547 547 | | | | parent: 18:1aa84d96232a
548 548 | | / / parent: 21:d42a756af44d
549 549 | | | | user: test
550 550 | | | | date: Thu Jan 01 00:00:22 1970 +0000
551 551 | | | | summary: (22) merge two known; one far left, one far right
552 552 | | | |
553 553 o | | | changeset: 21:d42a756af44d
554 554 |\ \ \ \ parent: 19:31ddc2c1573b
555 555 | | | | | parent: 20:d30ed6450e32
556 556 | | | | | user: test
557 557 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
558 558 | | | | | summary: (21) expand
559 559 | | | | |
560 560 | o---+-+ changeset: 20:d30ed6450e32
561 561 | | | | parent: 0:e6eb3150255d
562 562 | / / / parent: 18:1aa84d96232a
563 563 | | | | user: test
564 564 | | | | date: Thu Jan 01 00:00:20 1970 +0000
565 565 | | | | summary: (20) merge two known; two far right
566 566 | | | |
567 567 o | | | changeset: 19:31ddc2c1573b
568 568 |\ \ \ \ parent: 15:1dda3f72782d
569 569 | | | | | parent: 17:44765d7c06e0
570 570 | | | | | user: test
571 571 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
572 572 | | | | | summary: (19) expand
573 573 | | | | |
574 574 +---+---o changeset: 18:1aa84d96232a
575 575 | | | | parent: 1:6db2ef61d156
576 576 | | | | parent: 15:1dda3f72782d
577 577 | | | | user: test
578 578 | | | | date: Thu Jan 01 00:00:18 1970 +0000
579 579 | | | | summary: (18) merge two known; two far left
580 580 | | | |
581 581 | o | | changeset: 17:44765d7c06e0
582 582 | |\ \ \ parent: 12:86b91144a6e9
583 583 | | | | | parent: 16:3677d192927d
584 584 | | | | | user: test
585 585 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
586 586 | | | | | summary: (17) expand
587 587 | | | | |
588 588 | | o---+ changeset: 16:3677d192927d
589 589 | | | | | parent: 0:e6eb3150255d
590 590 | | |/ / parent: 1:6db2ef61d156
591 591 | | | | user: test
592 592 | | | | date: Thu Jan 01 00:00:16 1970 +0000
593 593 | | | | summary: (16) merge two known; one immediate right, one near right
594 594 | | | |
595 595 o | | | changeset: 15:1dda3f72782d
596 596 |\ \ \ \ parent: 13:22d8966a97e3
597 597 | | | | | parent: 14:8eac370358ef
598 598 | | | | | user: test
599 599 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
600 600 | | | | | summary: (15) expand
601 601 | | | | |
602 602 | o-----+ changeset: 14:8eac370358ef
603 603 | | | | | parent: 0:e6eb3150255d
604 604 | |/ / / parent: 12:86b91144a6e9
605 605 | | | | user: test
606 606 | | | | date: Thu Jan 01 00:00:14 1970 +0000
607 607 | | | | summary: (14) merge two known; one immediate right, one far right
608 608 | | | |
609 609 o | | | changeset: 13:22d8966a97e3
610 610 |\ \ \ \ parent: 9:7010c0af0a35
611 611 | | | | | parent: 11:832d76e6bdf2
612 612 | | | | | user: test
613 613 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
614 614 | | | | | summary: (13) expand
615 615 | | | | |
616 616 +---o | | changeset: 12:86b91144a6e9
617 617 | | |/ / parent: 1:6db2ef61d156
618 618 | | | | parent: 9:7010c0af0a35
619 619 | | | | user: test
620 620 | | | | date: Thu Jan 01 00:00:12 1970 +0000
621 621 | | | | summary: (12) merge two known; one immediate right, one far left
622 622 | | | |
623 623 | o | | changeset: 11:832d76e6bdf2
624 624 | |\ \ \ parent: 6:b105a072e251
625 625 | | | | | parent: 10:74c64d036d72
626 626 | | | | | user: test
627 627 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
628 628 | | | | | summary: (11) expand
629 629 | | | | |
630 630 | | o---+ changeset: 10:74c64d036d72
631 631 | | | | | parent: 0:e6eb3150255d
632 632 | |/ / / parent: 6:b105a072e251
633 633 | | | | user: test
634 634 | | | | date: Thu Jan 01 00:00:10 1970 +0000
635 635 | | | | summary: (10) merge two known; one immediate left, one near right
636 636 | | | |
637 637 o | | | changeset: 9:7010c0af0a35
638 638 |\ \ \ \ parent: 7:b632bb1b1224
639 639 | | | | | parent: 8:7a0b11f71937
640 640 | | | | | user: test
641 641 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
642 642 | | | | | summary: (9) expand
643 643 | | | | |
644 644 | o-----+ changeset: 8:7a0b11f71937
645 645 | | | | | parent: 0:e6eb3150255d
646 646 |/ / / / parent: 7:b632bb1b1224
647 647 | | | | user: test
648 648 | | | | date: Thu Jan 01 00:00:08 1970 +0000
649 649 | | | | summary: (8) merge two known; one immediate left, one far right
650 650 | | | |
651 651 o | | | changeset: 7:b632bb1b1224
652 652 |\ \ \ \ parent: 2:3d9a33b8d1e1
653 653 | | | | | parent: 5:4409d547b708
654 654 | | | | | user: test
655 655 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
656 656 | | | | | summary: (7) expand
657 657 | | | | |
658 658 +---o | | changeset: 6:b105a072e251
659 659 | |/ / / parent: 2:3d9a33b8d1e1
660 660 | | | | parent: 5:4409d547b708
661 661 | | | | user: test
662 662 | | | | date: Thu Jan 01 00:00:06 1970 +0000
663 663 | | | | summary: (6) merge two known; one immediate left, one far left
664 664 | | | |
665 665 | o | | changeset: 5:4409d547b708
666 666 | |\ \ \ parent: 3:27eef8ed80b4
667 667 | | | | | parent: 4:26a8bac39d9f
668 668 | | | | | user: test
669 669 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
670 670 | | | | | summary: (5) expand
671 671 | | | | |
672 672 | | o | | changeset: 4:26a8bac39d9f
673 673 | |/|/ / parent: 1:6db2ef61d156
674 674 | | | | parent: 3:27eef8ed80b4
675 675 | | | | user: test
676 676 | | | | date: Thu Jan 01 00:00:04 1970 +0000
677 677 | | | | summary: (4) merge two known; one immediate left, one immediate right
678 678 | | | |
679 679 | o | | changeset: 3:27eef8ed80b4
680 680 |/ / / user: test
681 681 | | | date: Thu Jan 01 00:00:03 1970 +0000
682 682 | | | summary: (3) collapse
683 683 | | |
684 684 o | | changeset: 2:3d9a33b8d1e1
685 685 |/ / user: test
686 686 | | date: Thu Jan 01 00:00:02 1970 +0000
687 687 | | summary: (2) collapse
688 688 | |
689 689 o | changeset: 1:6db2ef61d156
690 690 |/ user: test
691 691 | date: Thu Jan 01 00:00:01 1970 +0000
692 692 | summary: (1) collapse
693 693 |
694 694 o changeset: 0:e6eb3150255d
695 695 user: test
696 696 date: Thu Jan 01 00:00:00 1970 +0000
697 697 summary: (0) root
698 698
699 699
700 700 File glog per revset:
701 701
702 702 $ hg glog -r 'file("a")'
703 703 @ changeset: 34:fea3ac5810e0
704 704 | tag: tip
705 705 | parent: 32:d06dffa21a31
706 706 | user: test
707 707 | date: Thu Jan 01 00:00:34 1970 +0000
708 708 | summary: (34) head
709 709 |
710 710 | o changeset: 33:68608f5145f9
711 711 | | parent: 18:1aa84d96232a
712 712 | | user: test
713 713 | | date: Thu Jan 01 00:00:33 1970 +0000
714 714 | | summary: (33) head
715 715 | |
716 716 o | changeset: 32:d06dffa21a31
717 717 |\ \ parent: 27:886ed638191b
718 718 | | | parent: 31:621d83e11f67
719 719 | | | user: test
720 720 | | | date: Thu Jan 01 00:00:32 1970 +0000
721 721 | | | summary: (32) expand
722 722 | | |
723 723 | o | changeset: 31:621d83e11f67
724 724 | |\ \ parent: 21:d42a756af44d
725 725 | | | | parent: 30:6e11cd4b648f
726 726 | | | | user: test
727 727 | | | | date: Thu Jan 01 00:00:31 1970 +0000
728 728 | | | | summary: (31) expand
729 729 | | | |
730 730 | | o | changeset: 30:6e11cd4b648f
731 731 | | |\ \ parent: 28:44ecd0b9ae99
732 732 | | | | | parent: 29:cd9bb2be7593
733 733 | | | | | user: test
734 734 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
735 735 | | | | | summary: (30) expand
736 736 | | | | |
737 737 | | | o | changeset: 29:cd9bb2be7593
738 738 | | | | | parent: 0:e6eb3150255d
739 739 | | | | | user: test
740 740 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
741 741 | | | | | summary: (29) regular commit
742 742 | | | | |
743 743 | | o | | changeset: 28:44ecd0b9ae99
744 744 | | |\ \ \ parent: 1:6db2ef61d156
745 745 | | | | | | parent: 26:7f25b6c2f0b9
746 746 | | | | | | user: test
747 747 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
748 748 | | | | | | summary: (28) merge zero known
749 749 | | | | | |
750 750 o | | | | | changeset: 27:886ed638191b
751 751 |/ / / / / parent: 21:d42a756af44d
752 752 | | | | | user: test
753 753 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
754 754 | | | | | summary: (27) collapse
755 755 | | | | |
756 756 | | o---+ changeset: 26:7f25b6c2f0b9
757 757 | | | | | parent: 18:1aa84d96232a
758 758 | | | | | parent: 25:91da8ed57247
759 759 | | | | | user: test
760 760 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
761 761 | | | | | summary: (26) merge one known; far right
762 762 | | | | |
763 763 +---o | | changeset: 25:91da8ed57247
764 764 | | | | | parent: 21:d42a756af44d
765 765 | | | | | parent: 24:a9c19a3d96b7
766 766 | | | | | user: test
767 767 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
768 768 | | | | | summary: (25) merge one known; far left
769 769 | | | | |
770 770 | | o | | changeset: 24:a9c19a3d96b7
771 771 | | |\| | parent: 0:e6eb3150255d
772 772 | | | | | parent: 23:a01cddf0766d
773 773 | | | | | user: test
774 774 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
775 775 | | | | | summary: (24) merge one known; immediate right
776 776 | | | | |
777 777 | | o | | changeset: 23:a01cddf0766d
778 778 | |/| | | parent: 1:6db2ef61d156
779 779 | | | | | parent: 22:e0d9cccacb5d
780 780 | | | | | user: test
781 781 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
782 782 | | | | | summary: (23) merge one known; immediate left
783 783 | | | | |
784 784 +---o---+ changeset: 22:e0d9cccacb5d
785 785 | | | | parent: 18:1aa84d96232a
786 786 | | / / parent: 21:d42a756af44d
787 787 | | | | user: test
788 788 | | | | date: Thu Jan 01 00:00:22 1970 +0000
789 789 | | | | summary: (22) merge two known; one far left, one far right
790 790 | | | |
791 791 o | | | changeset: 21:d42a756af44d
792 792 |\ \ \ \ parent: 19:31ddc2c1573b
793 793 | | | | | parent: 20:d30ed6450e32
794 794 | | | | | user: test
795 795 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
796 796 | | | | | summary: (21) expand
797 797 | | | | |
798 798 | o---+-+ changeset: 20:d30ed6450e32
799 799 | | | | parent: 0:e6eb3150255d
800 800 | / / / parent: 18:1aa84d96232a
801 801 | | | | user: test
802 802 | | | | date: Thu Jan 01 00:00:20 1970 +0000
803 803 | | | | summary: (20) merge two known; two far right
804 804 | | | |
805 805 o | | | changeset: 19:31ddc2c1573b
806 806 |\ \ \ \ parent: 15:1dda3f72782d
807 807 | | | | | parent: 17:44765d7c06e0
808 808 | | | | | user: test
809 809 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
810 810 | | | | | summary: (19) expand
811 811 | | | | |
812 812 +---+---o changeset: 18:1aa84d96232a
813 813 | | | | parent: 1:6db2ef61d156
814 814 | | | | parent: 15:1dda3f72782d
815 815 | | | | user: test
816 816 | | | | date: Thu Jan 01 00:00:18 1970 +0000
817 817 | | | | summary: (18) merge two known; two far left
818 818 | | | |
819 819 | o | | changeset: 17:44765d7c06e0
820 820 | |\ \ \ parent: 12:86b91144a6e9
821 821 | | | | | parent: 16:3677d192927d
822 822 | | | | | user: test
823 823 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
824 824 | | | | | summary: (17) expand
825 825 | | | | |
826 826 | | o---+ changeset: 16:3677d192927d
827 827 | | | | | parent: 0:e6eb3150255d
828 828 | | |/ / parent: 1:6db2ef61d156
829 829 | | | | user: test
830 830 | | | | date: Thu Jan 01 00:00:16 1970 +0000
831 831 | | | | summary: (16) merge two known; one immediate right, one near right
832 832 | | | |
833 833 o | | | changeset: 15:1dda3f72782d
834 834 |\ \ \ \ parent: 13:22d8966a97e3
835 835 | | | | | parent: 14:8eac370358ef
836 836 | | | | | user: test
837 837 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
838 838 | | | | | summary: (15) expand
839 839 | | | | |
840 840 | o-----+ changeset: 14:8eac370358ef
841 841 | | | | | parent: 0:e6eb3150255d
842 842 | |/ / / parent: 12:86b91144a6e9
843 843 | | | | user: test
844 844 | | | | date: Thu Jan 01 00:00:14 1970 +0000
845 845 | | | | summary: (14) merge two known; one immediate right, one far right
846 846 | | | |
847 847 o | | | changeset: 13:22d8966a97e3
848 848 |\ \ \ \ parent: 9:7010c0af0a35
849 849 | | | | | parent: 11:832d76e6bdf2
850 850 | | | | | user: test
851 851 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
852 852 | | | | | summary: (13) expand
853 853 | | | | |
854 854 +---o | | changeset: 12:86b91144a6e9
855 855 | | |/ / parent: 1:6db2ef61d156
856 856 | | | | parent: 9:7010c0af0a35
857 857 | | | | user: test
858 858 | | | | date: Thu Jan 01 00:00:12 1970 +0000
859 859 | | | | summary: (12) merge two known; one immediate right, one far left
860 860 | | | |
861 861 | o | | changeset: 11:832d76e6bdf2
862 862 | |\ \ \ parent: 6:b105a072e251
863 863 | | | | | parent: 10:74c64d036d72
864 864 | | | | | user: test
865 865 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
866 866 | | | | | summary: (11) expand
867 867 | | | | |
868 868 | | o---+ changeset: 10:74c64d036d72
869 869 | | | | | parent: 0:e6eb3150255d
870 870 | |/ / / parent: 6:b105a072e251
871 871 | | | | user: test
872 872 | | | | date: Thu Jan 01 00:00:10 1970 +0000
873 873 | | | | summary: (10) merge two known; one immediate left, one near right
874 874 | | | |
875 875 o | | | changeset: 9:7010c0af0a35
876 876 |\ \ \ \ parent: 7:b632bb1b1224
877 877 | | | | | parent: 8:7a0b11f71937
878 878 | | | | | user: test
879 879 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
880 880 | | | | | summary: (9) expand
881 881 | | | | |
882 882 | o-----+ changeset: 8:7a0b11f71937
883 883 | | | | | parent: 0:e6eb3150255d
884 884 |/ / / / parent: 7:b632bb1b1224
885 885 | | | | user: test
886 886 | | | | date: Thu Jan 01 00:00:08 1970 +0000
887 887 | | | | summary: (8) merge two known; one immediate left, one far right
888 888 | | | |
889 889 o | | | changeset: 7:b632bb1b1224
890 890 |\ \ \ \ parent: 2:3d9a33b8d1e1
891 891 | | | | | parent: 5:4409d547b708
892 892 | | | | | user: test
893 893 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
894 894 | | | | | summary: (7) expand
895 895 | | | | |
896 896 +---o | | changeset: 6:b105a072e251
897 897 | |/ / / parent: 2:3d9a33b8d1e1
898 898 | | | | parent: 5:4409d547b708
899 899 | | | | user: test
900 900 | | | | date: Thu Jan 01 00:00:06 1970 +0000
901 901 | | | | summary: (6) merge two known; one immediate left, one far left
902 902 | | | |
903 903 | o | | changeset: 5:4409d547b708
904 904 | |\ \ \ parent: 3:27eef8ed80b4
905 905 | | | | | parent: 4:26a8bac39d9f
906 906 | | | | | user: test
907 907 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
908 908 | | | | | summary: (5) expand
909 909 | | | | |
910 910 | | o | | changeset: 4:26a8bac39d9f
911 911 | |/|/ / parent: 1:6db2ef61d156
912 912 | | | | parent: 3:27eef8ed80b4
913 913 | | | | user: test
914 914 | | | | date: Thu Jan 01 00:00:04 1970 +0000
915 915 | | | | summary: (4) merge two known; one immediate left, one immediate right
916 916 | | | |
917 917 | o | | changeset: 3:27eef8ed80b4
918 918 |/ / / user: test
919 919 | | | date: Thu Jan 01 00:00:03 1970 +0000
920 920 | | | summary: (3) collapse
921 921 | | |
922 922 o | | changeset: 2:3d9a33b8d1e1
923 923 |/ / user: test
924 924 | | date: Thu Jan 01 00:00:02 1970 +0000
925 925 | | summary: (2) collapse
926 926 | |
927 927 o | changeset: 1:6db2ef61d156
928 928 |/ user: test
929 929 | date: Thu Jan 01 00:00:01 1970 +0000
930 930 | summary: (1) collapse
931 931 |
932 932 o changeset: 0:e6eb3150255d
933 933 user: test
934 934 date: Thu Jan 01 00:00:00 1970 +0000
935 935 summary: (0) root
936 936
937 937
938 938
939 939 File glog per revset (only merges):
940 940
941 941 $ hg log -G -r 'file("a")' -m
942 942 o changeset: 32:d06dffa21a31
943 943 |\ parent: 27:886ed638191b
944 944 | | parent: 31:621d83e11f67
945 945 | | user: test
946 946 | | date: Thu Jan 01 00:00:32 1970 +0000
947 947 | | summary: (32) expand
948 948 | |
949 949 o | changeset: 31:621d83e11f67
950 950 |\| parent: 21:d42a756af44d
951 951 | | parent: 30:6e11cd4b648f
952 952 | | user: test
953 953 | | date: Thu Jan 01 00:00:31 1970 +0000
954 954 | | summary: (31) expand
955 955 | |
956 956 o | changeset: 30:6e11cd4b648f
957 957 |\ \ parent: 28:44ecd0b9ae99
958 958 | | | parent: 29:cd9bb2be7593
959 959 | | | user: test
960 960 | | | date: Thu Jan 01 00:00:30 1970 +0000
961 961 | | | summary: (30) expand
962 962 | | |
963 963 o | | changeset: 28:44ecd0b9ae99
964 964 |\ \ \ parent: 1:6db2ef61d156
965 965 | | | | parent: 26:7f25b6c2f0b9
966 966 | | | | user: test
967 967 | | | | date: Thu Jan 01 00:00:28 1970 +0000
968 968 | | | | summary: (28) merge zero known
969 969 | | | |
970 970 o | | | changeset: 26:7f25b6c2f0b9
971 971 |\ \ \ \ parent: 18:1aa84d96232a
972 972 | | | | | parent: 25:91da8ed57247
973 973 | | | | | user: test
974 974 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
975 975 | | | | | summary: (26) merge one known; far right
976 976 | | | | |
977 977 | o-----+ changeset: 25:91da8ed57247
978 978 | | | | | parent: 21:d42a756af44d
979 979 | | | | | parent: 24:a9c19a3d96b7
980 980 | | | | | user: test
981 981 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
982 982 | | | | | summary: (25) merge one known; far left
983 983 | | | | |
984 984 | o | | | changeset: 24:a9c19a3d96b7
985 985 | |\ \ \ \ parent: 0:e6eb3150255d
986 986 | | | | | | parent: 23:a01cddf0766d
987 987 | | | | | | user: test
988 988 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
989 989 | | | | | | summary: (24) merge one known; immediate right
990 990 | | | | | |
991 991 | o---+ | | changeset: 23:a01cddf0766d
992 992 | | | | | | parent: 1:6db2ef61d156
993 993 | | | | | | parent: 22:e0d9cccacb5d
994 994 | | | | | | user: test
995 995 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
996 996 | | | | | | summary: (23) merge one known; immediate left
997 997 | | | | | |
998 998 | o-------+ changeset: 22:e0d9cccacb5d
999 999 | | | | | | parent: 18:1aa84d96232a
1000 1000 |/ / / / / parent: 21:d42a756af44d
1001 1001 | | | | | user: test
1002 1002 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1003 1003 | | | | | summary: (22) merge two known; one far left, one far right
1004 1004 | | | | |
1005 1005 | | | | o changeset: 21:d42a756af44d
1006 1006 | | | | |\ parent: 19:31ddc2c1573b
1007 1007 | | | | | | parent: 20:d30ed6450e32
1008 1008 | | | | | | user: test
1009 1009 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1010 1010 | | | | | | summary: (21) expand
1011 1011 | | | | | |
1012 1012 +-+-------o changeset: 20:d30ed6450e32
1013 1013 | | | | | parent: 0:e6eb3150255d
1014 1014 | | | | | parent: 18:1aa84d96232a
1015 1015 | | | | | user: test
1016 1016 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1017 1017 | | | | | summary: (20) merge two known; two far right
1018 1018 | | | | |
1019 1019 | | | | o changeset: 19:31ddc2c1573b
1020 1020 | | | | |\ parent: 15:1dda3f72782d
1021 1021 | | | | | | parent: 17:44765d7c06e0
1022 1022 | | | | | | user: test
1023 1023 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1024 1024 | | | | | | summary: (19) expand
1025 1025 | | | | | |
1026 1026 o---+---+ | changeset: 18:1aa84d96232a
1027 1027 | | | | | parent: 1:6db2ef61d156
1028 1028 / / / / / parent: 15:1dda3f72782d
1029 1029 | | | | | user: test
1030 1030 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1031 1031 | | | | | summary: (18) merge two known; two far left
1032 1032 | | | | |
1033 1033 | | | | o changeset: 17:44765d7c06e0
1034 1034 | | | | |\ parent: 12:86b91144a6e9
1035 1035 | | | | | | parent: 16:3677d192927d
1036 1036 | | | | | | user: test
1037 1037 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1038 1038 | | | | | | summary: (17) expand
1039 1039 | | | | | |
1040 1040 +-+-------o changeset: 16:3677d192927d
1041 1041 | | | | | parent: 0:e6eb3150255d
1042 1042 | | | | | parent: 1:6db2ef61d156
1043 1043 | | | | | user: test
1044 1044 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1045 1045 | | | | | summary: (16) merge two known; one immediate right, one near right
1046 1046 | | | | |
1047 1047 | | | o | changeset: 15:1dda3f72782d
1048 1048 | | | |\ \ parent: 13:22d8966a97e3
1049 1049 | | | | | | parent: 14:8eac370358ef
1050 1050 | | | | | | user: test
1051 1051 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1052 1052 | | | | | | summary: (15) expand
1053 1053 | | | | | |
1054 1054 +-------o | changeset: 14:8eac370358ef
1055 1055 | | | | |/ parent: 0:e6eb3150255d
1056 1056 | | | | | parent: 12:86b91144a6e9
1057 1057 | | | | | user: test
1058 1058 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1059 1059 | | | | | summary: (14) merge two known; one immediate right, one far right
1060 1060 | | | | |
1061 1061 | | | o | changeset: 13:22d8966a97e3
1062 1062 | | | |\ \ parent: 9:7010c0af0a35
1063 1063 | | | | | | parent: 11:832d76e6bdf2
1064 1064 | | | | | | user: test
1065 1065 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1066 1066 | | | | | | summary: (13) expand
1067 1067 | | | | | |
1068 1068 | +---+---o changeset: 12:86b91144a6e9
1069 1069 | | | | | parent: 1:6db2ef61d156
1070 1070 | | | | | parent: 9:7010c0af0a35
1071 1071 | | | | | user: test
1072 1072 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1073 1073 | | | | | summary: (12) merge two known; one immediate right, one far left
1074 1074 | | | | |
1075 1075 | | | | o changeset: 11:832d76e6bdf2
1076 1076 | | | | |\ parent: 6:b105a072e251
1077 1077 | | | | | | parent: 10:74c64d036d72
1078 1078 | | | | | | user: test
1079 1079 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1080 1080 | | | | | | summary: (11) expand
1081 1081 | | | | | |
1082 1082 +---------o changeset: 10:74c64d036d72
1083 1083 | | | | |/ parent: 0:e6eb3150255d
1084 1084 | | | | | parent: 6:b105a072e251
1085 1085 | | | | | user: test
1086 1086 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1087 1087 | | | | | summary: (10) merge two known; one immediate left, one near right
1088 1088 | | | | |
1089 1089 | | | o | changeset: 9:7010c0af0a35
1090 1090 | | | |\ \ parent: 7:b632bb1b1224
1091 1091 | | | | | | parent: 8:7a0b11f71937
1092 1092 | | | | | | user: test
1093 1093 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1094 1094 | | | | | | summary: (9) expand
1095 1095 | | | | | |
1096 1096 +-------o | changeset: 8:7a0b11f71937
1097 1097 | | | |/ / parent: 0:e6eb3150255d
1098 1098 | | | | | parent: 7:b632bb1b1224
1099 1099 | | | | | user: test
1100 1100 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1101 1101 | | | | | summary: (8) merge two known; one immediate left, one far right
1102 1102 | | | | |
1103 1103 | | | o | changeset: 7:b632bb1b1224
1104 1104 | | | |\ \ parent: 2:3d9a33b8d1e1
1105 1105 | | | | | | parent: 5:4409d547b708
1106 1106 | | | | | | user: test
1107 1107 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1108 1108 | | | | | | summary: (7) expand
1109 1109 | | | | | |
1110 1110 | | | +---o changeset: 6:b105a072e251
1111 1111 | | | | |/ parent: 2:3d9a33b8d1e1
1112 1112 | | | | | parent: 5:4409d547b708
1113 1113 | | | | | user: test
1114 1114 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1115 1115 | | | | | summary: (6) merge two known; one immediate left, one far left
1116 1116 | | | | |
1117 1117 | | | o | changeset: 5:4409d547b708
1118 1118 | | | |\ \ parent: 3:27eef8ed80b4
1119 1119 | | | | | | parent: 4:26a8bac39d9f
1120 1120 | | | | | | user: test
1121 1121 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1122 1122 | | | | | | summary: (5) expand
1123 1123 | | | | | |
1124 1124 | +---o | | changeset: 4:26a8bac39d9f
1125 1125 | | | |/ / parent: 1:6db2ef61d156
1126 1126 | | | | | parent: 3:27eef8ed80b4
1127 1127 | | | | | user: test
1128 1128 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1129 1129 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1130 1130 | | | | |
1131 1131
1132 1132
1133 1133 Empty revision range - display nothing:
1134 1134 $ hg glog -r 1..0
1135 1135
1136 1136 $ cd ..
1137 1137
1138 1138 #if no-outer-repo
1139 1139
1140 1140 From outer space:
1141 1141 $ hg glog -l1 repo
1142 1142 @ changeset: 34:fea3ac5810e0
1143 1143 | tag: tip
1144 1144 | parent: 32:d06dffa21a31
1145 1145 | user: test
1146 1146 | date: Thu Jan 01 00:00:34 1970 +0000
1147 1147 | summary: (34) head
1148 1148 |
1149 1149 $ hg glog -l1 repo/a
1150 1150 @ changeset: 34:fea3ac5810e0
1151 1151 | tag: tip
1152 1152 | parent: 32:d06dffa21a31
1153 1153 | user: test
1154 1154 | date: Thu Jan 01 00:00:34 1970 +0000
1155 1155 | summary: (34) head
1156 1156 |
1157 1157 $ hg glog -l1 repo/missing
1158 1158
1159 1159 #endif
1160 1160
1161 1161 File log with revs != cset revs:
1162 1162 $ hg init flog
1163 1163 $ cd flog
1164 1164 $ echo one >one
1165 1165 $ hg add one
1166 1166 $ hg commit -mone
1167 1167 $ echo two >two
1168 1168 $ hg add two
1169 1169 $ hg commit -mtwo
1170 1170 $ echo more >two
1171 1171 $ hg commit -mmore
1172 1172 $ hg glog two
1173 1173 @ changeset: 2:12c28321755b
1174 1174 | tag: tip
1175 1175 | user: test
1176 1176 | date: Thu Jan 01 00:00:00 1970 +0000
1177 1177 | summary: more
1178 1178 |
1179 1179 o changeset: 1:5ac72c0599bf
1180 1180 | user: test
1181 1181 | date: Thu Jan 01 00:00:00 1970 +0000
1182 1182 | summary: two
1183 1183 |
1184 1184
1185 1185 Issue1896: File log with explicit style
1186 1186 $ hg glog --style=default one
1187 1187 o changeset: 0:3d578b4a1f53
1188 1188 user: test
1189 1189 date: Thu Jan 01 00:00:00 1970 +0000
1190 1190 summary: one
1191 1191
1192 1192 Issue2395: glog --style header and footer
1193 1193 $ hg glog --style=xml one
1194 1194 <?xml version="1.0"?>
1195 1195 <log>
1196 1196 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1197 1197 <author email="test">test</author>
1198 1198 <date>1970-01-01T00:00:00+00:00</date>
1199 1199 <msg xml:space="preserve">one</msg>
1200 1200 </logentry>
1201 1201 </log>
1202 1202
1203 1203 $ cd ..
1204 1204
1205 1205 Incoming and outgoing:
1206 1206
1207 1207 $ hg clone -U -r31 repo repo2
1208 1208 adding changesets
1209 1209 adding manifests
1210 1210 adding file changes
1211 1211 added 31 changesets with 31 changes to 1 files
1212 1212 $ cd repo2
1213 1213
1214 1214 $ hg incoming --graph ../repo
1215 1215 comparing with ../repo
1216 1216 searching for changes
1217 1217 o changeset: 34:fea3ac5810e0
1218 1218 | tag: tip
1219 1219 | parent: 32:d06dffa21a31
1220 1220 | user: test
1221 1221 | date: Thu Jan 01 00:00:34 1970 +0000
1222 1222 | summary: (34) head
1223 1223 |
1224 1224 | o changeset: 33:68608f5145f9
1225 1225 | parent: 18:1aa84d96232a
1226 1226 | user: test
1227 1227 | date: Thu Jan 01 00:00:33 1970 +0000
1228 1228 | summary: (33) head
1229 1229 |
1230 1230 o changeset: 32:d06dffa21a31
1231 1231 | parent: 27:886ed638191b
1232 1232 | parent: 31:621d83e11f67
1233 1233 | user: test
1234 1234 | date: Thu Jan 01 00:00:32 1970 +0000
1235 1235 | summary: (32) expand
1236 1236 |
1237 1237 o changeset: 27:886ed638191b
1238 1238 parent: 21:d42a756af44d
1239 1239 user: test
1240 1240 date: Thu Jan 01 00:00:27 1970 +0000
1241 1241 summary: (27) collapse
1242 1242
1243 1243 $ cd ..
1244 1244
1245 1245 $ hg -R repo outgoing --graph repo2
1246 1246 comparing with repo2
1247 1247 searching for changes
1248 1248 @ changeset: 34:fea3ac5810e0
1249 1249 | tag: tip
1250 1250 | parent: 32:d06dffa21a31
1251 1251 | user: test
1252 1252 | date: Thu Jan 01 00:00:34 1970 +0000
1253 1253 | summary: (34) head
1254 1254 |
1255 1255 | o changeset: 33:68608f5145f9
1256 1256 | parent: 18:1aa84d96232a
1257 1257 | user: test
1258 1258 | date: Thu Jan 01 00:00:33 1970 +0000
1259 1259 | summary: (33) head
1260 1260 |
1261 1261 o changeset: 32:d06dffa21a31
1262 1262 | parent: 27:886ed638191b
1263 1263 | parent: 31:621d83e11f67
1264 1264 | user: test
1265 1265 | date: Thu Jan 01 00:00:32 1970 +0000
1266 1266 | summary: (32) expand
1267 1267 |
1268 1268 o changeset: 27:886ed638191b
1269 1269 parent: 21:d42a756af44d
1270 1270 user: test
1271 1271 date: Thu Jan 01 00:00:27 1970 +0000
1272 1272 summary: (27) collapse
1273 1273
1274 1274
1275 1275 File + limit with revs != cset revs:
1276 1276 $ cd repo
1277 1277 $ touch b
1278 1278 $ hg ci -Aqm0
1279 1279 $ hg glog -l2 a
1280 1280 o changeset: 34:fea3ac5810e0
1281 1281 | parent: 32:d06dffa21a31
1282 1282 | user: test
1283 1283 | date: Thu Jan 01 00:00:34 1970 +0000
1284 1284 | summary: (34) head
1285 1285 |
1286 1286 | o changeset: 33:68608f5145f9
1287 1287 | | parent: 18:1aa84d96232a
1288 1288 | | user: test
1289 1289 | | date: Thu Jan 01 00:00:33 1970 +0000
1290 1290 | | summary: (33) head
1291 1291 | |
1292 1292
1293 1293 File + limit + -ra:b, (b - a) < limit:
1294 1294 $ hg glog -l3000 -r32:tip a
1295 1295 o changeset: 34:fea3ac5810e0
1296 1296 | parent: 32:d06dffa21a31
1297 1297 | user: test
1298 1298 | date: Thu Jan 01 00:00:34 1970 +0000
1299 1299 | summary: (34) head
1300 1300 |
1301 1301 | o changeset: 33:68608f5145f9
1302 1302 | | parent: 18:1aa84d96232a
1303 1303 | | user: test
1304 1304 | | date: Thu Jan 01 00:00:33 1970 +0000
1305 1305 | | summary: (33) head
1306 1306 | |
1307 1307 o | changeset: 32:d06dffa21a31
1308 1308 |\ \ parent: 27:886ed638191b
1309 1309 | | | parent: 31:621d83e11f67
1310 1310 | | | user: test
1311 1311 | | | date: Thu Jan 01 00:00:32 1970 +0000
1312 1312 | | | summary: (32) expand
1313 1313 | | |
1314 1314
1315 1315 Point out a common and an uncommon unshown parent
1316 1316
1317 1317 $ hg glog -r 'rev(8) or rev(9)'
1318 1318 o changeset: 9:7010c0af0a35
1319 1319 |\ parent: 7:b632bb1b1224
1320 1320 | | parent: 8:7a0b11f71937
1321 1321 | | user: test
1322 1322 | | date: Thu Jan 01 00:00:09 1970 +0000
1323 1323 | | summary: (9) expand
1324 1324 | |
1325 1325 o | changeset: 8:7a0b11f71937
1326 1326 |\| parent: 0:e6eb3150255d
1327 1327 | | parent: 7:b632bb1b1224
1328 1328 | | user: test
1329 1329 | | date: Thu Jan 01 00:00:08 1970 +0000
1330 1330 | | summary: (8) merge two known; one immediate left, one far right
1331 1331 | |
1332 1332
1333 1333 File + limit + -ra:b, b < tip:
1334 1334
1335 1335 $ hg glog -l1 -r32:34 a
1336 1336 o changeset: 34:fea3ac5810e0
1337 1337 | parent: 32:d06dffa21a31
1338 1338 | user: test
1339 1339 | date: Thu Jan 01 00:00:34 1970 +0000
1340 1340 | summary: (34) head
1341 1341 |
1342 1342
1343 1343 file(File) + limit + -ra:b, b < tip:
1344 1344
1345 1345 $ hg glog -l1 -r32:34 -r 'file("a")'
1346 1346 o changeset: 34:fea3ac5810e0
1347 1347 | parent: 32:d06dffa21a31
1348 1348 | user: test
1349 1349 | date: Thu Jan 01 00:00:34 1970 +0000
1350 1350 | summary: (34) head
1351 1351 |
1352 1352
1353 1353 limit(file(File) and a::b), b < tip:
1354 1354
1355 1355 $ hg glog -r 'limit(file("a") and 32::34, 1)'
1356 1356 o changeset: 32:d06dffa21a31
1357 1357 |\ parent: 27:886ed638191b
1358 1358 | | parent: 31:621d83e11f67
1359 1359 | | user: test
1360 1360 | | date: Thu Jan 01 00:00:32 1970 +0000
1361 1361 | | summary: (32) expand
1362 1362 | |
1363 1363
1364 1364 File + limit + -ra:b, b < tip:
1365 1365
1366 1366 $ hg glog -r 'limit(file("a") and 34::32, 1)'
1367 1367
1368 1368 File + limit + -ra:b, b < tip, (b - a) < limit:
1369 1369
1370 1370 $ hg glog -l10 -r33:34 a
1371 1371 o changeset: 34:fea3ac5810e0
1372 1372 | parent: 32:d06dffa21a31
1373 1373 | user: test
1374 1374 | date: Thu Jan 01 00:00:34 1970 +0000
1375 1375 | summary: (34) head
1376 1376 |
1377 1377 | o changeset: 33:68608f5145f9
1378 1378 | | parent: 18:1aa84d96232a
1379 1379 | | user: test
1380 1380 | | date: Thu Jan 01 00:00:33 1970 +0000
1381 1381 | | summary: (33) head
1382 1382 | |
1383 1383
1384 1384 Do not crash or produce strange graphs if history is buggy
1385 1385
1386 1386 $ hg branch branch
1387 1387 marked working directory as branch branch
1388 1388 (branches are permanent and global, did you want a bookmark?)
1389 1389 $ commit 36 "buggy merge: identical parents" 35 35
1390 1390 $ hg glog -l5
1391 1391 @ changeset: 36:08a19a744424
1392 1392 | branch: branch
1393 1393 | tag: tip
1394 1394 | parent: 35:9159c3644c5e
1395 1395 | parent: 35:9159c3644c5e
1396 1396 | user: test
1397 1397 | date: Thu Jan 01 00:00:36 1970 +0000
1398 1398 | summary: (36) buggy merge: identical parents
1399 1399 |
1400 1400 o changeset: 35:9159c3644c5e
1401 1401 | user: test
1402 1402 | date: Thu Jan 01 00:00:00 1970 +0000
1403 1403 | summary: 0
1404 1404 |
1405 1405 o changeset: 34:fea3ac5810e0
1406 1406 | parent: 32:d06dffa21a31
1407 1407 | user: test
1408 1408 | date: Thu Jan 01 00:00:34 1970 +0000
1409 1409 | summary: (34) head
1410 1410 |
1411 1411 | o changeset: 33:68608f5145f9
1412 1412 | | parent: 18:1aa84d96232a
1413 1413 | | user: test
1414 1414 | | date: Thu Jan 01 00:00:33 1970 +0000
1415 1415 | | summary: (33) head
1416 1416 | |
1417 1417 o | changeset: 32:d06dffa21a31
1418 1418 |\ \ parent: 27:886ed638191b
1419 1419 | | | parent: 31:621d83e11f67
1420 1420 | | | user: test
1421 1421 | | | date: Thu Jan 01 00:00:32 1970 +0000
1422 1422 | | | summary: (32) expand
1423 1423 | | |
1424 1424
1425 1425 Test log -G options
1426 1426
1427 1427 $ testlog() {
1428 1428 > hg log -G --print-revset "$@"
1429 1429 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1430 1430 > | sed 's/.*nodetag/nodetag/' > log.nodes
1431 1431 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1432 1432 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1433 1433 > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
1434 1434 > }
1435 1435
1436 1436 glog always reorders nodes which explains the difference with log
1437 1437
1438 1438 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1439 1439 ['27', '25', '21', '34', '32', '31']
1440 1440 []
1441 1441 --- log.nodes * (glob)
1442 1442 +++ glog.nodes * (glob)
1443 1443 @@ -1,6 +1,6 @@
1444 1444 -nodetag 27
1445 1445 -nodetag 25
1446 1446 -nodetag 21
1447 1447 nodetag 34
1448 1448 nodetag 32
1449 1449 nodetag 31
1450 1450 +nodetag 27
1451 1451 +nodetag 25
1452 1452 +nodetag 21
1453 1453 $ testlog -u test -u not-a-user
1454 1454 []
1455 1455 (group
1456 1456 (group
1457 1457 (or
1458 1458 (func
1459 1459 ('symbol', 'user')
1460 1460 ('string', 'test'))
1461 1461 (func
1462 1462 ('symbol', 'user')
1463 1463 ('string', 'not-a-user')))))
1464 1464 $ testlog -b not-a-branch
1465 1465 abort: unknown revision 'not-a-branch'!
1466 1466 abort: unknown revision 'not-a-branch'!
1467 1467 abort: unknown revision 'not-a-branch'!
1468 1468 $ testlog -b 35 -b 36 --only-branch branch
1469 1469 []
1470 1470 (group
1471 1471 (group
1472 1472 (or
1473 1473 (or
1474 1474 (func
1475 1475 ('symbol', 'branch')
1476 1476 ('string', 'default'))
1477 1477 (func
1478 1478 ('symbol', 'branch')
1479 1479 ('string', 'branch')))
1480 1480 (func
1481 1481 ('symbol', 'branch')
1482 1482 ('string', 'branch')))))
1483 1483 $ testlog -k expand -k merge
1484 1484 []
1485 1485 (group
1486 1486 (group
1487 1487 (or
1488 1488 (func
1489 1489 ('symbol', 'keyword')
1490 1490 ('string', 'expand'))
1491 1491 (func
1492 1492 ('symbol', 'keyword')
1493 1493 ('string', 'merge')))))
1494 1494 $ testlog --only-merges
1495 1495 []
1496 1496 (group
1497 1497 (func
1498 1498 ('symbol', 'merge')
1499 1499 None))
1500 1500 $ testlog --no-merges
1501 1501 []
1502 1502 (group
1503 1503 (not
1504 1504 (func
1505 1505 ('symbol', 'merge')
1506 1506 None)))
1507 1507 $ testlog --date '2 0 to 4 0'
1508 1508 []
1509 1509 (group
1510 1510 (func
1511 1511 ('symbol', 'date')
1512 1512 ('string', '2 0 to 4 0')))
1513 1513 $ hg log -G -d 'brace ) in a date'
1514 1514 abort: invalid date: 'brace ) in a date'
1515 1515 [255]
1516 1516 $ testlog --prune 31 --prune 32
1517 1517 []
1518 1518 (group
1519 1519 (group
1520 1520 (and
1521 1521 (not
1522 1522 (group
1523 1523 (or
1524 1524 ('string', '31')
1525 1525 (func
1526 1526 ('symbol', 'ancestors')
1527 1527 ('string', '31')))))
1528 1528 (not
1529 1529 (group
1530 1530 (or
1531 1531 ('string', '32')
1532 1532 (func
1533 1533 ('symbol', 'ancestors')
1534 1534 ('string', '32'))))))))
1535 1535
1536 1536 Dedicated repo for --follow and paths filtering. The g is crafted to
1537 1537 have 2 filelog topological heads in a linear changeset graph.
1538 1538
1539 1539 $ cd ..
1540 1540 $ hg init follow
1541 1541 $ cd follow
1542 1542 $ testlog --follow
1543 1543 []
1544 1544 []
1545 abort: unknown revision '0'!
1546 1545 $ echo a > a
1547 1546 $ echo aa > aa
1548 1547 $ echo f > f
1549 1548 $ hg ci -Am "add a" a aa f
1550 1549 $ hg cp a b
1551 1550 $ hg cp f g
1552 1551 $ hg ci -m "copy a b"
1553 1552 $ mkdir dir
1554 1553 $ hg mv b dir
1555 1554 $ echo g >> g
1556 1555 $ echo f >> f
1557 1556 $ hg ci -m "mv b dir/b"
1558 1557 $ hg mv a b
1559 1558 $ hg cp -f f g
1560 1559 $ echo a > d
1561 1560 $ hg add d
1562 1561 $ hg ci -m "mv a b; add d"
1563 1562 $ hg mv dir/b e
1564 1563 $ hg ci -m "mv dir/b e"
1565 1564 $ hg glog --template '({rev}) {desc|firstline}\n'
1566 1565 @ (4) mv dir/b e
1567 1566 |
1568 1567 o (3) mv a b; add d
1569 1568 |
1570 1569 o (2) mv b dir/b
1571 1570 |
1572 1571 o (1) copy a b
1573 1572 |
1574 1573 o (0) add a
1575 1574
1576 1575
1577 1576 $ testlog a
1578 1577 []
1579 1578 (group
1580 1579 (group
1581 1580 (func
1582 1581 ('symbol', 'filelog')
1583 1582 ('string', 'a'))))
1584 1583 $ testlog a b
1585 1584 []
1586 1585 (group
1587 1586 (group
1588 1587 (or
1589 1588 (func
1590 1589 ('symbol', 'filelog')
1591 1590 ('string', 'a'))
1592 1591 (func
1593 1592 ('symbol', 'filelog')
1594 1593 ('string', 'b')))))
1595 1594
1596 1595 Test falling back to slow path for non-existing files
1597 1596
1598 1597 $ testlog a c
1599 1598 []
1600 1599 (group
1601 1600 (func
1602 1601 ('symbol', '_matchfiles')
1603 1602 (list
1604 1603 (list
1605 1604 (list
1606 1605 ('string', 'r:')
1607 1606 ('string', 'd:relpath'))
1608 1607 ('string', 'p:a'))
1609 1608 ('string', 'p:c'))))
1610 1609
1611 1610 Test multiple --include/--exclude/paths
1612 1611
1613 1612 $ testlog --include a --include e --exclude b --exclude e a e
1614 1613 []
1615 1614 (group
1616 1615 (func
1617 1616 ('symbol', '_matchfiles')
1618 1617 (list
1619 1618 (list
1620 1619 (list
1621 1620 (list
1622 1621 (list
1623 1622 (list
1624 1623 (list
1625 1624 ('string', 'r:')
1626 1625 ('string', 'd:relpath'))
1627 1626 ('string', 'p:a'))
1628 1627 ('string', 'p:e'))
1629 1628 ('string', 'i:a'))
1630 1629 ('string', 'i:e'))
1631 1630 ('string', 'x:b'))
1632 1631 ('string', 'x:e'))))
1633 1632
1634 1633 Test glob expansion of pats
1635 1634
1636 1635 $ expandglobs=`python -c "import mercurial.util; \
1637 1636 > print mercurial.util.expandglobs and 'true' or 'false'"`
1638 1637 $ if [ $expandglobs = "true" ]; then
1639 1638 > testlog 'a*';
1640 1639 > else
1641 1640 > testlog a*;
1642 1641 > fi;
1643 1642 []
1644 1643 (group
1645 1644 (group
1646 1645 (func
1647 1646 ('symbol', 'filelog')
1648 1647 ('string', 'aa'))))
1649 1648
1650 1649 Test --follow on a directory
1651 1650
1652 1651 $ testlog -f dir
1653 1652 abort: cannot follow file not in parent revision: "dir"
1654 1653 abort: cannot follow file not in parent revision: "dir"
1655 1654 abort: cannot follow file not in parent revision: "dir"
1656 1655
1657 1656 Test --follow on file not in parent revision
1658 1657
1659 1658 $ testlog -f a
1660 1659 abort: cannot follow file not in parent revision: "a"
1661 1660 abort: cannot follow file not in parent revision: "a"
1662 1661 abort: cannot follow file not in parent revision: "a"
1663 1662
1664 1663 Test --follow and patterns
1665 1664
1666 1665 $ testlog -f 'glob:*'
1667 1666 abort: can only follow copies/renames for explicit filenames
1668 1667 abort: can only follow copies/renames for explicit filenames
1669 1668 abort: can only follow copies/renames for explicit filenames
1670 1669
1671 1670 Test --follow on a single rename
1672 1671
1673 1672 $ hg up -q 2
1674 1673 $ testlog -f a
1675 1674 []
1676 1675 (group
1677 1676 (group
1678 1677 (func
1679 1678 ('symbol', 'follow')
1680 1679 ('string', 'a'))))
1681 1680
1682 1681 Test --follow and multiple renames
1683 1682
1684 1683 $ hg up -q tip
1685 1684 $ testlog -f e
1686 1685 []
1687 1686 (group
1688 1687 (group
1689 1688 (func
1690 1689 ('symbol', 'follow')
1691 1690 ('string', 'e'))))
1692 1691
1693 1692 Test --follow and multiple filelog heads
1694 1693
1695 1694 $ hg up -q 2
1696 1695 $ testlog -f g
1697 1696 []
1698 1697 (group
1699 1698 (group
1700 1699 (func
1701 1700 ('symbol', 'follow')
1702 1701 ('string', 'g'))))
1703 1702 $ cat log.nodes
1704 1703 nodetag 2
1705 1704 nodetag 1
1706 1705 nodetag 0
1707 1706 $ hg up -q tip
1708 1707 $ testlog -f g
1709 1708 []
1710 1709 (group
1711 1710 (group
1712 1711 (func
1713 1712 ('symbol', 'follow')
1714 1713 ('string', 'g'))))
1715 1714 $ cat log.nodes
1716 1715 nodetag 3
1717 1716 nodetag 2
1718 1717 nodetag 0
1719 1718
1720 1719 Test --follow and multiple files
1721 1720
1722 1721 $ testlog -f g e
1723 1722 []
1724 1723 (group
1725 1724 (group
1726 1725 (or
1727 1726 (func
1728 1727 ('symbol', 'follow')
1729 1728 ('string', 'g'))
1730 1729 (func
1731 1730 ('symbol', 'follow')
1732 1731 ('string', 'e')))))
1733 1732 $ cat log.nodes
1734 1733 nodetag 4
1735 1734 nodetag 3
1736 1735 nodetag 2
1737 1736 nodetag 1
1738 1737 nodetag 0
1739 1738
1740 1739 Test --follow-first
1741 1740
1742 1741 $ hg up -q 3
1743 1742 $ echo ee > e
1744 1743 $ hg ci -Am "add another e" e
1745 1744 created new head
1746 1745 $ hg merge --tool internal:other 4
1747 1746 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1748 1747 (branch merge, don't forget to commit)
1749 1748 $ echo merge > e
1750 1749 $ hg ci -m "merge 5 and 4"
1751 1750 $ testlog --follow-first
1752 1751 []
1753 1752 (group
1754 1753 (func
1755 1754 ('symbol', '_firstancestors')
1756 1755 ('symbol', '6')))
1757 1756
1758 1757 Cannot compare with log --follow-first FILE as it never worked
1759 1758
1760 1759 $ hg log -G --print-revset --follow-first e
1761 1760 []
1762 1761 (group
1763 1762 (group
1764 1763 (func
1765 1764 ('symbol', '_followfirst')
1766 1765 ('string', 'e'))))
1767 1766 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1768 1767 @ 6 merge 5 and 4
1769 1768 |\
1770 1769 o | 5 add another e
1771 1770 | |
1772 1771
1773 1772 Test --copies
1774 1773
1775 1774 $ hg log -G --copies --template "{rev} {desc|firstline} \
1776 1775 > copies: {file_copies_switch}\n"
1777 1776 @ 6 merge 5 and 4 copies:
1778 1777 |\
1779 1778 | o 5 add another e copies:
1780 1779 | |
1781 1780 o | 4 mv dir/b e copies: e (dir/b)
1782 1781 |/
1783 1782 o 3 mv a b; add d copies: b (a)g (f)
1784 1783 |
1785 1784 o 2 mv b dir/b copies: dir/b (b)
1786 1785 |
1787 1786 o 1 copy a b copies: b (a)g (f)
1788 1787 |
1789 1788 o 0 add a copies:
1790 1789
1791 1790 Test "set:..." and parent revision
1792 1791
1793 1792 $ hg up -q 4
1794 1793 $ testlog "set:copied()"
1795 1794 []
1796 1795 (group
1797 1796 (func
1798 1797 ('symbol', '_matchfiles')
1799 1798 (list
1800 1799 (list
1801 1800 ('string', 'r:')
1802 1801 ('string', 'd:relpath'))
1803 1802 ('string', 'p:set:copied()'))))
1804 1803 $ testlog --include "set:copied()"
1805 1804 []
1806 1805 (group
1807 1806 (func
1808 1807 ('symbol', '_matchfiles')
1809 1808 (list
1810 1809 (list
1811 1810 ('string', 'r:')
1812 1811 ('string', 'd:relpath'))
1813 1812 ('string', 'i:set:copied()'))))
1814 1813 $ testlog -r "sort(file('set:copied()'), -rev)"
1815 1814 ["sort(file('set:copied()'), -rev)"]
1816 1815 []
1817 1816
1818 1817 Test --removed
1819 1818
1820 1819 $ testlog --removed
1821 1820 []
1822 1821 []
1823 1822 $ testlog --removed a
1824 1823 []
1825 1824 (group
1826 1825 (func
1827 1826 ('symbol', '_matchfiles')
1828 1827 (list
1829 1828 (list
1830 1829 ('string', 'r:')
1831 1830 ('string', 'd:relpath'))
1832 1831 ('string', 'p:a'))))
1833 1832 $ testlog --removed --follow a
1834 1833 abort: can only follow copies/renames for explicit filenames
1835 1834 abort: can only follow copies/renames for explicit filenames
1836 1835 abort: can only follow copies/renames for explicit filenames
1837 1836
1838 1837 Test --patch and --stat with --follow and --follow-first
1839 1838
1840 1839 $ hg up -q 3
1841 1840 $ hg log -G --git --patch b
1842 1841 o changeset: 1:216d4c92cf98
1843 1842 | user: test
1844 1843 | date: Thu Jan 01 00:00:00 1970 +0000
1845 1844 | summary: copy a b
1846 1845 |
1847 1846 | diff --git a/a b/b
1848 1847 | copy from a
1849 1848 | copy to b
1850 1849 |
1851 1850
1852 1851 $ hg log -G --git --stat b
1853 1852 o changeset: 1:216d4c92cf98
1854 1853 | user: test
1855 1854 | date: Thu Jan 01 00:00:00 1970 +0000
1856 1855 | summary: copy a b
1857 1856 |
1858 1857 | a | 0
1859 1858 | 1 files changed, 0 insertions(+), 0 deletions(-)
1860 1859 |
1861 1860
1862 1861 $ hg log -G --git --patch --follow b
1863 1862 o changeset: 1:216d4c92cf98
1864 1863 | user: test
1865 1864 | date: Thu Jan 01 00:00:00 1970 +0000
1866 1865 | summary: copy a b
1867 1866 |
1868 1867 | diff --git a/a b/b
1869 1868 | copy from a
1870 1869 | copy to b
1871 1870 |
1872 1871 o changeset: 0:f8035bb17114
1873 1872 user: test
1874 1873 date: Thu Jan 01 00:00:00 1970 +0000
1875 1874 summary: add a
1876 1875
1877 1876 diff --git a/a b/a
1878 1877 new file mode 100644
1879 1878 --- /dev/null
1880 1879 +++ b/a
1881 1880 @@ -0,0 +1,1 @@
1882 1881 +a
1883 1882
1884 1883
1885 1884 $ hg log -G --git --stat --follow b
1886 1885 o changeset: 1:216d4c92cf98
1887 1886 | user: test
1888 1887 | date: Thu Jan 01 00:00:00 1970 +0000
1889 1888 | summary: copy a b
1890 1889 |
1891 1890 | a | 0
1892 1891 | 1 files changed, 0 insertions(+), 0 deletions(-)
1893 1892 |
1894 1893 o changeset: 0:f8035bb17114
1895 1894 user: test
1896 1895 date: Thu Jan 01 00:00:00 1970 +0000
1897 1896 summary: add a
1898 1897
1899 1898 a | 1 +
1900 1899 1 files changed, 1 insertions(+), 0 deletions(-)
1901 1900
1902 1901
1903 1902 $ hg up -q 6
1904 1903 $ hg log -G --git --patch --follow-first e
1905 1904 @ changeset: 6:fc281d8ff18d
1906 1905 |\ tag: tip
1907 1906 | | parent: 5:99b31f1c2782
1908 1907 | | parent: 4:17d952250a9d
1909 1908 | | user: test
1910 1909 | | date: Thu Jan 01 00:00:00 1970 +0000
1911 1910 | | summary: merge 5 and 4
1912 1911 | |
1913 1912 | | diff --git a/e b/e
1914 1913 | | --- a/e
1915 1914 | | +++ b/e
1916 1915 | | @@ -1,1 +1,1 @@
1917 1916 | | -ee
1918 1917 | | +merge
1919 1918 | |
1920 1919 o | changeset: 5:99b31f1c2782
1921 1920 | | parent: 3:5918b8d165d1
1922 1921 | | user: test
1923 1922 | | date: Thu Jan 01 00:00:00 1970 +0000
1924 1923 | | summary: add another e
1925 1924 | |
1926 1925 | | diff --git a/e b/e
1927 1926 | | new file mode 100644
1928 1927 | | --- /dev/null
1929 1928 | | +++ b/e
1930 1929 | | @@ -0,0 +1,1 @@
1931 1930 | | +ee
1932 1931 | |
1933 1932
1934 1933 Test old-style --rev
1935 1934
1936 1935 $ hg tag 'foo-bar'
1937 1936 $ testlog -r 'foo-bar'
1938 1937 ['foo-bar']
1939 1938 []
1940 1939
1941 1940 Test --follow and forward --rev
1942 1941
1943 1942 $ hg up -q 6
1944 1943 $ echo g > g
1945 1944 $ hg ci -Am 'add g' g
1946 1945 created new head
1947 1946 $ hg up -q 2
1948 1947 $ hg log -G --template "{rev} {desc|firstline}\n"
1949 1948 o 8 add g
1950 1949 |
1951 1950 | o 7 Added tag foo-bar for changeset fc281d8ff18d
1952 1951 |/
1953 1952 o 6 merge 5 and 4
1954 1953 |\
1955 1954 | o 5 add another e
1956 1955 | |
1957 1956 o | 4 mv dir/b e
1958 1957 |/
1959 1958 o 3 mv a b; add d
1960 1959 |
1961 1960 @ 2 mv b dir/b
1962 1961 |
1963 1962 o 1 copy a b
1964 1963 |
1965 1964 o 0 add a
1966 1965
1967 1966 $ testlog --follow -r6 -r8 -r5 -r7 -r4
1968 1967 ['6', '8', '5', '7', '4']
1969 1968 (group
1970 1969 (func
1971 1970 ('symbol', 'descendants')
1972 1971 ('symbol', '6')))
1973 1972 --- log.nodes * (glob)
1974 1973 +++ glog.nodes * (glob)
1975 1974 @@ -1,3 +1,3 @@
1976 1975 -nodetag 6
1977 1976 nodetag 8
1978 1977 nodetag 7
1979 1978 +nodetag 6
1980 1979
1981 1980 Test --follow-first and forward --rev
1982 1981
1983 1982 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
1984 1983 ['6', '8', '5', '7', '4']
1985 1984 (group
1986 1985 (func
1987 1986 ('symbol', '_firstdescendants')
1988 1987 ('symbol', '6')))
1989 1988 --- log.nodes * (glob)
1990 1989 +++ glog.nodes * (glob)
1991 1990 @@ -1,3 +1,3 @@
1992 1991 -nodetag 6
1993 1992 nodetag 8
1994 1993 nodetag 7
1995 1994 +nodetag 6
1996 1995
1997 1996 Test --follow and backward --rev
1998 1997
1999 1998 $ testlog --follow -r6 -r5 -r7 -r8 -r4
2000 1999 ['6', '5', '7', '8', '4']
2001 2000 (group
2002 2001 (func
2003 2002 ('symbol', 'ancestors')
2004 2003 ('symbol', '6')))
2005 2004
2006 2005 Test --follow-first and backward --rev
2007 2006
2008 2007 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2009 2008 ['6', '5', '7', '8', '4']
2010 2009 (group
2011 2010 (func
2012 2011 ('symbol', '_firstancestors')
2013 2012 ('symbol', '6')))
2014 2013
2015 2014 Test subdir
2016 2015
2017 2016 $ hg up -q 3
2018 2017 $ cd dir
2019 2018 $ testlog .
2020 2019 []
2021 2020 (group
2022 2021 (func
2023 2022 ('symbol', '_matchfiles')
2024 2023 (list
2025 2024 (list
2026 2025 ('string', 'r:')
2027 2026 ('string', 'd:relpath'))
2028 2027 ('string', 'p:.'))))
2029 2028 $ testlog ../b
2030 2029 []
2031 2030 (group
2032 2031 (group
2033 2032 (func
2034 2033 ('symbol', 'filelog')
2035 2034 ('string', '../b'))))
2036 2035 $ testlog -f ../b
2037 2036 []
2038 2037 (group
2039 2038 (group
2040 2039 (func
2041 2040 ('symbol', 'follow')
2042 2041 ('string', 'b'))))
2043 2042 $ cd ..
2044 2043
2045 2044 Test --hidden
2046 2045 (enable obsolete)
2047 2046
2048 2047 $ cat > ${TESTTMP}/obs.py << EOF
2049 2048 > import mercurial.obsolete
2050 2049 > mercurial.obsolete._enabled = True
2051 2050 > EOF
2052 2051 $ echo '[extensions]' >> $HGRCPATH
2053 2052 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
2054 2053
2055 2054 $ hg debugobsolete `hg id --debug -i -r 8`
2056 2055 $ testlog
2057 2056 []
2058 2057 []
2059 2058 $ testlog --hidden
2060 2059 []
2061 2060 []
2062 2061 $ hg glog --template '{rev} {desc}\n'
2063 2062 o 7 Added tag foo-bar for changeset fc281d8ff18d
2064 2063 |
2065 2064 o 6 merge 5 and 4
2066 2065 |\
2067 2066 | o 5 add another e
2068 2067 | |
2069 2068 o | 4 mv dir/b e
2070 2069 |/
2071 2070 @ 3 mv a b; add d
2072 2071 |
2073 2072 o 2 mv b dir/b
2074 2073 |
2075 2074 o 1 copy a b
2076 2075 |
2077 2076 o 0 add a
2078 2077
2079 2078
2080 2079 A template without trailing newline should do something sane
2081 2080
2082 2081 $ hg glog -r ::2 --template '{rev} {desc}'
2083 2082 o 2 mv b dir/b
2084 2083 |
2085 2084 o 1 copy a b
2086 2085 |
2087 2086 o 0 add a
2088 2087
2089 2088
2090 2089 Extra newlines must be preserved
2091 2090
2092 2091 $ hg glog -r ::2 --template '\n{rev} {desc}\n\n'
2093 2092 o
2094 2093 | 2 mv b dir/b
2095 2094 |
2096 2095 o
2097 2096 | 1 copy a b
2098 2097 |
2099 2098 o
2100 2099 0 add a
2101 2100
2102 2101
2103 2102 The almost-empty template should do something sane too ...
2104 2103
2105 2104 $ hg glog -r ::2 --template '\n'
2106 2105 o
2107 2106 |
2108 2107 o
2109 2108 |
2110 2109 o
2111 2110
2112 2111
2113 2112 issue3772
2114 2113
2115 2114 $ hg glog -r :null
2116 2115 o changeset: -1:000000000000
2117 2116 user:
2118 2117 date: Thu Jan 01 00:00:00 1970 +0000
2119 2118
2120 2119 $ hg glog -r null:null
2121 2120 o changeset: -1:000000000000
2122 2121 user:
2123 2122 date: Thu Jan 01 00:00:00 1970 +0000
2124 2123
2125 2124
2126 2125 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now