##// END OF EJS Templates
tags: explicitly log which tags cache file is being written...
Gregory Szorc -
r24763:a698e088 default
parent child Browse files
Show More
@@ -1,533 +1,534
1 1 # tags.py - read tag info from local repository
2 2 #
3 3 # Copyright 2009 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2009 Greg Ward <greg@gerg.ca>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 # Currently this module only deals with reading and caching tags.
10 10 # Eventually, it could take care of updating (adding/removing/moving)
11 11 # tags too.
12 12
13 13 from node import nullid, bin, hex, short
14 14 from i18n import _
15 15 import util
16 16 import encoding
17 17 import error
18 18 from array import array
19 19 import errno
20 20 import time
21 21
22 22 # Tags computation can be expensive and caches exist to make it fast in
23 23 # the common case.
24 24 #
25 25 # The "hgtagsfnodes1" cache file caches the .hgtags filenode values for
26 26 # each revision in the repository. The file is effectively an array of
27 27 # fixed length records. Read the docs for "hgtagsfnodescache" for technical
28 28 # details.
29 29 #
30 30 # The .hgtags filenode cache grows in proportion to the length of the
31 31 # changelog. The file is truncated when the # changelog is stripped.
32 32 #
33 33 # The purpose of the filenode cache is to avoid the most expensive part
34 34 # of finding global tags, which is looking up the .hgtags filenode in the
35 35 # manifest for each head. This can take dozens or over 100ms for
36 36 # repositories with very large manifests. Multiplied by dozens or even
37 37 # hundreds of heads and there is a significant performance concern.
38 38 #
39 39 # There also exist a separate cache file for each repository filter.
40 40 # These "tags-*" files store information about the history of tags.
41 41 #
42 42 # The tags cache files consists of a cache validation line followed by
43 43 # a history of tags.
44 44 #
45 45 # The cache validation line has the format:
46 46 #
47 47 # <tiprev> <tipnode> [<filteredhash>]
48 48 #
49 49 # <tiprev> is an integer revision and <tipnode> is a 40 character hex
50 50 # node for that changeset. These redundantly identify the repository
51 51 # tip from the time the cache was written. In addition, <filteredhash>,
52 52 # if present, is a 40 character hex hash of the contents of the filtered
53 53 # revisions for this filter. If the set of filtered revs changes, the
54 54 # hash will change and invalidate the cache.
55 55 #
56 56 # The history part of the tags cache consists of lines of the form:
57 57 #
58 58 # <node> <tag>
59 59 #
60 60 # (This format is identical to that of .hgtags files.)
61 61 #
62 62 # <tag> is the tag name and <node> is the 40 character hex changeset
63 63 # the tag is associated with.
64 64 #
65 65 # Tags are written sorted by tag name.
66 66 #
67 67 # Tags associated with multiple changesets have an entry for each changeset.
68 68 # The most recent changeset (in terms of revlog ordering for the head
69 69 # setting it) for each tag is last.
70 70
71 71 def findglobaltags(ui, repo, alltags, tagtypes):
72 72 '''Find global tags in a repo.
73 73
74 74 "alltags" maps tag name to (node, hist) 2-tuples.
75 75
76 76 "tagtypes" maps tag name to tag type. Global tags always have the
77 77 "global" tag type.
78 78
79 79 The "alltags" and "tagtypes" dicts are updated in place. Empty dicts
80 80 should be passed in.
81 81
82 82 The tags cache is read and updated as a side-effect of calling.
83 83 '''
84 84 # This is so we can be lazy and assume alltags contains only global
85 85 # tags when we pass it to _writetagcache().
86 86 assert len(alltags) == len(tagtypes) == 0, \
87 87 "findglobaltags() should be called first"
88 88
89 89 (heads, tagfnode, valid, cachetags, shouldwrite) = _readtagcache(ui, repo)
90 90 if cachetags is not None:
91 91 assert not shouldwrite
92 92 # XXX is this really 100% correct? are there oddball special
93 93 # cases where a global tag should outrank a local tag but won't,
94 94 # because cachetags does not contain rank info?
95 95 _updatetags(cachetags, 'global', alltags, tagtypes)
96 96 return
97 97
98 98 seen = set() # set of fnode
99 99 fctx = None
100 100 for head in reversed(heads): # oldest to newest
101 101 assert head in repo.changelog.nodemap, \
102 102 "tag cache returned bogus head %s" % short(head)
103 103
104 104 fnode = tagfnode.get(head)
105 105 if fnode and fnode not in seen:
106 106 seen.add(fnode)
107 107 if not fctx:
108 108 fctx = repo.filectx('.hgtags', fileid=fnode)
109 109 else:
110 110 fctx = fctx.filectx(fnode)
111 111
112 112 filetags = _readtags(ui, repo, fctx.data().splitlines(), fctx)
113 113 _updatetags(filetags, 'global', alltags, tagtypes)
114 114
115 115 # and update the cache (if necessary)
116 116 if shouldwrite:
117 117 _writetagcache(ui, repo, valid, alltags)
118 118
119 119 def readlocaltags(ui, repo, alltags, tagtypes):
120 120 '''Read local tags in repo. Update alltags and tagtypes.'''
121 121 try:
122 122 data = repo.vfs.read("localtags")
123 123 except IOError, inst:
124 124 if inst.errno != errno.ENOENT:
125 125 raise
126 126 return
127 127
128 128 # localtags is in the local encoding; re-encode to UTF-8 on
129 129 # input for consistency with the rest of this module.
130 130 filetags = _readtags(
131 131 ui, repo, data.splitlines(), "localtags",
132 132 recode=encoding.fromlocal)
133 133
134 134 # remove tags pointing to invalid nodes
135 135 cl = repo.changelog
136 136 for t in filetags.keys():
137 137 try:
138 138 cl.rev(filetags[t][0])
139 139 except (LookupError, ValueError):
140 140 del filetags[t]
141 141
142 142 _updatetags(filetags, "local", alltags, tagtypes)
143 143
144 144 def _readtaghist(ui, repo, lines, fn, recode=None, calcnodelines=False):
145 145 '''Read tag definitions from a file (or any source of lines).
146 146
147 147 This function returns two sortdicts with similar information:
148 148
149 149 - the first dict, bintaghist, contains the tag information as expected by
150 150 the _readtags function, i.e. a mapping from tag name to (node, hist):
151 151 - node is the node id from the last line read for that name,
152 152 - hist is the list of node ids previously associated with it (in file
153 153 order). All node ids are binary, not hex.
154 154
155 155 - the second dict, hextaglines, is a mapping from tag name to a list of
156 156 [hexnode, line number] pairs, ordered from the oldest to the newest node.
157 157
158 158 When calcnodelines is False the hextaglines dict is not calculated (an
159 159 empty dict is returned). This is done to improve this function's
160 160 performance in cases where the line numbers are not needed.
161 161 '''
162 162
163 163 bintaghist = util.sortdict()
164 164 hextaglines = util.sortdict()
165 165 count = 0
166 166
167 167 def warn(msg):
168 168 ui.warn(_("%s, line %s: %s\n") % (fn, count, msg))
169 169
170 170 for nline, line in enumerate(lines):
171 171 count += 1
172 172 if not line:
173 173 continue
174 174 try:
175 175 (nodehex, name) = line.split(" ", 1)
176 176 except ValueError:
177 177 warn(_("cannot parse entry"))
178 178 continue
179 179 name = name.strip()
180 180 if recode:
181 181 name = recode(name)
182 182 try:
183 183 nodebin = bin(nodehex)
184 184 except TypeError:
185 185 warn(_("node '%s' is not well formed") % nodehex)
186 186 continue
187 187
188 188 # update filetags
189 189 if calcnodelines:
190 190 # map tag name to a list of line numbers
191 191 if name not in hextaglines:
192 192 hextaglines[name] = []
193 193 hextaglines[name].append([nodehex, nline])
194 194 continue
195 195 # map tag name to (node, hist)
196 196 if name not in bintaghist:
197 197 bintaghist[name] = []
198 198 bintaghist[name].append(nodebin)
199 199 return bintaghist, hextaglines
200 200
201 201 def _readtags(ui, repo, lines, fn, recode=None, calcnodelines=False):
202 202 '''Read tag definitions from a file (or any source of lines).
203 203
204 204 Returns a mapping from tag name to (node, hist).
205 205
206 206 "node" is the node id from the last line read for that name. "hist"
207 207 is the list of node ids previously associated with it (in file order).
208 208 All node ids are binary, not hex.
209 209 '''
210 210 filetags, nodelines = _readtaghist(ui, repo, lines, fn, recode=recode,
211 211 calcnodelines=calcnodelines)
212 212 for tag, taghist in filetags.items():
213 213 filetags[tag] = (taghist[-1], taghist[:-1])
214 214 return filetags
215 215
216 216 def _updatetags(filetags, tagtype, alltags, tagtypes):
217 217 '''Incorporate the tag info read from one file into the two
218 218 dictionaries, alltags and tagtypes, that contain all tag
219 219 info (global across all heads plus local).'''
220 220
221 221 for name, nodehist in filetags.iteritems():
222 222 if name not in alltags:
223 223 alltags[name] = nodehist
224 224 tagtypes[name] = tagtype
225 225 continue
226 226
227 227 # we prefer alltags[name] if:
228 228 # it supersedes us OR
229 229 # mutual supersedes and it has a higher rank
230 230 # otherwise we win because we're tip-most
231 231 anode, ahist = nodehist
232 232 bnode, bhist = alltags[name]
233 233 if (bnode != anode and anode in bhist and
234 234 (bnode not in ahist or len(bhist) > len(ahist))):
235 235 anode = bnode
236 236 else:
237 237 tagtypes[name] = tagtype
238 238 ahist.extend([n for n in bhist if n not in ahist])
239 239 alltags[name] = anode, ahist
240 240
241 241 def _filename(repo):
242 242 """name of a tagcache file for a given repo or repoview"""
243 243 filename = 'cache/tags2'
244 244 if repo.filtername:
245 245 filename = '%s-%s' % (filename, repo.filtername)
246 246 return filename
247 247
248 248 def _readtagcache(ui, repo):
249 249 '''Read the tag cache.
250 250
251 251 Returns a tuple (heads, fnodes, validinfo, cachetags, shouldwrite).
252 252
253 253 If the cache is completely up-to-date, "cachetags" is a dict of the
254 254 form returned by _readtags() and "heads", "fnodes", and "validinfo" are
255 255 None and "shouldwrite" is False.
256 256
257 257 If the cache is not up to date, "cachetags" is None. "heads" is a list
258 258 of all heads currently in the repository, ordered from tip to oldest.
259 259 "validinfo" is a tuple describing cache validation info. This is used
260 260 when writing the tags cache. "fnodes" is a mapping from head to .hgtags
261 261 filenode. "shouldwrite" is True.
262 262
263 263 If the cache is not up to date, the caller is responsible for reading tag
264 264 info from each returned head. (See findglobaltags().)
265 265 '''
266 266 import scmutil # avoid cycle
267 267
268 268 try:
269 269 cachefile = repo.vfs(_filename(repo), 'r')
270 270 # force reading the file for static-http
271 271 cachelines = iter(cachefile)
272 272 except IOError:
273 273 cachefile = None
274 274
275 275 cacherev = None
276 276 cachenode = None
277 277 cachehash = None
278 278 if cachefile:
279 279 try:
280 280 validline = cachelines.next()
281 281 validline = validline.split()
282 282 cacherev = int(validline[0])
283 283 cachenode = bin(validline[1])
284 284 if len(validline) > 2:
285 285 cachehash = bin(validline[2])
286 286 except Exception:
287 287 # corruption of the cache, just recompute it.
288 288 pass
289 289
290 290 tipnode = repo.changelog.tip()
291 291 tiprev = len(repo.changelog) - 1
292 292
293 293 # Case 1 (common): tip is the same, so nothing has changed.
294 294 # (Unchanged tip trivially means no changesets have been added.
295 295 # But, thanks to localrepository.destroyed(), it also means none
296 296 # have been destroyed by strip or rollback.)
297 297 if (cacherev == tiprev
298 298 and cachenode == tipnode
299 299 and cachehash == scmutil.filteredhash(repo, tiprev)):
300 300 tags = _readtags(ui, repo, cachelines, cachefile.name)
301 301 cachefile.close()
302 302 return (None, None, None, tags, False)
303 303 if cachefile:
304 304 cachefile.close() # ignore rest of file
305 305
306 306 valid = (tiprev, tipnode, scmutil.filteredhash(repo, tiprev))
307 307
308 308 repoheads = repo.heads()
309 309 # Case 2 (uncommon): empty repo; get out quickly and don't bother
310 310 # writing an empty cache.
311 311 if repoheads == [nullid]:
312 312 return ([], {}, valid, {}, False)
313 313
314 314 # Case 3 (uncommon): cache file missing or empty.
315 315
316 316 # Case 4 (uncommon): tip rev decreased. This should only happen
317 317 # when we're called from localrepository.destroyed(). Refresh the
318 318 # cache so future invocations will not see disappeared heads in the
319 319 # cache.
320 320
321 321 # Case 5 (common): tip has changed, so we've added/replaced heads.
322 322
323 323 # As it happens, the code to handle cases 3, 4, 5 is the same.
324 324
325 325 # N.B. in case 4 (nodes destroyed), "new head" really means "newly
326 326 # exposed".
327 327 if not len(repo.file('.hgtags')):
328 328 # No tags have ever been committed, so we can avoid a
329 329 # potentially expensive search.
330 330 return ([], {}, valid, None, True)
331 331
332 332 starttime = time.time()
333 333
334 334 # Now we have to lookup the .hgtags filenode for every new head.
335 335 # This is the most expensive part of finding tags, so performance
336 336 # depends primarily on the size of newheads. Worst case: no cache
337 337 # file, so newheads == repoheads.
338 338 fnodescache = hgtagsfnodescache(repo.unfiltered())
339 339 cachefnode = {}
340 340 for head in reversed(repoheads):
341 341 fnode = fnodescache.getfnode(head)
342 342 if fnode != nullid:
343 343 cachefnode[head] = fnode
344 344
345 345 fnodescache.write()
346 346
347 347 duration = time.time() - starttime
348 348 ui.log('tagscache',
349 349 '%d/%d cache hits/lookups in %0.4f '
350 350 'seconds\n',
351 351 fnodescache.hitcount, fnodescache.lookupcount, duration)
352 352
353 353 # Caller has to iterate over all heads, but can use the filenodes in
354 354 # cachefnode to get to each .hgtags revision quickly.
355 355 return (repoheads, cachefnode, valid, None, True)
356 356
357 357 def _writetagcache(ui, repo, valid, cachetags):
358 filename = _filename(repo)
358 359 try:
359 cachefile = repo.vfs(_filename(repo), 'w', atomictemp=True)
360 cachefile = repo.vfs(filename, 'w', atomictemp=True)
360 361 except (OSError, IOError):
361 362 return
362 363
363 ui.log('tagscache', 'writing tags cache file with %d tags\n',
364 len(cachetags))
364 ui.log('tagscache', 'writing .hg/%s with %d tags\n',
365 filename, len(cachetags))
365 366
366 367 if valid[2]:
367 368 cachefile.write('%d %s %s\n' % (valid[0], hex(valid[1]), hex(valid[2])))
368 369 else:
369 370 cachefile.write('%d %s\n' % (valid[0], hex(valid[1])))
370 371
371 372 # Tag names in the cache are in UTF-8 -- which is the whole reason
372 373 # we keep them in UTF-8 throughout this module. If we converted
373 374 # them local encoding on input, we would lose info writing them to
374 375 # the cache.
375 376 for (name, (node, hist)) in sorted(cachetags.iteritems()):
376 377 for n in hist:
377 378 cachefile.write("%s %s\n" % (hex(n), name))
378 379 cachefile.write("%s %s\n" % (hex(node), name))
379 380
380 381 try:
381 382 cachefile.close()
382 383 except (OSError, IOError):
383 384 pass
384 385
385 386 _fnodescachefile = 'cache/hgtagsfnodes1'
386 387 _fnodesrecsize = 4 + 20 # changeset fragment + filenode
387 388 _fnodesmissingrec = '\xff' * 24
388 389
389 390 class hgtagsfnodescache(object):
390 391 """Persistent cache mapping revisions to .hgtags filenodes.
391 392
392 393 The cache is an array of records. Each item in the array corresponds to
393 394 a changelog revision. Values in the array contain the first 4 bytes of
394 395 the node hash and the 20 bytes .hgtags filenode for that revision.
395 396
396 397 The first 4 bytes are present as a form of verification. Repository
397 398 stripping and rewriting may change the node at a numeric revision in the
398 399 changelog. The changeset fragment serves as a verifier to detect
399 400 rewriting. This logic is shared with the rev branch cache (see
400 401 branchmap.py).
401 402
402 403 The instance holds in memory the full cache content but entries are
403 404 only parsed on read.
404 405
405 406 Instances behave like lists. ``c[i]`` works where i is a rev or
406 407 changeset node. Missing indexes are populated automatically on access.
407 408 """
408 409 def __init__(self, repo):
409 410 assert repo.filtername is None
410 411
411 412 self._repo = repo
412 413
413 414 # Only for reporting purposes.
414 415 self.lookupcount = 0
415 416 self.hitcount = 0
416 417
417 418 self._raw = array('c')
418 419
419 420 data = repo.vfs.tryread(_fnodescachefile)
420 421 self._raw.fromstring(data)
421 422
422 423 # The end state of self._raw is an array that is of the exact length
423 424 # required to hold a record for every revision in the repository.
424 425 # We truncate or extend the array as necessary. self._dirtyoffset is
425 426 # defined to be the start offset at which we need to write the output
426 427 # file. This offset is also adjusted when new entries are calculated
427 428 # for array members.
428 429 cllen = len(repo.changelog)
429 430 wantedlen = cllen * _fnodesrecsize
430 431 rawlen = len(self._raw)
431 432
432 433 self._dirtyoffset = None
433 434
434 435 if rawlen < wantedlen:
435 436 self._dirtyoffset = rawlen
436 437 self._raw.extend('\xff' * (wantedlen - rawlen))
437 438 elif rawlen > wantedlen:
438 439 # There's no easy way to truncate array instances. This seems
439 440 # slightly less evil than copying a potentially large array slice.
440 441 for i in range(rawlen - wantedlen):
441 442 self._raw.pop()
442 443 self._dirtyoffset = len(self._raw)
443 444
444 445 def getfnode(self, node):
445 446 """Obtain the filenode of the .hgtags file at a specified revision.
446 447
447 448 If the value is in the cache, the entry will be validated and returned.
448 449 Otherwise, the filenode will be computed and returned.
449 450
450 451 If an .hgtags does not exist at the specified revision, nullid is
451 452 returned.
452 453 """
453 454 ctx = self._repo[node]
454 455 rev = ctx.rev()
455 456
456 457 self.lookupcount += 1
457 458
458 459 offset = rev * _fnodesrecsize
459 460 record = self._raw[offset:offset + _fnodesrecsize].tostring()
460 461 properprefix = node[0:4]
461 462
462 463 # Validate and return existing entry.
463 464 if record != _fnodesmissingrec:
464 465 fileprefix = record[0:4]
465 466
466 467 if fileprefix == properprefix:
467 468 self.hitcount += 1
468 469 return record[4:]
469 470
470 471 # Fall through.
471 472
472 473 # If we get here, the entry is either missing or invalid. Populate it.
473 474 try:
474 475 fnode = ctx.filenode('.hgtags')
475 476 except error.LookupError:
476 477 # No .hgtags file on this revision.
477 478 fnode = nullid
478 479
479 480 # Slices on array instances only accept other array.
480 481 entry = array('c', properprefix + fnode)
481 482 self._raw[offset:offset + _fnodesrecsize] = entry
482 483 # self._dirtyoffset could be None.
483 484 self._dirtyoffset = min(self._dirtyoffset, offset) or 0
484 485
485 486 return fnode
486 487
487 488 def write(self):
488 489 """Perform all necessary writes to cache file.
489 490
490 491 This may no-op if no writes are needed or if a write lock could
491 492 not be obtained.
492 493 """
493 494 if self._dirtyoffset is None:
494 495 return
495 496
496 497 data = self._raw[self._dirtyoffset:]
497 498 if not data:
498 499 return
499 500
500 501 repo = self._repo
501 502
502 503 try:
503 504 lock = repo.wlock(wait=False)
504 505 except error.LockHeld:
505 506 repo.ui.log('tagscache',
506 507 'not writing .hg/%s because lock held\n' %
507 508 (_fnodescachefile))
508 509 return
509 510
510 511 try:
511 512 try:
512 513 f = repo.vfs.open(_fnodescachefile, 'ab')
513 514 try:
514 515 # if the file has been truncated
515 516 actualoffset = f.tell()
516 517 if actualoffset < self._dirtyoffset:
517 518 self._dirtyoffset = actualoffset
518 519 data = self._raw[self._dirtyoffset:]
519 520 f.seek(self._dirtyoffset)
520 521 f.truncate()
521 522 repo.ui.log('tagscache',
522 523 'writing %d bytes to %s\n' % (
523 524 len(data), _fnodescachefile))
524 525 f.write(data)
525 526 self._dirtyoffset = None
526 527 finally:
527 528 f.close()
528 529 except (IOError, OSError), inst:
529 530 repo.ui.log('tagscache',
530 531 "couldn't write %s: %s\n" % (
531 532 _fnodescachefile, inst))
532 533 finally:
533 534 lock.release()
@@ -1,147 +1,147
1 1 setup
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [extensions]
4 4 > blackbox=
5 5 > mock=$TESTDIR/mockblackbox.py
6 6 > mq=
7 7 > EOF
8 8 $ hg init blackboxtest
9 9 $ cd blackboxtest
10 10
11 11 command, exit codes, and duration
12 12
13 13 $ echo a > a
14 14 $ hg add a
15 15 $ hg blackbox
16 16 1970/01/01 00:00:00 bob> add a
17 17 1970/01/01 00:00:00 bob> add a exited 0 after * seconds (glob)
18 18
19 19 incoming change tracking
20 20
21 21 create two heads to verify that we only see one change in the log later
22 22 $ hg commit -ma
23 23 $ hg up null
24 24 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
25 25 $ echo b > b
26 26 $ hg commit -Amb
27 27 adding b
28 28 created new head
29 29
30 30 clone, commit, pull
31 31 $ hg clone . ../blackboxtest2
32 32 updating to branch default
33 33 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
34 34 $ echo c > c
35 35 $ hg commit -Amc
36 36 adding c
37 37 $ cd ../blackboxtest2
38 38 $ hg pull
39 39 pulling from $TESTTMP/blackboxtest (glob)
40 40 searching for changes
41 41 adding changesets
42 42 adding manifests
43 43 adding file changes
44 44 added 1 changesets with 1 changes to 1 files
45 45 (run 'hg update' to get a working copy)
46 46 $ hg blackbox -l 5
47 47 1970/01/01 00:00:00 bob> pull
48 48 1970/01/01 00:00:00 bob> updated served branch cache in ?.???? seconds (glob)
49 49 1970/01/01 00:00:00 bob> wrote served branch cache with 1 labels and 2 nodes
50 50 1970/01/01 00:00:00 bob> 1 incoming changes - new heads: d02f48003e62
51 51 1970/01/01 00:00:00 bob> pull exited 0 after * seconds (glob)
52 52
53 53 we must not cause a failure if we cannot write to the log
54 54
55 55 $ hg rollback
56 56 repository tip rolled back to revision 1 (undo pull)
57 57
58 58 #if unix-permissions no-root
59 59 $ chmod 000 .hg/blackbox.log
60 60 $ hg --debug incoming
61 61 warning: cannot write to blackbox.log: Permission denied
62 62 comparing with $TESTTMP/blackboxtest (glob)
63 63 query 1; heads
64 64 searching for changes
65 65 all local heads known remotely
66 66 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
67 67 tag: tip
68 68 phase: draft
69 69 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
70 70 parent: -1:0000000000000000000000000000000000000000
71 71 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
72 72 user: test
73 73 date: Thu Jan 01 00:00:00 1970 +0000
74 74 files+: c
75 75 extra: branch=default
76 76 description:
77 77 c
78 78
79 79
80 80 #endif
81 81 $ hg pull
82 82 pulling from $TESTTMP/blackboxtest (glob)
83 83 searching for changes
84 84 adding changesets
85 85 adding manifests
86 86 adding file changes
87 87 added 1 changesets with 1 changes to 1 files
88 88 (run 'hg update' to get a working copy)
89 89
90 90 a failure reading from the log is fine
91 91 #if unix-permissions no-root
92 92 $ hg blackbox -l 3
93 93 abort: Permission denied: $TESTTMP/blackboxtest2/.hg/blackbox.log
94 94 [255]
95 95
96 96 $ chmod 600 .hg/blackbox.log
97 97 #endif
98 98
99 99 backup bundles get logged
100 100
101 101 $ touch d
102 102 $ hg commit -Amd
103 103 adding d
104 104 created new head
105 105 $ hg strip tip
106 106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 107 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
108 108 $ hg blackbox -l 5
109 109 1970/01/01 00:00:00 bob> strip tip
110 110 1970/01/01 00:00:00 bob> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
111 111 1970/01/01 00:00:00 bob> updated base branch cache in ?.???? seconds (glob)
112 112 1970/01/01 00:00:00 bob> wrote base branch cache with 1 labels and 2 nodes
113 113 1970/01/01 00:00:00 bob> strip tip exited 0 after * seconds (glob)
114 114
115 115 extension and python hooks - use the eol extension for a pythonhook
116 116
117 117 $ echo '[extensions]' >> .hg/hgrc
118 118 $ echo 'eol=' >> .hg/hgrc
119 119 $ echo '[hooks]' >> .hg/hgrc
120 120 $ echo 'update = echo hooked' >> .hg/hgrc
121 121 $ hg update
122 122 hooked
123 123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 124 $ hg blackbox -l 5
125 125 1970/01/01 00:00:00 bob> update
126 1970/01/01 00:00:00 bob> writing tags cache file with 0 tags
126 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 0 tags
127 127 1970/01/01 00:00:00 bob> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
128 128 1970/01/01 00:00:00 bob> exthook-update: echo hooked finished in * seconds (glob)
129 129 1970/01/01 00:00:00 bob> update exited 0 after * seconds (glob)
130 130
131 131 log rotation
132 132
133 133 $ echo '[blackbox]' >> .hg/hgrc
134 134 $ echo 'maxsize = 20 b' >> .hg/hgrc
135 135 $ echo 'maxfiles = 3' >> .hg/hgrc
136 136 $ hg status
137 137 $ hg status
138 138 $ hg status
139 139 $ hg tip -q
140 140 2:d02f48003e62
141 141 $ ls .hg/blackbox.log*
142 142 .hg/blackbox.log
143 143 .hg/blackbox.log.1
144 144 .hg/blackbox.log.2
145 145
146 146 cleanup
147 147 $ cd ..
@@ -1,1608 +1,1608
1 1 $ checkundo()
2 2 > {
3 3 > if [ -f .hg/store/undo ]; then
4 4 > echo ".hg/store/undo still exists after $1"
5 5 > fi
6 6 > }
7 7
8 8 $ cat <<EOF >> $HGRCPATH
9 9 > [extensions]
10 10 > mq =
11 11 > [mq]
12 12 > plain = true
13 13 > EOF
14 14
15 15
16 16 help
17 17
18 18 $ hg help mq
19 19 mq extension - manage a stack of patches
20 20
21 21 This extension lets you work with a stack of patches in a Mercurial
22 22 repository. It manages two stacks of patches - all known patches, and applied
23 23 patches (subset of known patches).
24 24
25 25 Known patches are represented as patch files in the .hg/patches directory.
26 26 Applied patches are both patch files and changesets.
27 27
28 28 Common tasks (use "hg help command" for more details):
29 29
30 30 create new patch qnew
31 31 import existing patch qimport
32 32
33 33 print patch series qseries
34 34 print applied patches qapplied
35 35
36 36 add known patch to applied stack qpush
37 37 remove patch from applied stack qpop
38 38 refresh contents of top applied patch qrefresh
39 39
40 40 By default, mq will automatically use git patches when required to avoid
41 41 losing file mode changes, copy records, binary files or empty files creations
42 42 or deletions. This behaviour can be configured with:
43 43
44 44 [mq]
45 45 git = auto/keep/yes/no
46 46
47 47 If set to 'keep', mq will obey the [diff] section configuration while
48 48 preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq
49 49 will override the [diff] section and always generate git or regular patches,
50 50 possibly losing data in the second case.
51 51
52 52 It may be desirable for mq changesets to be kept in the secret phase (see "hg
53 53 help phases"), which can be enabled with the following setting:
54 54
55 55 [mq]
56 56 secret = True
57 57
58 58 You will by default be managing a patch queue named "patches". You can create
59 59 other, independent patch queues with the "hg qqueue" command.
60 60
61 61 If the working directory contains uncommitted files, qpush, qpop and qgoto
62 62 abort immediately. If -f/--force is used, the changes are discarded. Setting:
63 63
64 64 [mq]
65 65 keepchanges = True
66 66
67 67 make them behave as if --keep-changes were passed, and non-conflicting local
68 68 changes will be tolerated and preserved. If incompatible options such as
69 69 -f/--force or --exact are passed, this setting is ignored.
70 70
71 71 This extension used to provide a strip command. This command now lives in the
72 72 strip extension.
73 73
74 74 list of commands:
75 75
76 76 qapplied print the patches already applied
77 77 qclone clone main and patch repository at same time
78 78 qdelete remove patches from queue
79 79 qdiff diff of the current patch and subsequent modifications
80 80 qfinish move applied patches into repository history
81 81 qfold fold the named patches into the current patch
82 82 qgoto push or pop patches until named patch is at top of stack
83 83 qguard set or print guards for a patch
84 84 qheader print the header of the topmost or specified patch
85 85 qimport import a patch or existing changeset
86 86 qnew create a new patch
87 87 qnext print the name of the next pushable patch
88 88 qpop pop the current patch off the stack
89 89 qprev print the name of the preceding applied patch
90 90 qpush push the next patch onto the stack
91 91 qqueue manage multiple patch queues
92 92 qrefresh update the current patch
93 93 qrename rename a patch
94 94 qselect set or print guarded patches to push
95 95 qseries print the entire series file
96 96 qtop print the name of the current patch
97 97 qunapplied print the patches not yet applied
98 98
99 99 (use "hg help -v mq" to show built-in aliases and global options)
100 100
101 101 $ hg init a
102 102 $ cd a
103 103 $ echo a > a
104 104 $ hg ci -Ama
105 105 adding a
106 106
107 107 $ hg clone . ../k
108 108 updating to branch default
109 109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 110
111 111 $ mkdir b
112 112 $ echo z > b/z
113 113 $ hg ci -Ama
114 114 adding b/z
115 115
116 116
117 117 qinit
118 118
119 119 $ hg qinit
120 120
121 121 $ cd ..
122 122 $ hg init b
123 123
124 124
125 125 -R qinit
126 126
127 127 $ hg -R b qinit
128 128
129 129 $ hg init c
130 130
131 131
132 132 qinit -c
133 133
134 134 $ hg --cwd c qinit -c
135 135 $ hg -R c/.hg/patches st
136 136 A .hgignore
137 137 A series
138 138
139 139
140 140 qinit; qinit -c
141 141
142 142 $ hg init d
143 143 $ cd d
144 144 $ hg qinit
145 145 $ hg qinit -c
146 146
147 147 qinit -c should create both files if they don't exist
148 148
149 149 $ cat .hg/patches/.hgignore
150 150 ^\.hg
151 151 ^\.mq
152 152 syntax: glob
153 153 status
154 154 guards
155 155 $ cat .hg/patches/series
156 156 $ hg qinit -c
157 157 abort: repository $TESTTMP/d/.hg/patches already exists! (glob)
158 158 [255]
159 159 $ cd ..
160 160
161 161 $ echo '% qinit; <stuff>; qinit -c'
162 162 % qinit; <stuff>; qinit -c
163 163 $ hg init e
164 164 $ cd e
165 165 $ hg qnew A
166 166 $ checkundo qnew
167 167 $ echo foo > foo
168 168 $ hg phase -r qbase
169 169 0: draft
170 170 $ hg add foo
171 171 $ hg qrefresh
172 172 $ hg phase -r qbase
173 173 0: draft
174 174 $ hg qnew B
175 175 $ echo >> foo
176 176 $ hg qrefresh
177 177 $ echo status >> .hg/patches/.hgignore
178 178 $ echo bleh >> .hg/patches/.hgignore
179 179 $ hg qinit -c
180 180 adding .hg/patches/A (glob)
181 181 adding .hg/patches/B (glob)
182 182 $ hg -R .hg/patches status
183 183 A .hgignore
184 184 A A
185 185 A B
186 186 A series
187 187
188 188 qinit -c shouldn't touch these files if they already exist
189 189
190 190 $ cat .hg/patches/.hgignore
191 191 status
192 192 bleh
193 193 $ cat .hg/patches/series
194 194 A
195 195 B
196 196
197 197 add an untracked file
198 198
199 199 $ echo >> .hg/patches/flaf
200 200
201 201 status --mq with color (issue2096)
202 202
203 203 $ hg status --mq --config extensions.color= --config color.mode=ansi --color=always
204 204 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1m.hgignore\x1b[0m (esc)
205 205 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mA\x1b[0m (esc)
206 206 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mB\x1b[0m (esc)
207 207 \x1b[0;32;1mA \x1b[0m\x1b[0;32;1mseries\x1b[0m (esc)
208 208 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mflaf\x1b[0m (esc)
209 209
210 210 try the --mq option on a command provided by an extension
211 211
212 212 $ hg purge --mq --verbose --config extensions.purge=
213 213 removing file flaf
214 214
215 215 $ cd ..
216 216
217 217 #if no-outer-repo
218 218
219 219 init --mq without repo
220 220
221 221 $ mkdir f
222 222 $ cd f
223 223 $ hg init --mq
224 224 abort: there is no Mercurial repository here (.hg not found)
225 225 [255]
226 226 $ cd ..
227 227
228 228 #endif
229 229
230 230 init --mq with repo path
231 231
232 232 $ hg init g
233 233 $ hg init --mq g
234 234 $ test -d g/.hg/patches/.hg
235 235
236 236 init --mq with nonexistent directory
237 237
238 238 $ hg init --mq nonexistentdir
239 239 abort: repository nonexistentdir not found!
240 240 [255]
241 241
242 242
243 243 init --mq with bundle (non "local")
244 244
245 245 $ hg -R a bundle --all a.bundle >/dev/null
246 246 $ hg init --mq a.bundle
247 247 abort: only a local queue repository may be initialized
248 248 [255]
249 249
250 250 $ cd a
251 251
252 252 $ hg qnew -m 'foo bar' test.patch
253 253
254 254 $ echo '# comment' > .hg/patches/series.tmp
255 255 $ echo >> .hg/patches/series.tmp # empty line
256 256 $ cat .hg/patches/series >> .hg/patches/series.tmp
257 257 $ mv .hg/patches/series.tmp .hg/patches/series
258 258
259 259
260 260 qrefresh
261 261
262 262 $ echo a >> a
263 263 $ hg qrefresh
264 264 $ cat .hg/patches/test.patch
265 265 foo bar
266 266
267 267 diff -r [a-f0-9]* a (re)
268 268 --- a/a\t(?P<date>.*) (re)
269 269 \+\+\+ b/a\t(?P<date2>.*) (re)
270 270 @@ -1,1 +1,2 @@
271 271 a
272 272 +a
273 273
274 274 empty qrefresh
275 275
276 276 $ hg qrefresh -X a
277 277
278 278 revision:
279 279
280 280 $ hg diff -r -2 -r -1
281 281
282 282 patch:
283 283
284 284 $ cat .hg/patches/test.patch
285 285 foo bar
286 286
287 287
288 288 working dir diff:
289 289
290 290 $ hg diff --nodates -q
291 291 --- a/a
292 292 +++ b/a
293 293 @@ -1,1 +1,2 @@
294 294 a
295 295 +a
296 296
297 297 restore things
298 298
299 299 $ hg qrefresh
300 300 $ checkundo qrefresh
301 301
302 302
303 303 qpop
304 304
305 305 $ hg qpop
306 306 popping test.patch
307 307 patch queue now empty
308 308 $ checkundo qpop
309 309
310 310
311 311 qpush with dump of tag cache
312 312 Dump the tag cache to ensure that it has exactly one head after qpush.
313 313
314 $ rm -f .hg/cache/tags-visible
314 $ rm -f .hg/cache/tags2-visible
315 315 $ hg tags > /dev/null
316 316
317 .hg/cache/tags-visible (pre qpush):
317 .hg/cache/tags2-visible (pre qpush):
318 318
319 $ cat .hg/cache/tags-visible
319 $ cat .hg/cache/tags2-visible
320 320 1 [\da-f]{40} (re)
321 321 $ hg qpush
322 322 applying test.patch
323 323 now at: test.patch
324 324 $ hg phase -r qbase
325 325 2: draft
326 326 $ hg tags > /dev/null
327 327
328 .hg/cache/tags-visible (post qpush):
328 .hg/cache/tags2-visible (post qpush):
329 329
330 $ cat .hg/cache/tags-visible
330 $ cat .hg/cache/tags2-visible
331 331 2 [\da-f]{40} (re)
332 332 $ checkundo qpush
333 333 $ cd ..
334 334
335 335
336 336 pop/push outside repo
337 337 $ hg -R a qpop
338 338 popping test.patch
339 339 patch queue now empty
340 340 $ hg -R a qpush
341 341 applying test.patch
342 342 now at: test.patch
343 343
344 344 $ cd a
345 345 $ hg qnew test2.patch
346 346
347 347 qrefresh in subdir
348 348
349 349 $ cd b
350 350 $ echo a > a
351 351 $ hg add a
352 352 $ hg qrefresh
353 353
354 354 pop/push -a in subdir
355 355
356 356 $ hg qpop -a
357 357 popping test2.patch
358 358 popping test.patch
359 359 patch queue now empty
360 360 $ hg --traceback qpush -a
361 361 applying test.patch
362 362 applying test2.patch
363 363 now at: test2.patch
364 364
365 365
366 366 setting columns & formatted tests truncating (issue1912)
367 367
368 368 $ COLUMNS=4 hg qseries --config ui.formatted=true
369 369 test.patch
370 370 test2.patch
371 371 $ COLUMNS=20 hg qseries --config ui.formatted=true -vs
372 372 0 A test.patch: f...
373 373 1 A test2.patch:
374 374 $ hg qpop
375 375 popping test2.patch
376 376 now at: test.patch
377 377 $ hg qseries -vs
378 378 0 A test.patch: foo bar
379 379 1 U test2.patch:
380 380 $ hg sum | grep mq
381 381 mq: 1 applied, 1 unapplied
382 382 $ hg qpush
383 383 applying test2.patch
384 384 now at: test2.patch
385 385 $ hg sum | grep mq
386 386 mq: 2 applied
387 387 $ hg qapplied
388 388 test.patch
389 389 test2.patch
390 390 $ hg qtop
391 391 test2.patch
392 392
393 393
394 394 prev
395 395
396 396 $ hg qapp -1
397 397 test.patch
398 398
399 399 next
400 400
401 401 $ hg qunapp -1
402 402 all patches applied
403 403 [1]
404 404
405 405 $ hg qpop
406 406 popping test2.patch
407 407 now at: test.patch
408 408
409 409 commit should fail
410 410
411 411 $ hg commit
412 412 abort: cannot commit over an applied mq patch
413 413 [255]
414 414
415 415 push should fail if draft
416 416
417 417 $ hg push ../../k
418 418 pushing to ../../k
419 419 abort: source has mq patches applied
420 420 [255]
421 421
422 422
423 423 import should fail
424 424
425 425 $ hg st .
426 426 $ echo foo >> ../a
427 427 $ hg diff > ../../import.diff
428 428 $ hg revert --no-backup ../a
429 429 $ hg import ../../import.diff
430 430 abort: cannot import over an applied patch
431 431 [255]
432 432 $ hg st
433 433
434 434 import --no-commit should succeed
435 435
436 436 $ hg import --no-commit ../../import.diff
437 437 applying ../../import.diff
438 438 $ hg st
439 439 M a
440 440 $ hg revert --no-backup ../a
441 441
442 442
443 443 qunapplied
444 444
445 445 $ hg qunapplied
446 446 test2.patch
447 447
448 448
449 449 qpush/qpop with index
450 450
451 451 $ hg qnew test1b.patch
452 452 $ echo 1b > 1b
453 453 $ hg add 1b
454 454 $ hg qrefresh
455 455 $ hg qpush 2
456 456 applying test2.patch
457 457 now at: test2.patch
458 458 $ hg qpop 0
459 459 popping test2.patch
460 460 popping test1b.patch
461 461 now at: test.patch
462 462 $ hg qpush test.patch+1
463 463 applying test1b.patch
464 464 now at: test1b.patch
465 465 $ hg qpush test.patch+2
466 466 applying test2.patch
467 467 now at: test2.patch
468 468 $ hg qpop test2.patch-1
469 469 popping test2.patch
470 470 now at: test1b.patch
471 471 $ hg qpop test2.patch-2
472 472 popping test1b.patch
473 473 now at: test.patch
474 474 $ hg qpush test1b.patch+1
475 475 applying test1b.patch
476 476 applying test2.patch
477 477 now at: test2.patch
478 478
479 479
480 480 qpush --move
481 481
482 482 $ hg qpop -a
483 483 popping test2.patch
484 484 popping test1b.patch
485 485 popping test.patch
486 486 patch queue now empty
487 487 $ hg qguard test1b.patch -- -negguard
488 488 $ hg qguard test2.patch -- +posguard
489 489 $ hg qpush --move test2.patch # can't move guarded patch
490 490 cannot push 'test2.patch' - guarded by '+posguard'
491 491 [1]
492 492 $ hg qselect posguard
493 493 number of unguarded, unapplied patches has changed from 2 to 3
494 494 $ hg qpush --move test2.patch # move to front
495 495 applying test2.patch
496 496 now at: test2.patch
497 497 $ hg qpush --move test1b.patch # negative guard unselected
498 498 applying test1b.patch
499 499 now at: test1b.patch
500 500 $ hg qpush --move test.patch # noop move
501 501 applying test.patch
502 502 now at: test.patch
503 503 $ hg qseries -v
504 504 0 A test2.patch
505 505 1 A test1b.patch
506 506 2 A test.patch
507 507 $ hg qpop -a
508 508 popping test.patch
509 509 popping test1b.patch
510 510 popping test2.patch
511 511 patch queue now empty
512 512
513 513 cleaning up
514 514
515 515 $ hg qselect --none
516 516 guards deactivated
517 517 number of unguarded, unapplied patches has changed from 3 to 2
518 518 $ hg qguard --none test1b.patch
519 519 $ hg qguard --none test2.patch
520 520 $ hg qpush --move test.patch
521 521 applying test.patch
522 522 now at: test.patch
523 523 $ hg qpush --move test1b.patch
524 524 applying test1b.patch
525 525 now at: test1b.patch
526 526 $ hg qpush --move bogus # nonexistent patch
527 527 abort: patch bogus not in series
528 528 [255]
529 529 $ hg qpush --move # no patch
530 530 abort: please specify the patch to move
531 531 [255]
532 532 $ hg qpush --move test.patch # already applied
533 533 abort: cannot push to a previous patch: test.patch
534 534 [255]
535 535 $ sed '2i\
536 536 > # make qtip index different in series and fullseries
537 537 > ' `hg root`/.hg/patches/series > $TESTTMP/sedtmp
538 538 $ cp $TESTTMP/sedtmp `hg root`/.hg/patches/series
539 539 $ cat `hg root`/.hg/patches/series
540 540 # comment
541 541 # make qtip index different in series and fullseries
542 542
543 543 test.patch
544 544 test1b.patch
545 545 test2.patch
546 546 $ hg qpush --move test2.patch
547 547 applying test2.patch
548 548 now at: test2.patch
549 549
550 550
551 551 series after move
552 552
553 553 $ cat `hg root`/.hg/patches/series
554 554 # comment
555 555 # make qtip index different in series and fullseries
556 556
557 557 test.patch
558 558 test1b.patch
559 559 test2.patch
560 560
561 561
562 562 pop, qapplied, qunapplied
563 563
564 564 $ hg qseries -v
565 565 0 A test.patch
566 566 1 A test1b.patch
567 567 2 A test2.patch
568 568
569 569 qapplied -1 test.patch
570 570
571 571 $ hg qapplied -1 test.patch
572 572 only one patch applied
573 573 [1]
574 574
575 575 qapplied -1 test1b.patch
576 576
577 577 $ hg qapplied -1 test1b.patch
578 578 test.patch
579 579
580 580 qapplied -1 test2.patch
581 581
582 582 $ hg qapplied -1 test2.patch
583 583 test1b.patch
584 584
585 585 qapplied -1
586 586
587 587 $ hg qapplied -1
588 588 test1b.patch
589 589
590 590 qapplied
591 591
592 592 $ hg qapplied
593 593 test.patch
594 594 test1b.patch
595 595 test2.patch
596 596
597 597 qapplied test1b.patch
598 598
599 599 $ hg qapplied test1b.patch
600 600 test.patch
601 601 test1b.patch
602 602
603 603 qunapplied -1
604 604
605 605 $ hg qunapplied -1
606 606 all patches applied
607 607 [1]
608 608
609 609 qunapplied
610 610
611 611 $ hg qunapplied
612 612
613 613 popping
614 614
615 615 $ hg qpop
616 616 popping test2.patch
617 617 now at: test1b.patch
618 618
619 619 qunapplied -1
620 620
621 621 $ hg qunapplied -1
622 622 test2.patch
623 623
624 624 qunapplied
625 625
626 626 $ hg qunapplied
627 627 test2.patch
628 628
629 629 qunapplied test2.patch
630 630
631 631 $ hg qunapplied test2.patch
632 632
633 633 qunapplied -1 test2.patch
634 634
635 635 $ hg qunapplied -1 test2.patch
636 636 all patches applied
637 637 [1]
638 638
639 639 popping -a
640 640
641 641 $ hg qpop -a
642 642 popping test1b.patch
643 643 popping test.patch
644 644 patch queue now empty
645 645
646 646 qapplied
647 647
648 648 $ hg qapplied
649 649
650 650 qapplied -1
651 651
652 652 $ hg qapplied -1
653 653 no patches applied
654 654 [1]
655 655 $ hg qpush
656 656 applying test.patch
657 657 now at: test.patch
658 658
659 659
660 660 push should succeed
661 661
662 662 $ hg qpop -a
663 663 popping test.patch
664 664 patch queue now empty
665 665 $ hg push ../../k
666 666 pushing to ../../k
667 667 searching for changes
668 668 adding changesets
669 669 adding manifests
670 670 adding file changes
671 671 added 1 changesets with 1 changes to 1 files
672 672
673 673
674 674 we want to start with some patches applied
675 675
676 676 $ hg qpush -a
677 677 applying test.patch
678 678 applying test1b.patch
679 679 applying test2.patch
680 680 now at: test2.patch
681 681
682 682 % pops all patches and succeeds
683 683
684 684 $ hg qpop -a
685 685 popping test2.patch
686 686 popping test1b.patch
687 687 popping test.patch
688 688 patch queue now empty
689 689
690 690 % does nothing and succeeds
691 691
692 692 $ hg qpop -a
693 693 no patches applied
694 694
695 695 % fails - nothing else to pop
696 696
697 697 $ hg qpop
698 698 no patches applied
699 699 [1]
700 700
701 701 % pushes a patch and succeeds
702 702
703 703 $ hg qpush
704 704 applying test.patch
705 705 now at: test.patch
706 706
707 707 % pops a patch and succeeds
708 708
709 709 $ hg qpop
710 710 popping test.patch
711 711 patch queue now empty
712 712
713 713 % pushes up to test1b.patch and succeeds
714 714
715 715 $ hg qpush test1b.patch
716 716 applying test.patch
717 717 applying test1b.patch
718 718 now at: test1b.patch
719 719
720 720 % does nothing and succeeds
721 721
722 722 $ hg qpush test1b.patch
723 723 qpush: test1b.patch is already at the top
724 724
725 725 % does nothing and succeeds
726 726
727 727 $ hg qpop test1b.patch
728 728 qpop: test1b.patch is already at the top
729 729
730 730 % fails - can't push to this patch
731 731
732 732 $ hg qpush test.patch
733 733 abort: cannot push to a previous patch: test.patch
734 734 [255]
735 735
736 736 % fails - can't pop to this patch
737 737
738 738 $ hg qpop test2.patch
739 739 abort: patch test2.patch is not applied
740 740 [255]
741 741
742 742 % pops up to test.patch and succeeds
743 743
744 744 $ hg qpop test.patch
745 745 popping test1b.patch
746 746 now at: test.patch
747 747
748 748 % pushes all patches and succeeds
749 749
750 750 $ hg qpush -a
751 751 applying test1b.patch
752 752 applying test2.patch
753 753 now at: test2.patch
754 754
755 755 % does nothing and succeeds
756 756
757 757 $ hg qpush -a
758 758 all patches are currently applied
759 759
760 760 % fails - nothing else to push
761 761
762 762 $ hg qpush
763 763 patch series already fully applied
764 764 [1]
765 765
766 766 % does nothing and succeeds
767 767
768 768 $ hg qpush test2.patch
769 769 qpush: test2.patch is already at the top
770 770
771 771 strip
772 772
773 773 $ cd ../../b
774 774 $ echo x>x
775 775 $ hg ci -Ama
776 776 adding x
777 777 $ hg strip tip
778 778 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
779 779 saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
780 780 $ hg unbundle .hg/strip-backup/*
781 781 adding changesets
782 782 adding manifests
783 783 adding file changes
784 784 added 1 changesets with 1 changes to 1 files
785 785 (run 'hg update' to get a working copy)
786 786
787 787
788 788 strip with local changes, should complain
789 789
790 790 $ hg up
791 791 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
792 792 $ echo y>y
793 793 $ hg add y
794 794 $ hg strip tip
795 795 abort: local changes found
796 796 [255]
797 797
798 798 --force strip with local changes
799 799
800 800 $ hg strip -f tip
801 801 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
802 802 saved backup bundle to $TESTTMP/b/.hg/strip-backup/770eb8fce608-0ddcae0f-backup.hg (glob)
803 803 $ cd ..
804 804
805 805
806 806 cd b; hg qrefresh
807 807
808 808 $ hg init refresh
809 809 $ cd refresh
810 810 $ echo a > a
811 811 $ hg ci -Ama
812 812 adding a
813 813 $ hg qnew -mfoo foo
814 814 $ echo a >> a
815 815 $ hg qrefresh
816 816 $ mkdir b
817 817 $ cd b
818 818 $ echo f > f
819 819 $ hg add f
820 820 $ hg qrefresh
821 821 $ cat ../.hg/patches/foo
822 822 foo
823 823
824 824 diff -r cb9a9f314b8b a
825 825 --- a/a\t(?P<date>.*) (re)
826 826 \+\+\+ b/a\t(?P<date>.*) (re)
827 827 @@ -1,1 +1,2 @@
828 828 a
829 829 +a
830 830 diff -r cb9a9f314b8b b/f
831 831 --- /dev/null\t(?P<date>.*) (re)
832 832 \+\+\+ b/b/f\t(?P<date>.*) (re)
833 833 @@ -0,0 +1,1 @@
834 834 +f
835 835
836 836 hg qrefresh .
837 837
838 838 $ hg qrefresh .
839 839 $ cat ../.hg/patches/foo
840 840 foo
841 841
842 842 diff -r cb9a9f314b8b b/f
843 843 --- /dev/null\t(?P<date>.*) (re)
844 844 \+\+\+ b/b/f\t(?P<date>.*) (re)
845 845 @@ -0,0 +1,1 @@
846 846 +f
847 847 $ hg status
848 848 M a
849 849
850 850
851 851 qpush failure
852 852
853 853 $ cd ..
854 854 $ hg qrefresh
855 855 $ hg qnew -mbar bar
856 856 $ echo foo > foo
857 857 $ echo bar > bar
858 858 $ hg add foo bar
859 859 $ hg qrefresh
860 860 $ hg qpop -a
861 861 popping bar
862 862 popping foo
863 863 patch queue now empty
864 864 $ echo bar > foo
865 865 $ hg qpush -a
866 866 applying foo
867 867 applying bar
868 868 file foo already exists
869 869 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
870 870 patch failed, unable to continue (try -v)
871 871 patch failed, rejects left in working directory
872 872 errors during apply, please fix and refresh bar
873 873 [2]
874 874 $ hg st
875 875 ? foo
876 876 ? foo.rej
877 877
878 878
879 879 mq tags
880 880
881 881 $ hg log --template '{rev} {tags}\n' -r qparent:qtip
882 882 0 qparent
883 883 1 foo qbase
884 884 2 bar qtip tip
885 885
886 886 mq revset
887 887
888 888 $ hg log -r 'mq()' --template '{rev}\n'
889 889 1
890 890 2
891 891 $ hg help revsets | grep -i mq
892 892 "mq()"
893 893 Changesets managed by MQ.
894 894
895 895 bad node in status
896 896
897 897 $ hg qpop
898 898 popping bar
899 899 now at: foo
900 900 $ hg strip -qn tip
901 901 $ hg tip
902 902 changeset: 0:cb9a9f314b8b
903 903 tag: tip
904 904 user: test
905 905 date: Thu Jan 01 00:00:00 1970 +0000
906 906 summary: a
907 907
908 908 $ hg branches
909 909 default 0:cb9a9f314b8b
910 910 $ hg qpop
911 911 no patches applied
912 912 [1]
913 913
914 914 $ cd ..
915 915
916 916
917 917 git patches
918 918
919 919 $ cat >>$HGRCPATH <<EOF
920 920 > [diff]
921 921 > git = True
922 922 > EOF
923 923 $ hg init git
924 924 $ cd git
925 925 $ hg qinit
926 926
927 927 $ hg qnew -m'new file' new
928 928 $ echo foo > new
929 929 #if execbit
930 930 $ chmod +x new
931 931 #endif
932 932 $ hg add new
933 933 $ hg qrefresh
934 934 #if execbit
935 935 $ cat .hg/patches/new
936 936 new file
937 937
938 938 diff --git a/new b/new
939 939 new file mode 100755
940 940 --- /dev/null
941 941 +++ b/new
942 942 @@ -0,0 +1,1 @@
943 943 +foo
944 944 #else
945 945 $ cat .hg/patches/new
946 946 new file
947 947
948 948 diff --git a/new b/new
949 949 new file mode 100644
950 950 --- /dev/null
951 951 +++ b/new
952 952 @@ -0,0 +1,1 @@
953 953 +foo
954 954 #endif
955 955
956 956 $ hg qnew -m'copy file' copy
957 957 $ hg cp new copy
958 958 $ hg qrefresh
959 959 $ cat .hg/patches/copy
960 960 copy file
961 961
962 962 diff --git a/new b/copy
963 963 copy from new
964 964 copy to copy
965 965
966 966 $ hg qpop
967 967 popping copy
968 968 now at: new
969 969 $ hg qpush
970 970 applying copy
971 971 now at: copy
972 972 $ hg qdiff
973 973 diff --git a/new b/copy
974 974 copy from new
975 975 copy to copy
976 976 $ cat >>$HGRCPATH <<EOF
977 977 > [diff]
978 978 > git = False
979 979 > EOF
980 980 $ hg qdiff --git
981 981 diff --git a/new b/copy
982 982 copy from new
983 983 copy to copy
984 984 $ cd ..
985 985
986 986 empty lines in status
987 987
988 988 $ hg init emptystatus
989 989 $ cd emptystatus
990 990 $ hg qinit
991 991 $ printf '\n\n' > .hg/patches/status
992 992 $ hg qser
993 993 $ cd ..
994 994
995 995 bad line in status (without ":")
996 996
997 997 $ hg init badstatus
998 998 $ cd badstatus
999 999 $ hg qinit
1000 1000 $ printf 'babar has no colon in this line\n' > .hg/patches/status
1001 1001 $ hg qser
1002 1002 malformated mq status line: ['babar has no colon in this line']
1003 1003 $ cd ..
1004 1004
1005 1005
1006 1006 test file addition in slow path
1007 1007
1008 1008 $ hg init slow
1009 1009 $ cd slow
1010 1010 $ hg qinit
1011 1011 $ echo foo > foo
1012 1012 $ hg add foo
1013 1013 $ hg ci -m 'add foo'
1014 1014 $ hg qnew bar
1015 1015 $ echo bar > bar
1016 1016 $ hg add bar
1017 1017 $ hg mv foo baz
1018 1018 $ hg qrefresh --git
1019 1019 $ hg up -C 0
1020 1020 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1021 1021 $ echo >> foo
1022 1022 $ hg ci -m 'change foo'
1023 1023 created new head
1024 1024 $ hg up -C 1
1025 1025 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1026 1026 $ hg qrefresh --git
1027 1027 $ cat .hg/patches/bar
1028 1028 diff --git a/bar b/bar
1029 1029 new file mode 100644
1030 1030 --- /dev/null
1031 1031 +++ b/bar
1032 1032 @@ -0,0 +1,1 @@
1033 1033 +bar
1034 1034 diff --git a/foo b/baz
1035 1035 rename from foo
1036 1036 rename to baz
1037 1037 $ hg log -v --template '{rev} {file_copies}\n' -r .
1038 1038 2 baz (foo)
1039 1039 $ hg qrefresh --git
1040 1040 $ cat .hg/patches/bar
1041 1041 diff --git a/bar b/bar
1042 1042 new file mode 100644
1043 1043 --- /dev/null
1044 1044 +++ b/bar
1045 1045 @@ -0,0 +1,1 @@
1046 1046 +bar
1047 1047 diff --git a/foo b/baz
1048 1048 rename from foo
1049 1049 rename to baz
1050 1050 $ hg log -v --template '{rev} {file_copies}\n' -r .
1051 1051 2 baz (foo)
1052 1052 $ hg qrefresh
1053 1053 $ grep 'diff --git' .hg/patches/bar
1054 1054 diff --git a/bar b/bar
1055 1055 diff --git a/foo b/baz
1056 1056
1057 1057
1058 1058 test file move chains in the slow path
1059 1059
1060 1060 $ hg up -C 1
1061 1061 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1062 1062 $ echo >> foo
1063 1063 $ hg ci -m 'change foo again'
1064 1064 $ hg up -C 2
1065 1065 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1066 1066 $ hg mv bar quux
1067 1067 $ hg mv baz bleh
1068 1068 $ hg qrefresh --git
1069 1069 $ cat .hg/patches/bar
1070 1070 diff --git a/foo b/bleh
1071 1071 rename from foo
1072 1072 rename to bleh
1073 1073 diff --git a/quux b/quux
1074 1074 new file mode 100644
1075 1075 --- /dev/null
1076 1076 +++ b/quux
1077 1077 @@ -0,0 +1,1 @@
1078 1078 +bar
1079 1079 $ hg log -v --template '{rev} {file_copies}\n' -r .
1080 1080 3 bleh (foo)
1081 1081 $ hg mv quux fred
1082 1082 $ hg mv bleh barney
1083 1083 $ hg qrefresh --git
1084 1084 $ cat .hg/patches/bar
1085 1085 diff --git a/foo b/barney
1086 1086 rename from foo
1087 1087 rename to barney
1088 1088 diff --git a/fred b/fred
1089 1089 new file mode 100644
1090 1090 --- /dev/null
1091 1091 +++ b/fred
1092 1092 @@ -0,0 +1,1 @@
1093 1093 +bar
1094 1094 $ hg log -v --template '{rev} {file_copies}\n' -r .
1095 1095 3 barney (foo)
1096 1096
1097 1097
1098 1098 refresh omitting an added file
1099 1099
1100 1100 $ hg qnew baz
1101 1101 $ echo newfile > newfile
1102 1102 $ hg add newfile
1103 1103 $ hg qrefresh
1104 1104 $ hg st -A newfile
1105 1105 C newfile
1106 1106 $ hg qrefresh -X newfile
1107 1107 $ hg st -A newfile
1108 1108 A newfile
1109 1109 $ hg revert newfile
1110 1110 $ rm newfile
1111 1111 $ hg qpop
1112 1112 popping baz
1113 1113 now at: bar
1114 1114
1115 1115 test qdel/qrm
1116 1116
1117 1117 $ hg qdel baz
1118 1118 $ echo p >> .hg/patches/series
1119 1119 $ hg qrm p
1120 1120 $ hg qser
1121 1121 bar
1122 1122
1123 1123 create a git patch
1124 1124
1125 1125 $ echo a > alexander
1126 1126 $ hg add alexander
1127 1127 $ hg qnew -f --git addalexander
1128 1128 $ grep diff .hg/patches/addalexander
1129 1129 diff --git a/alexander b/alexander
1130 1130
1131 1131
1132 1132 create a git binary patch
1133 1133
1134 1134 $ cat > writebin.py <<EOF
1135 1135 > import sys
1136 1136 > path = sys.argv[1]
1137 1137 > open(path, 'wb').write('BIN\x00ARY')
1138 1138 > EOF
1139 1139 $ python writebin.py bucephalus
1140 1140
1141 1141 $ python "$TESTDIR/md5sum.py" bucephalus
1142 1142 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1143 1143 $ hg add bucephalus
1144 1144 $ hg qnew -f --git addbucephalus
1145 1145 $ grep diff .hg/patches/addbucephalus
1146 1146 diff --git a/bucephalus b/bucephalus
1147 1147
1148 1148
1149 1149 check binary patches can be popped and pushed
1150 1150
1151 1151 $ hg qpop
1152 1152 popping addbucephalus
1153 1153 now at: addalexander
1154 1154 $ test -f bucephalus && echo % bucephalus should not be there
1155 1155 [1]
1156 1156 $ hg qpush
1157 1157 applying addbucephalus
1158 1158 now at: addbucephalus
1159 1159 $ test -f bucephalus
1160 1160 $ python "$TESTDIR/md5sum.py" bucephalus
1161 1161 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
1162 1162
1163 1163
1164 1164
1165 1165 strip again
1166 1166
1167 1167 $ cd ..
1168 1168 $ hg init strip
1169 1169 $ cd strip
1170 1170 $ touch foo
1171 1171 $ hg add foo
1172 1172 $ hg ci -m 'add foo'
1173 1173 $ echo >> foo
1174 1174 $ hg ci -m 'change foo 1'
1175 1175 $ hg up -C 0
1176 1176 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1177 1177 $ echo 1 >> foo
1178 1178 $ hg ci -m 'change foo 2'
1179 1179 created new head
1180 1180 $ HGMERGE=true hg merge
1181 1181 merging foo
1182 1182 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
1183 1183 (branch merge, don't forget to commit)
1184 1184 $ hg ci -m merge
1185 1185 $ hg log
1186 1186 changeset: 3:99615015637b
1187 1187 tag: tip
1188 1188 parent: 2:20cbbe65cff7
1189 1189 parent: 1:d2871fc282d4
1190 1190 user: test
1191 1191 date: Thu Jan 01 00:00:00 1970 +0000
1192 1192 summary: merge
1193 1193
1194 1194 changeset: 2:20cbbe65cff7
1195 1195 parent: 0:53245c60e682
1196 1196 user: test
1197 1197 date: Thu Jan 01 00:00:00 1970 +0000
1198 1198 summary: change foo 2
1199 1199
1200 1200 changeset: 1:d2871fc282d4
1201 1201 user: test
1202 1202 date: Thu Jan 01 00:00:00 1970 +0000
1203 1203 summary: change foo 1
1204 1204
1205 1205 changeset: 0:53245c60e682
1206 1206 user: test
1207 1207 date: Thu Jan 01 00:00:00 1970 +0000
1208 1208 summary: add foo
1209 1209
1210 1210 $ hg strip 1
1211 1211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1212 1212 saved backup bundle to $TESTTMP/strip/.hg/strip-backup/*-backup.hg (glob)
1213 1213 $ checkundo strip
1214 1214 $ hg log
1215 1215 changeset: 1:20cbbe65cff7
1216 1216 tag: tip
1217 1217 user: test
1218 1218 date: Thu Jan 01 00:00:00 1970 +0000
1219 1219 summary: change foo 2
1220 1220
1221 1221 changeset: 0:53245c60e682
1222 1222 user: test
1223 1223 date: Thu Jan 01 00:00:00 1970 +0000
1224 1224 summary: add foo
1225 1225
1226 1226 $ cd ..
1227 1227
1228 1228
1229 1229 qclone
1230 1230
1231 1231 $ qlog()
1232 1232 > {
1233 1233 > echo 'main repo:'
1234 1234 > hg log --template ' rev {rev}: {desc}\n'
1235 1235 > echo 'patch repo:'
1236 1236 > hg -R .hg/patches log --template ' rev {rev}: {desc}\n'
1237 1237 > }
1238 1238 $ hg init qclonesource
1239 1239 $ cd qclonesource
1240 1240 $ echo foo > foo
1241 1241 $ hg add foo
1242 1242 $ hg ci -m 'add foo'
1243 1243 $ hg qinit
1244 1244 $ hg qnew patch1
1245 1245 $ echo bar >> foo
1246 1246 $ hg qrefresh -m 'change foo'
1247 1247 $ cd ..
1248 1248
1249 1249
1250 1250 repo with unversioned patch dir
1251 1251
1252 1252 $ hg qclone qclonesource failure
1253 1253 abort: versioned patch repository not found (see init --mq)
1254 1254 [255]
1255 1255
1256 1256 $ cd qclonesource
1257 1257 $ hg qinit -c
1258 1258 adding .hg/patches/patch1 (glob)
1259 1259 $ hg qci -m checkpoint
1260 1260 $ qlog
1261 1261 main repo:
1262 1262 rev 1: change foo
1263 1263 rev 0: add foo
1264 1264 patch repo:
1265 1265 rev 0: checkpoint
1266 1266 $ cd ..
1267 1267
1268 1268
1269 1269 repo with patches applied
1270 1270
1271 1271 $ hg qclone qclonesource qclonedest
1272 1272 updating to branch default
1273 1273 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1274 1274 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1275 1275 $ cd qclonedest
1276 1276 $ qlog
1277 1277 main repo:
1278 1278 rev 0: add foo
1279 1279 patch repo:
1280 1280 rev 0: checkpoint
1281 1281 $ cd ..
1282 1282
1283 1283
1284 1284 repo with patches unapplied
1285 1285
1286 1286 $ cd qclonesource
1287 1287 $ hg qpop -a
1288 1288 popping patch1
1289 1289 patch queue now empty
1290 1290 $ qlog
1291 1291 main repo:
1292 1292 rev 0: add foo
1293 1293 patch repo:
1294 1294 rev 0: checkpoint
1295 1295 $ cd ..
1296 1296 $ hg qclone qclonesource qclonedest2
1297 1297 updating to branch default
1298 1298 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1299 1299 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1300 1300 $ cd qclonedest2
1301 1301 $ qlog
1302 1302 main repo:
1303 1303 rev 0: add foo
1304 1304 patch repo:
1305 1305 rev 0: checkpoint
1306 1306 $ cd ..
1307 1307
1308 1308
1309 1309 Issue1033: test applying on an empty file
1310 1310
1311 1311 $ hg init empty
1312 1312 $ cd empty
1313 1313 $ touch a
1314 1314 $ hg ci -Am addempty
1315 1315 adding a
1316 1316 $ echo a > a
1317 1317 $ hg qnew -f -e changea
1318 1318 $ hg qpop
1319 1319 popping changea
1320 1320 patch queue now empty
1321 1321 $ hg qpush
1322 1322 applying changea
1323 1323 now at: changea
1324 1324 $ cd ..
1325 1325
1326 1326 test qpush with --force, issue1087
1327 1327
1328 1328 $ hg init forcepush
1329 1329 $ cd forcepush
1330 1330 $ echo hello > hello.txt
1331 1331 $ echo bye > bye.txt
1332 1332 $ hg ci -Ama
1333 1333 adding bye.txt
1334 1334 adding hello.txt
1335 1335 $ hg qnew -d '0 0' empty
1336 1336 $ hg qpop
1337 1337 popping empty
1338 1338 patch queue now empty
1339 1339 $ echo world >> hello.txt
1340 1340
1341 1341
1342 1342 qpush should fail, local changes
1343 1343
1344 1344 $ hg qpush
1345 1345 abort: local changes found
1346 1346 [255]
1347 1347
1348 1348
1349 1349 apply force, should not discard changes with empty patch
1350 1350
1351 1351 $ hg qpush -f
1352 1352 applying empty
1353 1353 patch empty is empty
1354 1354 now at: empty
1355 1355 $ hg diff --config diff.nodates=True
1356 1356 diff -r d58265112590 hello.txt
1357 1357 --- a/hello.txt
1358 1358 +++ b/hello.txt
1359 1359 @@ -1,1 +1,2 @@
1360 1360 hello
1361 1361 +world
1362 1362 $ hg qdiff --config diff.nodates=True
1363 1363 diff -r 9ecee4f634e3 hello.txt
1364 1364 --- a/hello.txt
1365 1365 +++ b/hello.txt
1366 1366 @@ -1,1 +1,2 @@
1367 1367 hello
1368 1368 +world
1369 1369 $ hg log -l1 -p
1370 1370 changeset: 1:d58265112590
1371 1371 tag: empty
1372 1372 tag: qbase
1373 1373 tag: qtip
1374 1374 tag: tip
1375 1375 user: test
1376 1376 date: Thu Jan 01 00:00:00 1970 +0000
1377 1377 summary: imported patch empty
1378 1378
1379 1379
1380 1380 $ hg qref -d '0 0'
1381 1381 $ hg qpop
1382 1382 popping empty
1383 1383 patch queue now empty
1384 1384 $ echo universe >> hello.txt
1385 1385 $ echo universe >> bye.txt
1386 1386
1387 1387
1388 1388 qpush should fail, local changes
1389 1389
1390 1390 $ hg qpush
1391 1391 abort: local changes found
1392 1392 [255]
1393 1393
1394 1394
1395 1395 apply force, should discard changes in hello, but not bye
1396 1396
1397 1397 $ hg qpush -f --verbose
1398 1398 applying empty
1399 1399 saving current version of hello.txt as hello.txt.orig
1400 1400 patching file hello.txt
1401 1401 committing files:
1402 1402 hello.txt
1403 1403 committing manifest
1404 1404 committing changelog
1405 1405 now at: empty
1406 1406 $ hg st
1407 1407 M bye.txt
1408 1408 ? hello.txt.orig
1409 1409 $ hg diff --config diff.nodates=True
1410 1410 diff -r ba252371dbc1 bye.txt
1411 1411 --- a/bye.txt
1412 1412 +++ b/bye.txt
1413 1413 @@ -1,1 +1,2 @@
1414 1414 bye
1415 1415 +universe
1416 1416 $ hg qdiff --config diff.nodates=True
1417 1417 diff -r 9ecee4f634e3 bye.txt
1418 1418 --- a/bye.txt
1419 1419 +++ b/bye.txt
1420 1420 @@ -1,1 +1,2 @@
1421 1421 bye
1422 1422 +universe
1423 1423 diff -r 9ecee4f634e3 hello.txt
1424 1424 --- a/hello.txt
1425 1425 +++ b/hello.txt
1426 1426 @@ -1,1 +1,3 @@
1427 1427 hello
1428 1428 +world
1429 1429 +universe
1430 1430
1431 1431
1432 1432 test popping revisions not in working dir ancestry
1433 1433
1434 1434 $ hg qseries -v
1435 1435 0 A empty
1436 1436 $ hg up qparent
1437 1437 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1438 1438 $ hg qpop
1439 1439 popping empty
1440 1440 patch queue now empty
1441 1441
1442 1442 $ cd ..
1443 1443 $ hg init deletion-order
1444 1444 $ cd deletion-order
1445 1445
1446 1446 $ touch a
1447 1447 $ hg ci -Aqm0
1448 1448
1449 1449 $ hg qnew rename-dir
1450 1450 $ hg rm a
1451 1451 $ hg qrefresh
1452 1452
1453 1453 $ mkdir a b
1454 1454 $ touch a/a b/b
1455 1455 $ hg add -q a b
1456 1456 $ hg qrefresh
1457 1457
1458 1458
1459 1459 test popping must remove files added in subdirectories first
1460 1460
1461 1461 $ hg qpop
1462 1462 popping rename-dir
1463 1463 patch queue now empty
1464 1464 $ cd ..
1465 1465
1466 1466
1467 1467 test case preservation through patch pushing especially on case
1468 1468 insensitive filesystem
1469 1469
1470 1470 $ hg init casepreserve
1471 1471 $ cd casepreserve
1472 1472
1473 1473 $ hg qnew add-file1
1474 1474 $ echo a > TeXtFiLe.TxT
1475 1475 $ hg add TeXtFiLe.TxT
1476 1476 $ hg qrefresh
1477 1477
1478 1478 $ hg qnew add-file2
1479 1479 $ echo b > AnOtHeRFiLe.TxT
1480 1480 $ hg add AnOtHeRFiLe.TxT
1481 1481 $ hg qrefresh
1482 1482
1483 1483 $ hg qnew modify-file
1484 1484 $ echo c >> AnOtHeRFiLe.TxT
1485 1485 $ hg qrefresh
1486 1486
1487 1487 $ hg qapplied
1488 1488 add-file1
1489 1489 add-file2
1490 1490 modify-file
1491 1491 $ hg qpop -a
1492 1492 popping modify-file
1493 1493 popping add-file2
1494 1494 popping add-file1
1495 1495 patch queue now empty
1496 1496
1497 1497 this qpush causes problems below, if case preservation on case
1498 1498 insensitive filesystem is not enough:
1499 1499 (1) unexpected "adding ..." messages are shown
1500 1500 (2) patching fails in modification of (1) files
1501 1501
1502 1502 $ hg qpush -a
1503 1503 applying add-file1
1504 1504 applying add-file2
1505 1505 applying modify-file
1506 1506 now at: modify-file
1507 1507
1508 1508 Proper phase default with mq:
1509 1509
1510 1510 1. mq.secret=false
1511 1511
1512 1512 $ rm .hg/store/phaseroots
1513 1513 $ hg phase 'qparent::'
1514 1514 -1: public
1515 1515 0: draft
1516 1516 1: draft
1517 1517 2: draft
1518 1518 $ echo '[mq]' >> $HGRCPATH
1519 1519 $ echo 'secret=true' >> $HGRCPATH
1520 1520 $ rm -f .hg/store/phaseroots
1521 1521 $ hg phase 'qparent::'
1522 1522 -1: public
1523 1523 0: secret
1524 1524 1: secret
1525 1525 2: secret
1526 1526
1527 1527 Test that qfinish change phase when mq.secret=true
1528 1528
1529 1529 $ hg qfinish qbase
1530 1530 patch add-file1 finalized without changeset message
1531 1531 $ hg phase 'all()'
1532 1532 0: draft
1533 1533 1: secret
1534 1534 2: secret
1535 1535
1536 1536 Test that qfinish respect phases.new-commit setting
1537 1537
1538 1538 $ echo '[phases]' >> $HGRCPATH
1539 1539 $ echo 'new-commit=secret' >> $HGRCPATH
1540 1540 $ hg qfinish qbase
1541 1541 patch add-file2 finalized without changeset message
1542 1542 $ hg phase 'all()'
1543 1543 0: draft
1544 1544 1: secret
1545 1545 2: secret
1546 1546
1547 1547 (restore env for next test)
1548 1548
1549 1549 $ sed -e 's/new-commit=secret//' $HGRCPATH > $TESTTMP/sedtmp
1550 1550 $ cp $TESTTMP/sedtmp $HGRCPATH
1551 1551 $ hg qimport -r 1 --name add-file2
1552 1552
1553 1553 Test that qfinish preserve phase when mq.secret=false
1554 1554
1555 1555 $ sed -e 's/secret=true/secret=false/' $HGRCPATH > $TESTTMP/sedtmp
1556 1556 $ cp $TESTTMP/sedtmp $HGRCPATH
1557 1557 $ hg qfinish qbase
1558 1558 patch add-file2 finalized without changeset message
1559 1559 $ hg phase 'all()'
1560 1560 0: draft
1561 1561 1: secret
1562 1562 2: secret
1563 1563
1564 1564 Test that secret mq patch does not break hgweb
1565 1565
1566 1566 $ cat > hgweb.cgi <<HGWEB
1567 1567 > from mercurial import demandimport; demandimport.enable()
1568 1568 > from mercurial.hgweb import hgweb
1569 1569 > from mercurial.hgweb import wsgicgi
1570 1570 > import cgitb
1571 1571 > cgitb.enable()
1572 1572 > app = hgweb('.', 'test')
1573 1573 > wsgicgi.launch(app)
1574 1574 > HGWEB
1575 1575 $ . "$TESTDIR/cgienv"
1576 1576 #if msys
1577 1577 $ PATH_INFO=//tags; export PATH_INFO
1578 1578 #else
1579 1579 $ PATH_INFO=/tags; export PATH_INFO
1580 1580 #endif
1581 1581 $ QUERY_STRING='style=raw'
1582 1582 $ python hgweb.cgi | grep '^tip'
1583 1583 tip [0-9a-f]{40} (re)
1584 1584
1585 1585 $ cd ..
1586 1586
1587 1587 Test interaction with revset (issue4426)
1588 1588
1589 1589 $ hg init issue4426
1590 1590 $ cd issue4426
1591 1591
1592 1592 $ echo a > a
1593 1593 $ hg ci -Am a
1594 1594 adding a
1595 1595 $ echo a >> a
1596 1596 $ hg ci -m a
1597 1597 $ echo a >> a
1598 1598 $ hg ci -m a
1599 1599 $ hg qimport -r 0::
1600 1600
1601 1601 reimport things
1602 1602
1603 1603 $ hg qimport -r 1::
1604 1604 abort: revision 2 is already managed
1605 1605 [255]
1606 1606
1607 1607
1608 1608 $ cd ..
@@ -1,113 +1,113
1 1 $ cat >> $HGRCPATH << EOF
2 2 > [extensions]
3 3 > blackbox=
4 4 > rebase=
5 5 > mock=$TESTDIR/mockblackbox.py
6 6 >
7 7 > [experimental]
8 8 > evolution = createmarkers
9 9 > EOF
10 10
11 11 Create a repo with some tags
12 12
13 13 $ hg init repo
14 14 $ cd repo
15 15 $ echo initial > foo
16 16 $ hg -q commit -A -m initial
17 17 $ hg tag -m 'test tag' test1
18 18 $ echo first > first
19 19 $ hg -q commit -A -m first
20 20 $ hg tag -m 'test2 tag' test2
21 21 $ hg -q up -r 0
22 22 $ echo newhead > newhead
23 23 $ hg commit -A -m newhead
24 24 adding newhead
25 25 created new head
26 26 $ hg tag -m 'test head 2 tag' head2
27 27
28 28 $ hg log -G -T '{rev}:{node|short} {tags} {desc}\n'
29 29 @ 5:2942a772f72a tip test head 2 tag
30 30 |
31 31 o 4:042eb6bfcc49 head2 newhead
32 32 |
33 33 | o 3:c3cb30f2d2cd test2 tag
34 34 | |
35 35 | o 2:d75775ffbc6b test2 first
36 36 | |
37 37 | o 1:5f97d42da03f test tag
38 38 |/
39 39 o 0:55482a6fb4b1 test1 initial
40 40
41 41
42 42 Trigger tags cache population by doing something that accesses tags info
43 43
44 44 $ hg tags
45 45 tip 5:2942a772f72a
46 46 head2 4:042eb6bfcc49
47 47 test2 2:d75775ffbc6b
48 48 test1 0:55482a6fb4b1
49 49
50 50 $ cat .hg/cache/tags2-visible
51 51 5 2942a772f72a444bef4bef13874d515f50fa27b6
52 52 042eb6bfcc4909bad84a1cbf6eb1ddf0ab587d41 head2
53 53 55482a6fb4b1881fa8f746fd52cf6f096bb21c89 test1
54 54 d75775ffbc6bca1794d300f5571272879bd280da test2
55 55
56 56 Hiding a non-tip changeset should change filtered hash and cause tags recompute
57 57
58 58 $ hg debugobsolete -d '0 0' c3cb30f2d2cd0aae008cc91a07876e3c5131fd22 -u dummyuser
59 59
60 60 $ hg tags
61 61 tip 5:2942a772f72a
62 62 head2 4:042eb6bfcc49
63 63 test1 0:55482a6fb4b1
64 64
65 65 $ cat .hg/cache/tags2-visible
66 66 5 2942a772f72a444bef4bef13874d515f50fa27b6 f34fbc9a9769ba9eff5aff3d008a6b49f85c08b1
67 67 042eb6bfcc4909bad84a1cbf6eb1ddf0ab587d41 head2
68 68 55482a6fb4b1881fa8f746fd52cf6f096bb21c89 test1
69 69
70 70 $ hg blackbox -l 4
71 71 1970/01/01 00:00:00 bob> tags
72 72 1970/01/01 00:00:00 bob> 2/2 cache hits/lookups in * seconds (glob)
73 1970/01/01 00:00:00 bob> writing tags cache file with 2 tags
73 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 2 tags
74 74 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
75 75
76 76 Hiding another changeset should cause the filtered hash to change
77 77
78 78 $ hg debugobsolete -d '0 0' d75775ffbc6bca1794d300f5571272879bd280da -u dummyuser
79 79 $ hg debugobsolete -d '0 0' 5f97d42da03fd56f3b228b03dfe48af5c0adf75b -u dummyuser
80 80
81 81 $ hg tags
82 82 tip 5:2942a772f72a
83 83 head2 4:042eb6bfcc49
84 84
85 85 $ cat .hg/cache/tags2-visible
86 86 5 2942a772f72a444bef4bef13874d515f50fa27b6 2fce1eec33263d08a4d04293960fc73a555230e4
87 87 042eb6bfcc4909bad84a1cbf6eb1ddf0ab587d41 head2
88 88
89 89 $ hg blackbox -l 4
90 90 1970/01/01 00:00:00 bob> tags
91 91 1970/01/01 00:00:00 bob> 1/1 cache hits/lookups in * seconds (glob)
92 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
92 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
93 93 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
94 94
95 95 Resolving tags on an unfiltered repo writes a separate tags cache
96 96
97 97 $ hg --hidden tags
98 98 tip 5:2942a772f72a
99 99 head2 4:042eb6bfcc49
100 100 test2 2:d75775ffbc6b
101 101 test1 0:55482a6fb4b1
102 102
103 103 $ cat .hg/cache/tags2
104 104 5 2942a772f72a444bef4bef13874d515f50fa27b6
105 105 042eb6bfcc4909bad84a1cbf6eb1ddf0ab587d41 head2
106 106 55482a6fb4b1881fa8f746fd52cf6f096bb21c89 test1
107 107 d75775ffbc6bca1794d300f5571272879bd280da test2
108 108
109 109 $ hg blackbox -l 4
110 110 1970/01/01 00:00:00 bob> --hidden tags
111 111 1970/01/01 00:00:00 bob> 2/2 cache hits/lookups in * seconds (glob)
112 1970/01/01 00:00:00 bob> writing tags cache file with 3 tags
112 1970/01/01 00:00:00 bob> writing .hg/cache/tags2 with 3 tags
113 113 1970/01/01 00:00:00 bob> --hidden tags exited 0 after * seconds (glob)
@@ -1,612 +1,612
1 1 setup
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > blackbox=
6 6 > mock=$TESTDIR/mockblackbox.py
7 7 > EOF
8 8
9 9 Helper functions:
10 10
11 11 $ cacheexists() {
12 12 > [ -f .hg/cache/tags2-visible ] && echo "tag cache exists" || echo "no tag cache"
13 13 > }
14 14
15 15 $ fnodescacheexists() {
16 16 > [ -f .hg/cache/hgtagsfnodes1 ] && echo "fnodes cache exists" || echo "no fnodes cache"
17 17 > }
18 18
19 19 $ dumptags() {
20 20 > rev=$1
21 21 > echo "rev $rev: .hgtags:"
22 22 > hg cat -r$rev .hgtags
23 23 > }
24 24
25 25 # XXX need to test that the tag cache works when we strip an old head
26 26 # and add a new one rooted off non-tip: i.e. node and rev of tip are the
27 27 # same, but stuff has changed behind tip.
28 28
29 29 Setup:
30 30
31 31 $ hg init t
32 32 $ cd t
33 33 $ cacheexists
34 34 no tag cache
35 35 $ fnodescacheexists
36 36 no fnodes cache
37 37 $ hg id
38 38 000000000000 tip
39 39 $ cacheexists
40 40 no tag cache
41 41 $ fnodescacheexists
42 42 no fnodes cache
43 43 $ echo a > a
44 44 $ hg add a
45 45 $ hg commit -m "test"
46 46 $ hg co
47 47 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 48 $ hg identify
49 49 acb14030fe0a tip
50 50 $ cacheexists
51 51 tag cache exists
52 52 No fnodes cache because .hgtags file doesn't exist
53 53 (this is an implementation detail)
54 54 $ fnodescacheexists
55 55 no fnodes cache
56 56
57 57 Try corrupting the cache
58 58
59 59 $ printf 'a b' > .hg/cache/tags2-visible
60 60 $ hg identify
61 61 acb14030fe0a tip
62 62 $ cacheexists
63 63 tag cache exists
64 64 $ fnodescacheexists
65 65 no fnodes cache
66 66 $ hg identify
67 67 acb14030fe0a tip
68 68
69 69 Create local tag with long name:
70 70
71 71 $ T=`hg identify --debug --id`
72 72 $ hg tag -l "This is a local tag with a really long name!"
73 73 $ hg tags
74 74 tip 0:acb14030fe0a
75 75 This is a local tag with a really long name! 0:acb14030fe0a
76 76 $ rm .hg/localtags
77 77
78 78 Create a tag behind hg's back:
79 79
80 80 $ echo "$T first" > .hgtags
81 81 $ cat .hgtags
82 82 acb14030fe0a21b60322c440ad2d20cf7685a376 first
83 83 $ hg add .hgtags
84 84 $ hg commit -m "add tags"
85 85 $ hg tags
86 86 tip 1:b9154636be93
87 87 first 0:acb14030fe0a
88 88 $ hg identify
89 89 b9154636be93 tip
90 90
91 91 We should have a fnodes cache now that we have a real tag
92 92 The cache should have an empty entry for rev 0 and a valid entry for rev 1.
93 93
94 94
95 95 $ fnodescacheexists
96 96 fnodes cache exists
97 97 $ f --size --hexdump .hg/cache/hgtagsfnodes1
98 98 .hg/cache/hgtagsfnodes1: size=48
99 99 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
100 100 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
101 101 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|
102 102
103 103 Repeat with cold tag cache:
104 104
105 105 $ rm -f .hg/cache/tags2-visible .hg/cache/hgtagsfnodes1
106 106 $ hg identify
107 107 b9154636be93 tip
108 108
109 109 $ fnodescacheexists
110 110 fnodes cache exists
111 111 $ f --size --hexdump .hg/cache/hgtagsfnodes1
112 112 .hg/cache/hgtagsfnodes1: size=48
113 113 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
114 114 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
115 115 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|
116 116
117 117 And again, but now unable to write tag cache:
118 118
119 119 #if unix-permissions
120 120 $ rm -f .hg/cache/tags2-visible .hg/cache/hgtagsfnodes1
121 121 $ chmod 555 .hg/cache
122 122 $ hg identify
123 123 b9154636be93 tip
124 124 $ chmod 755 .hg/cache
125 125 #endif
126 126
127 127 Tag cache debug info written to blackbox log
128 128
129 129 $ rm -f .hg/cache/tags2-visible .hg/cache/hgtagsfnodes1
130 130 $ hg identify
131 131 b9154636be93 tip
132 132 $ hg blackbox -l 5
133 133 1970/01/01 00:00:00 bob> identify
134 134 1970/01/01 00:00:00 bob> writing 48 bytes to cache/hgtagsfnodes1
135 135 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
136 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
136 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
137 137 1970/01/01 00:00:00 bob> identify exited 0 after ?.?? seconds (glob)
138 138
139 139 Failure to acquire lock results in no write
140 140
141 141 $ rm -f .hg/cache/tags2-visible .hg/cache/hgtagsfnodes1
142 142 $ echo 'foo:1' > .hg/wlock
143 143 $ hg identify
144 144 b9154636be93 tip
145 145 $ hg blackbox -l 5
146 146 1970/01/01 00:00:00 bob> identify
147 147 1970/01/01 00:00:00 bob> not writing .hg/cache/hgtagsfnodes1 because lock held
148 148 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
149 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
149 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
150 150 1970/01/01 00:00:00 bob> identify exited 0 after * seconds (glob)
151 151
152 152 $ fnodescacheexists
153 153 no fnodes cache
154 154
155 155 $ rm .hg/wlock
156 156
157 157 $ rm -f .hg/cache/tags2-visible .hg/cache/hgtagsfnodes1
158 158 $ hg identify
159 159 b9154636be93 tip
160 160
161 161 Create a branch:
162 162
163 163 $ echo bb > a
164 164 $ hg status
165 165 M a
166 166 $ hg identify
167 167 b9154636be93+ tip
168 168 $ hg co first
169 169 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
170 170 $ hg id
171 171 acb14030fe0a+ first
172 172 $ hg -v id
173 173 acb14030fe0a+ first
174 174 $ hg status
175 175 M a
176 176 $ echo 1 > b
177 177 $ hg add b
178 178 $ hg commit -m "branch"
179 179 created new head
180 180
181 181 Creating a new commit shouldn't append the .hgtags fnodes cache until
182 182 tags info is accessed
183 183
184 184 $ f --size --hexdump .hg/cache/hgtagsfnodes1
185 185 .hg/cache/hgtagsfnodes1: size=48
186 186 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
187 187 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
188 188 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|
189 189
190 190 $ hg id
191 191 c8edf04160c7 tip
192 192
193 193 First 4 bytes of record 3 are changeset fragment
194 194
195 195 $ f --size --hexdump .hg/cache/hgtagsfnodes1
196 196 .hg/cache/hgtagsfnodes1: size=72
197 197 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
198 198 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
199 199 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|
200 200 0030: c8 ed f0 41 00 00 00 00 00 00 00 00 00 00 00 00 |...A............|
201 201 0040: 00 00 00 00 00 00 00 00 |........|
202 202
203 203 Merge the two heads:
204 204
205 205 $ hg merge 1
206 206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 207 (branch merge, don't forget to commit)
208 208 $ hg id
209 209 c8edf04160c7+b9154636be93+ tip
210 210 $ hg status
211 211 M .hgtags
212 212 $ hg commit -m "merge"
213 213
214 214 Create a fake head, make sure tag not visible afterwards:
215 215
216 216 $ cp .hgtags tags
217 217 $ hg tag last
218 218 $ hg rm .hgtags
219 219 $ hg commit -m "remove"
220 220
221 221 $ mv tags .hgtags
222 222 $ hg add .hgtags
223 223 $ hg commit -m "readd"
224 224 $
225 225 $ hg tags
226 226 tip 6:35ff301afafe
227 227 first 0:acb14030fe0a
228 228
229 229 Add invalid tags:
230 230
231 231 $ echo "spam" >> .hgtags
232 232 $ echo >> .hgtags
233 233 $ echo "foo bar" >> .hgtags
234 234 $ echo "a5a5 invalid" >> .hg/localtags
235 235 $ cat .hgtags
236 236 acb14030fe0a21b60322c440ad2d20cf7685a376 first
237 237 spam
238 238
239 239 foo bar
240 240 $ hg commit -m "tags"
241 241
242 242 Report tag parse error on other head:
243 243
244 244 $ hg up 3
245 245 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 246 $ echo 'x y' >> .hgtags
247 247 $ hg commit -m "head"
248 248 created new head
249 249
250 250 $ hg tags
251 251 .hgtags@75d9f02dfe28, line 2: cannot parse entry
252 252 .hgtags@75d9f02dfe28, line 4: node 'foo' is not well formed
253 253 .hgtags@c4be69a18c11, line 2: node 'x' is not well formed
254 254 tip 8:c4be69a18c11
255 255 first 0:acb14030fe0a
256 256 $ hg tip
257 257 changeset: 8:c4be69a18c11
258 258 tag: tip
259 259 parent: 3:ac5e980c4dc0
260 260 user: test
261 261 date: Thu Jan 01 00:00:00 1970 +0000
262 262 summary: head
263 263
264 264
265 265 Test tag precedence rules:
266 266
267 267 $ cd ..
268 268 $ hg init t2
269 269 $ cd t2
270 270 $ echo foo > foo
271 271 $ hg add foo
272 272 $ hg ci -m 'add foo' # rev 0
273 273 $ hg tag bar # rev 1
274 274 $ echo >> foo
275 275 $ hg ci -m 'change foo 1' # rev 2
276 276 $ hg up -C 1
277 277 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
278 278 $ hg tag -r 1 -f bar # rev 3
279 279 $ hg up -C 1
280 280 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 281 $ echo >> foo
282 282 $ hg ci -m 'change foo 2' # rev 4
283 283 created new head
284 284 $ hg tags
285 285 tip 4:0c192d7d5e6b
286 286 bar 1:78391a272241
287 287
288 288 Repeat in case of cache effects:
289 289
290 290 $ hg tags
291 291 tip 4:0c192d7d5e6b
292 292 bar 1:78391a272241
293 293
294 294 Detailed dump of tag info:
295 295
296 296 $ hg heads -q # expect 4, 3, 2
297 297 4:0c192d7d5e6b
298 298 3:6fa450212aeb
299 299 2:7a94127795a3
300 300 $ dumptags 2
301 301 rev 2: .hgtags:
302 302 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
303 303 $ dumptags 3
304 304 rev 3: .hgtags:
305 305 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
306 306 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
307 307 78391a272241d70354aa14c874552cad6b51bb42 bar
308 308 $ dumptags 4
309 309 rev 4: .hgtags:
310 310 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
311 311
312 312 Dump cache:
313 313
314 314 $ cat .hg/cache/tags2-visible
315 315 4 0c192d7d5e6b78a714de54a2e9627952a877e25a
316 316 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
317 317 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
318 318 78391a272241d70354aa14c874552cad6b51bb42 bar
319 319
320 320 $ f --size --hexdump .hg/cache/hgtagsfnodes1
321 321 .hg/cache/hgtagsfnodes1: size=120
322 322 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
323 323 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
324 324 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
325 325 0030: 7a 94 12 77 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |z..w.....1....B(|
326 326 0040: 78 ee 5a 2d ad bc 94 3d 6f a4 50 21 7d 3b 71 8c |x.Z-...=o.P!};q.|
327 327 0050: 96 4e f3 7b 89 e5 50 eb da fd 57 89 e7 6c e1 b0 |.N.{..P...W..l..|
328 328 0060: 0c 19 2d 7d 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |..-}.....1....B(|
329 329 0070: 78 ee 5a 2d ad bc 94 3d |x.Z-...=|
330 330
331 331 Corrupt the .hgtags fnodes cache
332 332 Extra junk data at the end should get overwritten on next cache update
333 333
334 334 $ echo extra >> .hg/cache/hgtagsfnodes1
335 335 $ echo dummy1 > foo
336 336 $ hg commit -m throwaway1
337 337
338 338 $ hg tags
339 339 tip 5:8dbfe60eff30
340 340 bar 1:78391a272241
341 341
342 342 $ hg blackbox -l 5
343 343 1970/01/01 00:00:00 bob> tags
344 344 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
345 345 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
346 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
346 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
347 347 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
348 348
349 349 #if unix-permissions no-root
350 350 Errors writing to .hgtags fnodes cache are silently ignored
351 351
352 352 $ echo dummy2 > foo
353 353 $ hg commit -m throwaway2
354 354
355 355 $ chmod a-w .hg/cache/hgtagsfnodes1
356 356 $ rm -f .hg/cache/tags2-visible
357 357
358 358 $ hg tags
359 359 tip 6:b968051b5cf3
360 360 bar 1:78391a272241
361 361
362 362 $ hg blackbox -l 5
363 363 1970/01/01 00:00:00 bob> tags
364 364 1970/01/01 00:00:00 bob> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1'
365 365 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
366 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
366 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
367 367 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
368 368
369 369 $ chmod a+w .hg/cache/hgtagsfnodes1
370 370 #endif
371 371
372 372 $ rm -f .hg/cache/tags2-visible
373 373 $ hg tags
374 374 tip 6:b968051b5cf3
375 375 bar 1:78391a272241
376 376
377 377 $ hg blackbox -l 5
378 378 1970/01/01 00:00:00 bob> tags
379 379 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
380 380 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
381 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
381 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
382 382 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
383 383
384 384 $ f --size .hg/cache/hgtagsfnodes1
385 385 .hg/cache/hgtagsfnodes1: size=168
386 386
387 387 Stripping doesn't truncate the tags cache until new data is available
388 388
389 389 $ hg -q --config extensions.strip= strip -r 5 --no-backup
390 390 $ hg tags
391 391 tip 4:0c192d7d5e6b
392 392 bar 1:78391a272241
393 393
394 394 $ hg blackbox -l 4
395 395 1970/01/01 00:00:00 bob> tags
396 396 1970/01/01 00:00:00 bob> 3/3 cache hits/lookups in * seconds (glob)
397 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
397 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
398 398 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
399 399
400 400 $ f --size .hg/cache/hgtagsfnodes1
401 401 .hg/cache/hgtagsfnodes1: size=168
402 402
403 403 $ echo dummy > foo
404 404 $ hg commit -m throwaway3
405 405
406 406 $ hg tags
407 407 tip 5:035f65efb448
408 408 bar 1:78391a272241
409 409
410 410 $ hg blackbox -l 5
411 411 1970/01/01 00:00:00 bob> tags
412 412 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
413 413 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
414 1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
414 1970/01/01 00:00:00 bob> writing .hg/cache/tags2-visible with 1 tags
415 415 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
416 416 $ f --size .hg/cache/hgtagsfnodes1
417 417 .hg/cache/hgtagsfnodes1: size=144
418 418
419 419 $ hg -q --config extensions.strip= strip -r 5 --no-backup
420 420
421 421 Test tag removal:
422 422
423 423 $ hg tag --remove bar # rev 5
424 424 $ hg tip -vp
425 425 changeset: 5:5f6e8655b1c7
426 426 tag: tip
427 427 user: test
428 428 date: Thu Jan 01 00:00:00 1970 +0000
429 429 files: .hgtags
430 430 description:
431 431 Removed tag bar
432 432
433 433
434 434 diff -r 0c192d7d5e6b -r 5f6e8655b1c7 .hgtags
435 435 --- a/.hgtags Thu Jan 01 00:00:00 1970 +0000
436 436 +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
437 437 @@ -1,1 +1,3 @@
438 438 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
439 439 +78391a272241d70354aa14c874552cad6b51bb42 bar
440 440 +0000000000000000000000000000000000000000 bar
441 441
442 442 $ hg tags
443 443 tip 5:5f6e8655b1c7
444 444 $ hg tags # again, try to expose cache bugs
445 445 tip 5:5f6e8655b1c7
446 446
447 447 Remove nonexistent tag:
448 448
449 449 $ hg tag --remove foobar
450 450 abort: tag 'foobar' does not exist
451 451 [255]
452 452 $ hg tip
453 453 changeset: 5:5f6e8655b1c7
454 454 tag: tip
455 455 user: test
456 456 date: Thu Jan 01 00:00:00 1970 +0000
457 457 summary: Removed tag bar
458 458
459 459
460 460 Undo a tag with rollback:
461 461
462 462 $ hg rollback # destroy rev 5 (restore bar)
463 463 repository tip rolled back to revision 4 (undo commit)
464 464 working directory now based on revision 4
465 465 $ hg tags
466 466 tip 4:0c192d7d5e6b
467 467 bar 1:78391a272241
468 468 $ hg tags
469 469 tip 4:0c192d7d5e6b
470 470 bar 1:78391a272241
471 471
472 472 Test tag rank:
473 473
474 474 $ cd ..
475 475 $ hg init t3
476 476 $ cd t3
477 477 $ echo foo > foo
478 478 $ hg add foo
479 479 $ hg ci -m 'add foo' # rev 0
480 480 $ hg tag -f bar # rev 1 bar -> 0
481 481 $ hg tag -f bar # rev 2 bar -> 1
482 482 $ hg tag -fr 0 bar # rev 3 bar -> 0
483 483 $ hg tag -fr 1 bar # rev 4 bar -> 1
484 484 $ hg tag -fr 0 bar # rev 5 bar -> 0
485 485 $ hg tags
486 486 tip 5:85f05169d91d
487 487 bar 0:bbd179dfa0a7
488 488 $ hg co 3
489 489 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
490 490 $ echo barbar > foo
491 491 $ hg ci -m 'change foo' # rev 6
492 492 created new head
493 493 $ hg tags
494 494 tip 6:735c3ca72986
495 495 bar 0:bbd179dfa0a7
496 496
497 497 Don't allow moving tag without -f:
498 498
499 499 $ hg tag -r 3 bar
500 500 abort: tag 'bar' already exists (use -f to force)
501 501 [255]
502 502 $ hg tags
503 503 tip 6:735c3ca72986
504 504 bar 0:bbd179dfa0a7
505 505
506 506 Strip 1: expose an old head:
507 507
508 508 $ hg --config extensions.mq= strip 5
509 509 saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
510 510 $ hg tags # partly stale cache
511 511 tip 5:735c3ca72986
512 512 bar 1:78391a272241
513 513 $ hg tags # up-to-date cache
514 514 tip 5:735c3ca72986
515 515 bar 1:78391a272241
516 516
517 517 Strip 2: destroy whole branch, no old head exposed
518 518
519 519 $ hg --config extensions.mq= strip 4
520 520 saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
521 521 $ hg tags # partly stale
522 522 tip 4:735c3ca72986
523 523 bar 0:bbd179dfa0a7
524 524 $ rm -f .hg/cache/tags2-visible
525 525 $ hg tags # cold cache
526 526 tip 4:735c3ca72986
527 527 bar 0:bbd179dfa0a7
528 528
529 529 Test tag rank with 3 heads:
530 530
531 531 $ cd ..
532 532 $ hg init t4
533 533 $ cd t4
534 534 $ echo foo > foo
535 535 $ hg add
536 536 adding foo
537 537 $ hg ci -m 'add foo' # rev 0
538 538 $ hg tag bar # rev 1 bar -> 0
539 539 $ hg tag -f bar # rev 2 bar -> 1
540 540 $ hg up -qC 0
541 541 $ hg tag -fr 2 bar # rev 3 bar -> 2
542 542 $ hg tags
543 543 tip 3:197c21bbbf2c
544 544 bar 2:6fa450212aeb
545 545 $ hg up -qC 0
546 546 $ hg tag -m 'retag rev 0' -fr 0 bar # rev 4 bar -> 0, but bar stays at 2
547 547
548 548 Bar should still point to rev 2:
549 549
550 550 $ hg tags
551 551 tip 4:3b4b14ed0202
552 552 bar 2:6fa450212aeb
553 553
554 554 Test that removing global/local tags does not get confused when trying
555 555 to remove a tag of type X which actually only exists as a type Y:
556 556
557 557 $ cd ..
558 558 $ hg init t5
559 559 $ cd t5
560 560 $ echo foo > foo
561 561 $ hg add
562 562 adding foo
563 563 $ hg ci -m 'add foo' # rev 0
564 564
565 565 $ hg tag -r 0 -l localtag
566 566 $ hg tag --remove localtag
567 567 abort: tag 'localtag' is not a global tag
568 568 [255]
569 569 $
570 570 $ hg tag -r 0 globaltag
571 571 $ hg tag --remove -l globaltag
572 572 abort: tag 'globaltag' is not a local tag
573 573 [255]
574 574 $ hg tags -v
575 575 tip 1:a0b6fe111088
576 576 localtag 0:bbd179dfa0a7 local
577 577 globaltag 0:bbd179dfa0a7
578 578
579 579 Test for issue3911
580 580
581 581 $ hg tag -r 0 -l localtag2
582 582 $ hg tag -l --remove localtag2
583 583 $ hg tags -v
584 584 tip 1:a0b6fe111088
585 585 localtag 0:bbd179dfa0a7 local
586 586 globaltag 0:bbd179dfa0a7
587 587
588 588 $ hg tag -r 1 -f localtag
589 589 $ hg tags -v
590 590 tip 2:5c70a037bb37
591 591 localtag 1:a0b6fe111088
592 592 globaltag 0:bbd179dfa0a7
593 593
594 594 $ hg tags -v
595 595 tip 2:5c70a037bb37
596 596 localtag 1:a0b6fe111088
597 597 globaltag 0:bbd179dfa0a7
598 598
599 599 $ hg tag -r 1 localtag2
600 600 $ hg tags -v
601 601 tip 3:bbfb8cd42be2
602 602 localtag2 1:a0b6fe111088
603 603 localtag 1:a0b6fe111088
604 604 globaltag 0:bbd179dfa0a7
605 605
606 606 $ hg tags -v
607 607 tip 3:bbfb8cd42be2
608 608 localtag2 1:a0b6fe111088
609 609 localtag 1:a0b6fe111088
610 610 globaltag 0:bbd179dfa0a7
611 611
612 612 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now