##// END OF EJS Templates
rollback: only restore dirstate and branch when appropriate....
Greg Ward -
r15131:7c26ce9e default
parent child Browse files
Show More
@@ -1,2067 +1,2074 b''
1 1 # localrepo.py - read/write repository class 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 from node import bin, hex, nullid, nullrev, short
9 9 from i18n import _
10 10 import repo, changegroup, subrepo, discovery, pushkey
11 11 import changelog, dirstate, filelog, manifest, context, bookmarks
12 12 import lock, transaction, store, encoding
13 13 import scmutil, util, extensions, hook, error, revset
14 14 import match as matchmod
15 15 import merge as mergemod
16 16 import tags as tagsmod
17 17 from lock import release
18 18 import weakref, errno, os, time, inspect
19 19 propertycache = util.propertycache
20 20 filecache = scmutil.filecache
21 21
22 22 class localrepository(repo.repository):
23 23 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
24 24 'known', 'getbundle'))
25 25 supportedformats = set(('revlogv1', 'generaldelta'))
26 26 supported = supportedformats | set(('store', 'fncache', 'shared',
27 27 'dotencode'))
28 28
29 29 def __init__(self, baseui, path=None, create=False):
30 30 repo.repository.__init__(self)
31 31 self.root = os.path.realpath(util.expandpath(path))
32 32 self.path = os.path.join(self.root, ".hg")
33 33 self.origroot = path
34 34 self.auditor = scmutil.pathauditor(self.root, self._checknested)
35 35 self.opener = scmutil.opener(self.path)
36 36 self.wopener = scmutil.opener(self.root)
37 37 self.baseui = baseui
38 38 self.ui = baseui.copy()
39 39
40 40 try:
41 41 self.ui.readconfig(self.join("hgrc"), self.root)
42 42 extensions.loadall(self.ui)
43 43 except IOError:
44 44 pass
45 45
46 46 if not os.path.isdir(self.path):
47 47 if create:
48 48 if not os.path.exists(path):
49 49 util.makedirs(path)
50 50 util.makedir(self.path, notindexed=True)
51 51 requirements = ["revlogv1"]
52 52 if self.ui.configbool('format', 'usestore', True):
53 53 os.mkdir(os.path.join(self.path, "store"))
54 54 requirements.append("store")
55 55 if self.ui.configbool('format', 'usefncache', True):
56 56 requirements.append("fncache")
57 57 if self.ui.configbool('format', 'dotencode', True):
58 58 requirements.append('dotencode')
59 59 # create an invalid changelog
60 60 self.opener.append(
61 61 "00changelog.i",
62 62 '\0\0\0\2' # represents revlogv2
63 63 ' dummy changelog to prevent using the old repo layout'
64 64 )
65 65 if self.ui.configbool('format', 'generaldelta', False):
66 66 requirements.append("generaldelta")
67 67 requirements = set(requirements)
68 68 else:
69 69 raise error.RepoError(_("repository %s not found") % path)
70 70 elif create:
71 71 raise error.RepoError(_("repository %s already exists") % path)
72 72 else:
73 73 try:
74 74 requirements = scmutil.readrequires(self.opener, self.supported)
75 75 except IOError, inst:
76 76 if inst.errno != errno.ENOENT:
77 77 raise
78 78 requirements = set()
79 79
80 80 self.sharedpath = self.path
81 81 try:
82 82 s = os.path.realpath(self.opener.read("sharedpath").rstrip('\n'))
83 83 if not os.path.exists(s):
84 84 raise error.RepoError(
85 85 _('.hg/sharedpath points to nonexistent directory %s') % s)
86 86 self.sharedpath = s
87 87 except IOError, inst:
88 88 if inst.errno != errno.ENOENT:
89 89 raise
90 90
91 91 self.store = store.store(requirements, self.sharedpath, scmutil.opener)
92 92 self.spath = self.store.path
93 93 self.sopener = self.store.opener
94 94 self.sjoin = self.store.join
95 95 self.opener.createmode = self.store.createmode
96 96 self._applyrequirements(requirements)
97 97 if create:
98 98 self._writerequirements()
99 99
100 100
101 101 self._branchcache = None
102 102 self._branchcachetip = None
103 103 self.filterpats = {}
104 104 self._datafilters = {}
105 105 self._transref = self._lockref = self._wlockref = None
106 106
107 107 # A cache for various files under .hg/ that tracks file changes,
108 108 # (used by the filecache decorator)
109 109 #
110 110 # Maps a property name to its util.filecacheentry
111 111 self._filecache = {}
112 112
113 113 def _applyrequirements(self, requirements):
114 114 self.requirements = requirements
115 115 openerreqs = set(('revlogv1', 'generaldelta'))
116 116 self.sopener.options = dict((r, 1) for r in requirements
117 117 if r in openerreqs)
118 118
119 119 def _writerequirements(self):
120 120 reqfile = self.opener("requires", "w")
121 121 for r in self.requirements:
122 122 reqfile.write("%s\n" % r)
123 123 reqfile.close()
124 124
125 125 def _checknested(self, path):
126 126 """Determine if path is a legal nested repository."""
127 127 if not path.startswith(self.root):
128 128 return False
129 129 subpath = path[len(self.root) + 1:]
130 130
131 131 # XXX: Checking against the current working copy is wrong in
132 132 # the sense that it can reject things like
133 133 #
134 134 # $ hg cat -r 10 sub/x.txt
135 135 #
136 136 # if sub/ is no longer a subrepository in the working copy
137 137 # parent revision.
138 138 #
139 139 # However, it can of course also allow things that would have
140 140 # been rejected before, such as the above cat command if sub/
141 141 # is a subrepository now, but was a normal directory before.
142 142 # The old path auditor would have rejected by mistake since it
143 143 # panics when it sees sub/.hg/.
144 144 #
145 145 # All in all, checking against the working copy seems sensible
146 146 # since we want to prevent access to nested repositories on
147 147 # the filesystem *now*.
148 148 ctx = self[None]
149 149 parts = util.splitpath(subpath)
150 150 while parts:
151 151 prefix = os.sep.join(parts)
152 152 if prefix in ctx.substate:
153 153 if prefix == subpath:
154 154 return True
155 155 else:
156 156 sub = ctx.sub(prefix)
157 157 return sub.checknested(subpath[len(prefix) + 1:])
158 158 else:
159 159 parts.pop()
160 160 return False
161 161
162 162 @filecache('bookmarks')
163 163 def _bookmarks(self):
164 164 return bookmarks.read(self)
165 165
166 166 @filecache('bookmarks.current')
167 167 def _bookmarkcurrent(self):
168 168 return bookmarks.readcurrent(self)
169 169
170 170 @filecache('00changelog.i', True)
171 171 def changelog(self):
172 172 c = changelog.changelog(self.sopener)
173 173 if 'HG_PENDING' in os.environ:
174 174 p = os.environ['HG_PENDING']
175 175 if p.startswith(self.root):
176 176 c.readpending('00changelog.i.a')
177 177 return c
178 178
179 179 @filecache('00manifest.i', True)
180 180 def manifest(self):
181 181 return manifest.manifest(self.sopener)
182 182
183 183 @filecache('dirstate')
184 184 def dirstate(self):
185 185 warned = [0]
186 186 def validate(node):
187 187 try:
188 188 self.changelog.rev(node)
189 189 return node
190 190 except error.LookupError:
191 191 if not warned[0]:
192 192 warned[0] = True
193 193 self.ui.warn(_("warning: ignoring unknown"
194 194 " working parent %s!\n") % short(node))
195 195 return nullid
196 196
197 197 return dirstate.dirstate(self.opener, self.ui, self.root, validate)
198 198
199 199 def __getitem__(self, changeid):
200 200 if changeid is None:
201 201 return context.workingctx(self)
202 202 return context.changectx(self, changeid)
203 203
204 204 def __contains__(self, changeid):
205 205 try:
206 206 return bool(self.lookup(changeid))
207 207 except error.RepoLookupError:
208 208 return False
209 209
210 210 def __nonzero__(self):
211 211 return True
212 212
213 213 def __len__(self):
214 214 return len(self.changelog)
215 215
216 216 def __iter__(self):
217 217 for i in xrange(len(self)):
218 218 yield i
219 219
220 220 def set(self, expr, *args):
221 221 '''
222 222 Yield a context for each matching revision, after doing arg
223 223 replacement via revset.formatspec
224 224 '''
225 225
226 226 expr = revset.formatspec(expr, *args)
227 227 m = revset.match(None, expr)
228 228 for r in m(self, range(len(self))):
229 229 yield self[r]
230 230
231 231 def url(self):
232 232 return 'file:' + self.root
233 233
234 234 def hook(self, name, throw=False, **args):
235 235 return hook.hook(self.ui, self, name, throw, **args)
236 236
237 237 tag_disallowed = ':\r\n'
238 238
239 239 def _tag(self, names, node, message, local, user, date, extra={}):
240 240 if isinstance(names, str):
241 241 allchars = names
242 242 names = (names,)
243 243 else:
244 244 allchars = ''.join(names)
245 245 for c in self.tag_disallowed:
246 246 if c in allchars:
247 247 raise util.Abort(_('%r cannot be used in a tag name') % c)
248 248
249 249 branches = self.branchmap()
250 250 for name in names:
251 251 self.hook('pretag', throw=True, node=hex(node), tag=name,
252 252 local=local)
253 253 if name in branches:
254 254 self.ui.warn(_("warning: tag %s conflicts with existing"
255 255 " branch name\n") % name)
256 256
257 257 def writetags(fp, names, munge, prevtags):
258 258 fp.seek(0, 2)
259 259 if prevtags and prevtags[-1] != '\n':
260 260 fp.write('\n')
261 261 for name in names:
262 262 m = munge and munge(name) or name
263 263 if self._tagscache.tagtypes and name in self._tagscache.tagtypes:
264 264 old = self.tags().get(name, nullid)
265 265 fp.write('%s %s\n' % (hex(old), m))
266 266 fp.write('%s %s\n' % (hex(node), m))
267 267 fp.close()
268 268
269 269 prevtags = ''
270 270 if local:
271 271 try:
272 272 fp = self.opener('localtags', 'r+')
273 273 except IOError:
274 274 fp = self.opener('localtags', 'a')
275 275 else:
276 276 prevtags = fp.read()
277 277
278 278 # local tags are stored in the current charset
279 279 writetags(fp, names, None, prevtags)
280 280 for name in names:
281 281 self.hook('tag', node=hex(node), tag=name, local=local)
282 282 return
283 283
284 284 try:
285 285 fp = self.wfile('.hgtags', 'rb+')
286 286 except IOError, e:
287 287 if e.errno != errno.ENOENT:
288 288 raise
289 289 fp = self.wfile('.hgtags', 'ab')
290 290 else:
291 291 prevtags = fp.read()
292 292
293 293 # committed tags are stored in UTF-8
294 294 writetags(fp, names, encoding.fromlocal, prevtags)
295 295
296 296 fp.close()
297 297
298 298 if '.hgtags' not in self.dirstate:
299 299 self[None].add(['.hgtags'])
300 300
301 301 m = matchmod.exact(self.root, '', ['.hgtags'])
302 302 tagnode = self.commit(message, user, date, extra=extra, match=m)
303 303
304 304 for name in names:
305 305 self.hook('tag', node=hex(node), tag=name, local=local)
306 306
307 307 return tagnode
308 308
309 309 def tag(self, names, node, message, local, user, date):
310 310 '''tag a revision with one or more symbolic names.
311 311
312 312 names is a list of strings or, when adding a single tag, names may be a
313 313 string.
314 314
315 315 if local is True, the tags are stored in a per-repository file.
316 316 otherwise, they are stored in the .hgtags file, and a new
317 317 changeset is committed with the change.
318 318
319 319 keyword arguments:
320 320
321 321 local: whether to store tags in non-version-controlled file
322 322 (default False)
323 323
324 324 message: commit message to use if committing
325 325
326 326 user: name of user to use if committing
327 327
328 328 date: date tuple to use if committing'''
329 329
330 330 if not local:
331 331 for x in self.status()[:5]:
332 332 if '.hgtags' in x:
333 333 raise util.Abort(_('working copy of .hgtags is changed '
334 334 '(please commit .hgtags manually)'))
335 335
336 336 self.tags() # instantiate the cache
337 337 self._tag(names, node, message, local, user, date)
338 338
339 339 @propertycache
340 340 def _tagscache(self):
341 341 '''Returns a tagscache object that contains various tags related caches.'''
342 342
343 343 # This simplifies its cache management by having one decorated
344 344 # function (this one) and the rest simply fetch things from it.
345 345 class tagscache(object):
346 346 def __init__(self):
347 347 # These two define the set of tags for this repository. tags
348 348 # maps tag name to node; tagtypes maps tag name to 'global' or
349 349 # 'local'. (Global tags are defined by .hgtags across all
350 350 # heads, and local tags are defined in .hg/localtags.)
351 351 # They constitute the in-memory cache of tags.
352 352 self.tags = self.tagtypes = None
353 353
354 354 self.nodetagscache = self.tagslist = None
355 355
356 356 cache = tagscache()
357 357 cache.tags, cache.tagtypes = self._findtags()
358 358
359 359 return cache
360 360
361 361 def tags(self):
362 362 '''return a mapping of tag to node'''
363 363 return self._tagscache.tags
364 364
365 365 def _findtags(self):
366 366 '''Do the hard work of finding tags. Return a pair of dicts
367 367 (tags, tagtypes) where tags maps tag name to node, and tagtypes
368 368 maps tag name to a string like \'global\' or \'local\'.
369 369 Subclasses or extensions are free to add their own tags, but
370 370 should be aware that the returned dicts will be retained for the
371 371 duration of the localrepo object.'''
372 372
373 373 # XXX what tagtype should subclasses/extensions use? Currently
374 374 # mq and bookmarks add tags, but do not set the tagtype at all.
375 375 # Should each extension invent its own tag type? Should there
376 376 # be one tagtype for all such "virtual" tags? Or is the status
377 377 # quo fine?
378 378
379 379 alltags = {} # map tag name to (node, hist)
380 380 tagtypes = {}
381 381
382 382 tagsmod.findglobaltags(self.ui, self, alltags, tagtypes)
383 383 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
384 384
385 385 # Build the return dicts. Have to re-encode tag names because
386 386 # the tags module always uses UTF-8 (in order not to lose info
387 387 # writing to the cache), but the rest of Mercurial wants them in
388 388 # local encoding.
389 389 tags = {}
390 390 for (name, (node, hist)) in alltags.iteritems():
391 391 if node != nullid:
392 392 try:
393 393 # ignore tags to unknown nodes
394 394 self.changelog.lookup(node)
395 395 tags[encoding.tolocal(name)] = node
396 396 except error.LookupError:
397 397 pass
398 398 tags['tip'] = self.changelog.tip()
399 399 tagtypes = dict([(encoding.tolocal(name), value)
400 400 for (name, value) in tagtypes.iteritems()])
401 401 return (tags, tagtypes)
402 402
403 403 def tagtype(self, tagname):
404 404 '''
405 405 return the type of the given tag. result can be:
406 406
407 407 'local' : a local tag
408 408 'global' : a global tag
409 409 None : tag does not exist
410 410 '''
411 411
412 412 return self._tagscache.tagtypes.get(tagname)
413 413
414 414 def tagslist(self):
415 415 '''return a list of tags ordered by revision'''
416 416 if not self._tagscache.tagslist:
417 417 l = []
418 418 for t, n in self.tags().iteritems():
419 419 r = self.changelog.rev(n)
420 420 l.append((r, t, n))
421 421 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
422 422
423 423 return self._tagscache.tagslist
424 424
425 425 def nodetags(self, node):
426 426 '''return the tags associated with a node'''
427 427 if not self._tagscache.nodetagscache:
428 428 nodetagscache = {}
429 429 for t, n in self.tags().iteritems():
430 430 nodetagscache.setdefault(n, []).append(t)
431 431 for tags in nodetagscache.itervalues():
432 432 tags.sort()
433 433 self._tagscache.nodetagscache = nodetagscache
434 434 return self._tagscache.nodetagscache.get(node, [])
435 435
436 436 def nodebookmarks(self, node):
437 437 marks = []
438 438 for bookmark, n in self._bookmarks.iteritems():
439 439 if n == node:
440 440 marks.append(bookmark)
441 441 return sorted(marks)
442 442
443 443 def _branchtags(self, partial, lrev):
444 444 # TODO: rename this function?
445 445 tiprev = len(self) - 1
446 446 if lrev != tiprev:
447 447 ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
448 448 self._updatebranchcache(partial, ctxgen)
449 449 self._writebranchcache(partial, self.changelog.tip(), tiprev)
450 450
451 451 return partial
452 452
453 453 def updatebranchcache(self):
454 454 tip = self.changelog.tip()
455 455 if self._branchcache is not None and self._branchcachetip == tip:
456 456 return self._branchcache
457 457
458 458 oldtip = self._branchcachetip
459 459 self._branchcachetip = tip
460 460 if oldtip is None or oldtip not in self.changelog.nodemap:
461 461 partial, last, lrev = self._readbranchcache()
462 462 else:
463 463 lrev = self.changelog.rev(oldtip)
464 464 partial = self._branchcache
465 465
466 466 self._branchtags(partial, lrev)
467 467 # this private cache holds all heads (not just tips)
468 468 self._branchcache = partial
469 469
470 470 def branchmap(self):
471 471 '''returns a dictionary {branch: [branchheads]}'''
472 472 self.updatebranchcache()
473 473 return self._branchcache
474 474
475 475 def branchtags(self):
476 476 '''return a dict where branch names map to the tipmost head of
477 477 the branch, open heads come before closed'''
478 478 bt = {}
479 479 for bn, heads in self.branchmap().iteritems():
480 480 tip = heads[-1]
481 481 for h in reversed(heads):
482 482 if 'close' not in self.changelog.read(h)[5]:
483 483 tip = h
484 484 break
485 485 bt[bn] = tip
486 486 return bt
487 487
488 488 def _readbranchcache(self):
489 489 partial = {}
490 490 try:
491 491 f = self.opener("cache/branchheads")
492 492 lines = f.read().split('\n')
493 493 f.close()
494 494 except (IOError, OSError):
495 495 return {}, nullid, nullrev
496 496
497 497 try:
498 498 last, lrev = lines.pop(0).split(" ", 1)
499 499 last, lrev = bin(last), int(lrev)
500 500 if lrev >= len(self) or self[lrev].node() != last:
501 501 # invalidate the cache
502 502 raise ValueError('invalidating branch cache (tip differs)')
503 503 for l in lines:
504 504 if not l:
505 505 continue
506 506 node, label = l.split(" ", 1)
507 507 label = encoding.tolocal(label.strip())
508 508 partial.setdefault(label, []).append(bin(node))
509 509 except KeyboardInterrupt:
510 510 raise
511 511 except Exception, inst:
512 512 if self.ui.debugflag:
513 513 self.ui.warn(str(inst), '\n')
514 514 partial, last, lrev = {}, nullid, nullrev
515 515 return partial, last, lrev
516 516
517 517 def _writebranchcache(self, branches, tip, tiprev):
518 518 try:
519 519 f = self.opener("cache/branchheads", "w", atomictemp=True)
520 520 f.write("%s %s\n" % (hex(tip), tiprev))
521 521 for label, nodes in branches.iteritems():
522 522 for node in nodes:
523 523 f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
524 524 f.close()
525 525 except (IOError, OSError):
526 526 pass
527 527
528 528 def _updatebranchcache(self, partial, ctxgen):
529 529 # collect new branch entries
530 530 newbranches = {}
531 531 for c in ctxgen:
532 532 newbranches.setdefault(c.branch(), []).append(c.node())
533 533 # if older branchheads are reachable from new ones, they aren't
534 534 # really branchheads. Note checking parents is insufficient:
535 535 # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
536 536 for branch, newnodes in newbranches.iteritems():
537 537 bheads = partial.setdefault(branch, [])
538 538 bheads.extend(newnodes)
539 539 if len(bheads) <= 1:
540 540 continue
541 541 bheads = sorted(bheads, key=lambda x: self[x].rev())
542 542 # starting from tip means fewer passes over reachable
543 543 while newnodes:
544 544 latest = newnodes.pop()
545 545 if latest not in bheads:
546 546 continue
547 547 minbhrev = self[bheads[0]].node()
548 548 reachable = self.changelog.reachable(latest, minbhrev)
549 549 reachable.remove(latest)
550 550 if reachable:
551 551 bheads = [b for b in bheads if b not in reachable]
552 552 partial[branch] = bheads
553 553
554 554 def lookup(self, key):
555 555 if isinstance(key, int):
556 556 return self.changelog.node(key)
557 557 elif key == '.':
558 558 return self.dirstate.p1()
559 559 elif key == 'null':
560 560 return nullid
561 561 elif key == 'tip':
562 562 return self.changelog.tip()
563 563 n = self.changelog._match(key)
564 564 if n:
565 565 return n
566 566 if key in self._bookmarks:
567 567 return self._bookmarks[key]
568 568 if key in self.tags():
569 569 return self.tags()[key]
570 570 if key in self.branchtags():
571 571 return self.branchtags()[key]
572 572 n = self.changelog._partialmatch(key)
573 573 if n:
574 574 return n
575 575
576 576 # can't find key, check if it might have come from damaged dirstate
577 577 if key in self.dirstate.parents():
578 578 raise error.Abort(_("working directory has unknown parent '%s'!")
579 579 % short(key))
580 580 try:
581 581 if len(key) == 20:
582 582 key = hex(key)
583 583 except TypeError:
584 584 pass
585 585 raise error.RepoLookupError(_("unknown revision '%s'") % key)
586 586
587 587 def lookupbranch(self, key, remote=None):
588 588 repo = remote or self
589 589 if key in repo.branchmap():
590 590 return key
591 591
592 592 repo = (remote and remote.local()) and remote or self
593 593 return repo[key].branch()
594 594
595 595 def known(self, nodes):
596 596 nm = self.changelog.nodemap
597 597 return [(n in nm) for n in nodes]
598 598
599 599 def local(self):
600 600 return self
601 601
602 602 def join(self, f):
603 603 return os.path.join(self.path, f)
604 604
605 605 def wjoin(self, f):
606 606 return os.path.join(self.root, f)
607 607
608 608 def file(self, f):
609 609 if f[0] == '/':
610 610 f = f[1:]
611 611 return filelog.filelog(self.sopener, f)
612 612
613 613 def changectx(self, changeid):
614 614 return self[changeid]
615 615
616 616 def parents(self, changeid=None):
617 617 '''get list of changectxs for parents of changeid'''
618 618 return self[changeid].parents()
619 619
620 620 def filectx(self, path, changeid=None, fileid=None):
621 621 """changeid can be a changeset revision, node, or tag.
622 622 fileid can be a file revision or node."""
623 623 return context.filectx(self, path, changeid, fileid)
624 624
625 625 def getcwd(self):
626 626 return self.dirstate.getcwd()
627 627
628 628 def pathto(self, f, cwd=None):
629 629 return self.dirstate.pathto(f, cwd)
630 630
631 631 def wfile(self, f, mode='r'):
632 632 return self.wopener(f, mode)
633 633
634 634 def _link(self, f):
635 635 return os.path.islink(self.wjoin(f))
636 636
637 637 def _loadfilter(self, filter):
638 638 if filter not in self.filterpats:
639 639 l = []
640 640 for pat, cmd in self.ui.configitems(filter):
641 641 if cmd == '!':
642 642 continue
643 643 mf = matchmod.match(self.root, '', [pat])
644 644 fn = None
645 645 params = cmd
646 646 for name, filterfn in self._datafilters.iteritems():
647 647 if cmd.startswith(name):
648 648 fn = filterfn
649 649 params = cmd[len(name):].lstrip()
650 650 break
651 651 if not fn:
652 652 fn = lambda s, c, **kwargs: util.filter(s, c)
653 653 # Wrap old filters not supporting keyword arguments
654 654 if not inspect.getargspec(fn)[2]:
655 655 oldfn = fn
656 656 fn = lambda s, c, **kwargs: oldfn(s, c)
657 657 l.append((mf, fn, params))
658 658 self.filterpats[filter] = l
659 659 return self.filterpats[filter]
660 660
661 661 def _filter(self, filterpats, filename, data):
662 662 for mf, fn, cmd in filterpats:
663 663 if mf(filename):
664 664 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
665 665 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
666 666 break
667 667
668 668 return data
669 669
670 670 @propertycache
671 671 def _encodefilterpats(self):
672 672 return self._loadfilter('encode')
673 673
674 674 @propertycache
675 675 def _decodefilterpats(self):
676 676 return self._loadfilter('decode')
677 677
678 678 def adddatafilter(self, name, filter):
679 679 self._datafilters[name] = filter
680 680
681 681 def wread(self, filename):
682 682 if self._link(filename):
683 683 data = os.readlink(self.wjoin(filename))
684 684 else:
685 685 data = self.wopener.read(filename)
686 686 return self._filter(self._encodefilterpats, filename, data)
687 687
688 688 def wwrite(self, filename, data, flags):
689 689 data = self._filter(self._decodefilterpats, filename, data)
690 690 if 'l' in flags:
691 691 self.wopener.symlink(data, filename)
692 692 else:
693 693 self.wopener.write(filename, data)
694 694 if 'x' in flags:
695 695 util.setflags(self.wjoin(filename), False, True)
696 696
697 697 def wwritedata(self, filename, data):
698 698 return self._filter(self._decodefilterpats, filename, data)
699 699
700 700 def transaction(self, desc):
701 701 tr = self._transref and self._transref() or None
702 702 if tr and tr.running():
703 703 return tr.nest()
704 704
705 705 # abort here if the journal already exists
706 706 if os.path.exists(self.sjoin("journal")):
707 707 raise error.RepoError(
708 708 _("abandoned transaction found - run hg recover"))
709 709
710 710 journalfiles = self._writejournal(desc)
711 711 renames = [(x, undoname(x)) for x in journalfiles]
712 712
713 713 tr = transaction.transaction(self.ui.warn, self.sopener,
714 714 self.sjoin("journal"),
715 715 aftertrans(renames),
716 716 self.store.createmode)
717 717 self._transref = weakref.ref(tr)
718 718 return tr
719 719
720 720 def _writejournal(self, desc):
721 721 # save dirstate for rollback
722 722 try:
723 723 ds = self.opener.read("dirstate")
724 724 except IOError:
725 725 ds = ""
726 726 self.opener.write("journal.dirstate", ds)
727 727 self.opener.write("journal.branch",
728 728 encoding.fromlocal(self.dirstate.branch()))
729 729 self.opener.write("journal.desc",
730 730 "%d\n%s\n" % (len(self), desc))
731 731
732 732 bkname = self.join('bookmarks')
733 733 if os.path.exists(bkname):
734 734 util.copyfile(bkname, self.join('journal.bookmarks'))
735 735 else:
736 736 self.opener.write('journal.bookmarks', '')
737 737
738 738 return (self.sjoin('journal'), self.join('journal.dirstate'),
739 739 self.join('journal.branch'), self.join('journal.desc'),
740 740 self.join('journal.bookmarks'))
741 741
742 742 def recover(self):
743 743 lock = self.lock()
744 744 try:
745 745 if os.path.exists(self.sjoin("journal")):
746 746 self.ui.status(_("rolling back interrupted transaction\n"))
747 747 transaction.rollback(self.sopener, self.sjoin("journal"),
748 748 self.ui.warn)
749 749 self.invalidate()
750 750 return True
751 751 else:
752 752 self.ui.warn(_("no interrupted transaction available\n"))
753 753 return False
754 754 finally:
755 755 lock.release()
756 756
757 757 def rollback(self, dryrun=False):
758 758 wlock = lock = None
759 759 try:
760 760 wlock = self.wlock()
761 761 lock = self.lock()
762 762 if os.path.exists(self.sjoin("undo")):
763 763 return self._rollback(dryrun)
764 764 else:
765 765 self.ui.warn(_("no rollback information available\n"))
766 766 return 1
767 767 finally:
768 768 release(lock, wlock)
769 769
770 770 def _rollback(self, dryrun):
771 771 ui = self.ui
772 772 try:
773 773 args = self.opener.read('undo.desc').splitlines()
774 774 (oldlen, desc, detail) = (int(args[0]), args[1], None)
775 775 if len(args) >= 3:
776 776 detail = args[2]
777 777 oldtip = oldlen - 1
778 778
779 779 if detail and ui.verbose:
780 780 msg = (_('repository tip rolled back to revision %s'
781 781 ' (undo %s: %s)\n')
782 782 % (oldtip, desc, detail))
783 783 else:
784 784 msg = (_('repository tip rolled back to revision %s'
785 785 ' (undo %s)\n')
786 786 % (oldtip, desc))
787 787 except IOError:
788 788 msg = _('rolling back unknown transaction\n')
789 789 ui.status(msg)
790 790 if dryrun:
791 791 return 0
792
793 parents = self.dirstate.parents()
792 794 transaction.rollback(self.sopener, self.sjoin('undo'), ui.warn)
793 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
794 795 if os.path.exists(self.join('undo.bookmarks')):
795 796 util.rename(self.join('undo.bookmarks'),
796 797 self.join('bookmarks'))
797 try:
798 branch = self.opener.read('undo.branch')
799 self.dirstate.setbranch(branch)
800 except IOError:
801 ui.warn(_('named branch could not be reset: '
802 'current branch is still \'%s\'\n')
803 % self.dirstate.branch())
804 798 self.invalidate()
805 self.dirstate.invalidate()
806 self.destroyed()
807 parents = tuple([p.rev() for p in self.parents()])
808 if len(parents) > 1:
809 ui.status(_('working directory now based on '
810 'revisions %d and %d\n') % parents)
811 else:
812 ui.status(_('working directory now based on '
813 'revision %d\n') % parents)
799
800 parentgone = (parents[0] not in self.changelog.nodemap or
801 parents[1] not in self.changelog.nodemap)
802 if parentgone:
803 util.rename(self.join('undo.dirstate'), self.join('dirstate'))
804 try:
805 branch = self.opener.read('undo.branch')
806 self.dirstate.setbranch(branch)
807 except IOError:
808 ui.warn(_('named branch could not be reset: '
809 'current branch is still \'%s\'\n')
810 % self.dirstate.branch())
811
812 self.dirstate.invalidate()
813 self.destroyed()
814 parents = tuple([p.rev() for p in self.parents()])
815 if len(parents) > 1:
816 ui.status(_('working directory now based on '
817 'revisions %d and %d\n') % parents)
818 else:
819 ui.status(_('working directory now based on '
820 'revision %d\n') % parents)
814 821 return 0
815 822
816 823 def invalidatecaches(self):
817 824 try:
818 825 delattr(self, '_tagscache')
819 826 except AttributeError:
820 827 pass
821 828
822 829 self._branchcache = None # in UTF-8
823 830 self._branchcachetip = None
824 831
825 832 def invalidatedirstate(self):
826 833 '''Invalidates the dirstate, causing the next call to dirstate
827 834 to check if it was modified since the last time it was read,
828 835 rereading it if it has.
829 836
830 837 This is different to dirstate.invalidate() that it doesn't always
831 838 rereads the dirstate. Use dirstate.invalidate() if you want to
832 839 explicitly read the dirstate again (i.e. restoring it to a previous
833 840 known good state).'''
834 841 try:
835 842 delattr(self, 'dirstate')
836 843 except AttributeError:
837 844 pass
838 845
839 846 def invalidate(self):
840 847 for k in self._filecache:
841 848 # dirstate is invalidated separately in invalidatedirstate()
842 849 if k == 'dirstate':
843 850 continue
844 851
845 852 try:
846 853 delattr(self, k)
847 854 except AttributeError:
848 855 pass
849 856 self.invalidatecaches()
850 857
851 858 def _lock(self, lockname, wait, releasefn, acquirefn, desc):
852 859 try:
853 860 l = lock.lock(lockname, 0, releasefn, desc=desc)
854 861 except error.LockHeld, inst:
855 862 if not wait:
856 863 raise
857 864 self.ui.warn(_("waiting for lock on %s held by %r\n") %
858 865 (desc, inst.locker))
859 866 # default to 600 seconds timeout
860 867 l = lock.lock(lockname, int(self.ui.config("ui", "timeout", "600")),
861 868 releasefn, desc=desc)
862 869 if acquirefn:
863 870 acquirefn()
864 871 return l
865 872
866 873 def lock(self, wait=True):
867 874 '''Lock the repository store (.hg/store) and return a weak reference
868 875 to the lock. Use this before modifying the store (e.g. committing or
869 876 stripping). If you are opening a transaction, get a lock as well.)'''
870 877 l = self._lockref and self._lockref()
871 878 if l is not None and l.held:
872 879 l.lock()
873 880 return l
874 881
875 882 def unlock():
876 883 self.store.write()
877 884 for k, ce in self._filecache.items():
878 885 if k == 'dirstate':
879 886 continue
880 887 ce.refresh()
881 888
882 889 l = self._lock(self.sjoin("lock"), wait, unlock,
883 890 self.invalidate, _('repository %s') % self.origroot)
884 891 self._lockref = weakref.ref(l)
885 892 return l
886 893
887 894 def wlock(self, wait=True):
888 895 '''Lock the non-store parts of the repository (everything under
889 896 .hg except .hg/store) and return a weak reference to the lock.
890 897 Use this before modifying files in .hg.'''
891 898 l = self._wlockref and self._wlockref()
892 899 if l is not None and l.held:
893 900 l.lock()
894 901 return l
895 902
896 903 def unlock():
897 904 self.dirstate.write()
898 905 ce = self._filecache.get('dirstate')
899 906 if ce:
900 907 ce.refresh()
901 908
902 909 l = self._lock(self.join("wlock"), wait, unlock,
903 910 self.invalidatedirstate, _('working directory of %s') %
904 911 self.origroot)
905 912 self._wlockref = weakref.ref(l)
906 913 return l
907 914
908 915 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
909 916 """
910 917 commit an individual file as part of a larger transaction
911 918 """
912 919
913 920 fname = fctx.path()
914 921 text = fctx.data()
915 922 flog = self.file(fname)
916 923 fparent1 = manifest1.get(fname, nullid)
917 924 fparent2 = fparent2o = manifest2.get(fname, nullid)
918 925
919 926 meta = {}
920 927 copy = fctx.renamed()
921 928 if copy and copy[0] != fname:
922 929 # Mark the new revision of this file as a copy of another
923 930 # file. This copy data will effectively act as a parent
924 931 # of this new revision. If this is a merge, the first
925 932 # parent will be the nullid (meaning "look up the copy data")
926 933 # and the second one will be the other parent. For example:
927 934 #
928 935 # 0 --- 1 --- 3 rev1 changes file foo
929 936 # \ / rev2 renames foo to bar and changes it
930 937 # \- 2 -/ rev3 should have bar with all changes and
931 938 # should record that bar descends from
932 939 # bar in rev2 and foo in rev1
933 940 #
934 941 # this allows this merge to succeed:
935 942 #
936 943 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
937 944 # \ / merging rev3 and rev4 should use bar@rev2
938 945 # \- 2 --- 4 as the merge base
939 946 #
940 947
941 948 cfname = copy[0]
942 949 crev = manifest1.get(cfname)
943 950 newfparent = fparent2
944 951
945 952 if manifest2: # branch merge
946 953 if fparent2 == nullid or crev is None: # copied on remote side
947 954 if cfname in manifest2:
948 955 crev = manifest2[cfname]
949 956 newfparent = fparent1
950 957
951 958 # find source in nearest ancestor if we've lost track
952 959 if not crev:
953 960 self.ui.debug(" %s: searching for copy revision for %s\n" %
954 961 (fname, cfname))
955 962 for ancestor in self[None].ancestors():
956 963 if cfname in ancestor:
957 964 crev = ancestor[cfname].filenode()
958 965 break
959 966
960 967 if crev:
961 968 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
962 969 meta["copy"] = cfname
963 970 meta["copyrev"] = hex(crev)
964 971 fparent1, fparent2 = nullid, newfparent
965 972 else:
966 973 self.ui.warn(_("warning: can't find ancestor for '%s' "
967 974 "copied from '%s'!\n") % (fname, cfname))
968 975
969 976 elif fparent2 != nullid:
970 977 # is one parent an ancestor of the other?
971 978 fparentancestor = flog.ancestor(fparent1, fparent2)
972 979 if fparentancestor == fparent1:
973 980 fparent1, fparent2 = fparent2, nullid
974 981 elif fparentancestor == fparent2:
975 982 fparent2 = nullid
976 983
977 984 # is the file changed?
978 985 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
979 986 changelist.append(fname)
980 987 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
981 988
982 989 # are just the flags changed during merge?
983 990 if fparent1 != fparent2o and manifest1.flags(fname) != fctx.flags():
984 991 changelist.append(fname)
985 992
986 993 return fparent1
987 994
988 995 def commit(self, text="", user=None, date=None, match=None, force=False,
989 996 editor=False, extra={}):
990 997 """Add a new revision to current repository.
991 998
992 999 Revision information is gathered from the working directory,
993 1000 match can be used to filter the committed files. If editor is
994 1001 supplied, it is called to get a commit message.
995 1002 """
996 1003
997 1004 def fail(f, msg):
998 1005 raise util.Abort('%s: %s' % (f, msg))
999 1006
1000 1007 if not match:
1001 1008 match = matchmod.always(self.root, '')
1002 1009
1003 1010 if not force:
1004 1011 vdirs = []
1005 1012 match.dir = vdirs.append
1006 1013 match.bad = fail
1007 1014
1008 1015 wlock = self.wlock()
1009 1016 try:
1010 1017 wctx = self[None]
1011 1018 merge = len(wctx.parents()) > 1
1012 1019
1013 1020 if (not force and merge and match and
1014 1021 (match.files() or match.anypats())):
1015 1022 raise util.Abort(_('cannot partially commit a merge '
1016 1023 '(do not specify files or patterns)'))
1017 1024
1018 1025 changes = self.status(match=match, clean=force)
1019 1026 if force:
1020 1027 changes[0].extend(changes[6]) # mq may commit unchanged files
1021 1028
1022 1029 # check subrepos
1023 1030 subs = []
1024 1031 removedsubs = set()
1025 1032 if '.hgsub' in wctx:
1026 1033 # only manage subrepos and .hgsubstate if .hgsub is present
1027 1034 for p in wctx.parents():
1028 1035 removedsubs.update(s for s in p.substate if match(s))
1029 1036 for s in wctx.substate:
1030 1037 removedsubs.discard(s)
1031 1038 if match(s) and wctx.sub(s).dirty():
1032 1039 subs.append(s)
1033 1040 if (subs or removedsubs):
1034 1041 if (not match('.hgsub') and
1035 1042 '.hgsub' in (wctx.modified() + wctx.added())):
1036 1043 raise util.Abort(
1037 1044 _("can't commit subrepos without .hgsub"))
1038 1045 if '.hgsubstate' not in changes[0]:
1039 1046 changes[0].insert(0, '.hgsubstate')
1040 1047 if '.hgsubstate' in changes[2]:
1041 1048 changes[2].remove('.hgsubstate')
1042 1049 elif '.hgsub' in changes[2]:
1043 1050 # clean up .hgsubstate when .hgsub is removed
1044 1051 if ('.hgsubstate' in wctx and
1045 1052 '.hgsubstate' not in changes[0] + changes[1] + changes[2]):
1046 1053 changes[2].insert(0, '.hgsubstate')
1047 1054
1048 1055 if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
1049 1056 changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
1050 1057 if changedsubs:
1051 1058 raise util.Abort(_("uncommitted changes in subrepo %s")
1052 1059 % changedsubs[0])
1053 1060
1054 1061 # make sure all explicit patterns are matched
1055 1062 if not force and match.files():
1056 1063 matched = set(changes[0] + changes[1] + changes[2])
1057 1064
1058 1065 for f in match.files():
1059 1066 if f == '.' or f in matched or f in wctx.substate:
1060 1067 continue
1061 1068 if f in changes[3]: # missing
1062 1069 fail(f, _('file not found!'))
1063 1070 if f in vdirs: # visited directory
1064 1071 d = f + '/'
1065 1072 for mf in matched:
1066 1073 if mf.startswith(d):
1067 1074 break
1068 1075 else:
1069 1076 fail(f, _("no match under directory!"))
1070 1077 elif f not in self.dirstate:
1071 1078 fail(f, _("file not tracked!"))
1072 1079
1073 1080 if (not force and not extra.get("close") and not merge
1074 1081 and not (changes[0] or changes[1] or changes[2])
1075 1082 and wctx.branch() == wctx.p1().branch()):
1076 1083 return None
1077 1084
1078 1085 ms = mergemod.mergestate(self)
1079 1086 for f in changes[0]:
1080 1087 if f in ms and ms[f] == 'u':
1081 1088 raise util.Abort(_("unresolved merge conflicts "
1082 1089 "(see hg help resolve)"))
1083 1090
1084 1091 cctx = context.workingctx(self, text, user, date, extra, changes)
1085 1092 if editor:
1086 1093 cctx._text = editor(self, cctx, subs)
1087 1094 edited = (text != cctx._text)
1088 1095
1089 1096 # commit subs
1090 1097 if subs or removedsubs:
1091 1098 state = wctx.substate.copy()
1092 1099 for s in sorted(subs):
1093 1100 sub = wctx.sub(s)
1094 1101 self.ui.status(_('committing subrepository %s\n') %
1095 1102 subrepo.subrelpath(sub))
1096 1103 sr = sub.commit(cctx._text, user, date)
1097 1104 state[s] = (state[s][0], sr)
1098 1105 subrepo.writestate(self, state)
1099 1106
1100 1107 # Save commit message in case this transaction gets rolled back
1101 1108 # (e.g. by a pretxncommit hook). Leave the content alone on
1102 1109 # the assumption that the user will use the same editor again.
1103 1110 msgfn = self.savecommitmessage(cctx._text)
1104 1111
1105 1112 p1, p2 = self.dirstate.parents()
1106 1113 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
1107 1114 try:
1108 1115 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
1109 1116 ret = self.commitctx(cctx, True)
1110 1117 except:
1111 1118 if edited:
1112 1119 self.ui.write(
1113 1120 _('note: commit message saved in %s\n') % msgfn)
1114 1121 raise
1115 1122
1116 1123 # update bookmarks, dirstate and mergestate
1117 1124 bookmarks.update(self, p1, ret)
1118 1125 for f in changes[0] + changes[1]:
1119 1126 self.dirstate.normal(f)
1120 1127 for f in changes[2]:
1121 1128 self.dirstate.drop(f)
1122 1129 self.dirstate.setparents(ret)
1123 1130 ms.reset()
1124 1131 finally:
1125 1132 wlock.release()
1126 1133
1127 1134 self.hook("commit", node=hex(ret), parent1=hookp1, parent2=hookp2)
1128 1135 return ret
1129 1136
1130 1137 def commitctx(self, ctx, error=False):
1131 1138 """Add a new revision to current repository.
1132 1139 Revision information is passed via the context argument.
1133 1140 """
1134 1141
1135 1142 tr = lock = None
1136 1143 removed = list(ctx.removed())
1137 1144 p1, p2 = ctx.p1(), ctx.p2()
1138 1145 user = ctx.user()
1139 1146
1140 1147 lock = self.lock()
1141 1148 try:
1142 1149 tr = self.transaction("commit")
1143 1150 trp = weakref.proxy(tr)
1144 1151
1145 1152 if ctx.files():
1146 1153 m1 = p1.manifest().copy()
1147 1154 m2 = p2.manifest()
1148 1155
1149 1156 # check in files
1150 1157 new = {}
1151 1158 changed = []
1152 1159 linkrev = len(self)
1153 1160 for f in sorted(ctx.modified() + ctx.added()):
1154 1161 self.ui.note(f + "\n")
1155 1162 try:
1156 1163 fctx = ctx[f]
1157 1164 new[f] = self._filecommit(fctx, m1, m2, linkrev, trp,
1158 1165 changed)
1159 1166 m1.set(f, fctx.flags())
1160 1167 except OSError, inst:
1161 1168 self.ui.warn(_("trouble committing %s!\n") % f)
1162 1169 raise
1163 1170 except IOError, inst:
1164 1171 errcode = getattr(inst, 'errno', errno.ENOENT)
1165 1172 if error or errcode and errcode != errno.ENOENT:
1166 1173 self.ui.warn(_("trouble committing %s!\n") % f)
1167 1174 raise
1168 1175 else:
1169 1176 removed.append(f)
1170 1177
1171 1178 # update manifest
1172 1179 m1.update(new)
1173 1180 removed = [f for f in sorted(removed) if f in m1 or f in m2]
1174 1181 drop = [f for f in removed if f in m1]
1175 1182 for f in drop:
1176 1183 del m1[f]
1177 1184 mn = self.manifest.add(m1, trp, linkrev, p1.manifestnode(),
1178 1185 p2.manifestnode(), (new, drop))
1179 1186 files = changed + removed
1180 1187 else:
1181 1188 mn = p1.manifestnode()
1182 1189 files = []
1183 1190
1184 1191 # update changelog
1185 1192 self.changelog.delayupdate()
1186 1193 n = self.changelog.add(mn, files, ctx.description(),
1187 1194 trp, p1.node(), p2.node(),
1188 1195 user, ctx.date(), ctx.extra().copy())
1189 1196 p = lambda: self.changelog.writepending() and self.root or ""
1190 1197 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
1191 1198 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
1192 1199 parent2=xp2, pending=p)
1193 1200 self.changelog.finalize(trp)
1194 1201 tr.close()
1195 1202
1196 1203 if self._branchcache:
1197 1204 self.updatebranchcache()
1198 1205 return n
1199 1206 finally:
1200 1207 if tr:
1201 1208 tr.release()
1202 1209 lock.release()
1203 1210
1204 1211 def destroyed(self):
1205 1212 '''Inform the repository that nodes have been destroyed.
1206 1213 Intended for use by strip and rollback, so there's a common
1207 1214 place for anything that has to be done after destroying history.'''
1208 1215 # XXX it might be nice if we could take the list of destroyed
1209 1216 # nodes, but I don't see an easy way for rollback() to do that
1210 1217
1211 1218 # Ensure the persistent tag cache is updated. Doing it now
1212 1219 # means that the tag cache only has to worry about destroyed
1213 1220 # heads immediately after a strip/rollback. That in turn
1214 1221 # guarantees that "cachetip == currenttip" (comparing both rev
1215 1222 # and node) always means no nodes have been added or destroyed.
1216 1223
1217 1224 # XXX this is suboptimal when qrefresh'ing: we strip the current
1218 1225 # head, refresh the tag cache, then immediately add a new head.
1219 1226 # But I think doing it this way is necessary for the "instant
1220 1227 # tag cache retrieval" case to work.
1221 1228 self.invalidatecaches()
1222 1229
1223 1230 def walk(self, match, node=None):
1224 1231 '''
1225 1232 walk recursively through the directory tree or a given
1226 1233 changeset, finding all files matched by the match
1227 1234 function
1228 1235 '''
1229 1236 return self[node].walk(match)
1230 1237
1231 1238 def status(self, node1='.', node2=None, match=None,
1232 1239 ignored=False, clean=False, unknown=False,
1233 1240 listsubrepos=False):
1234 1241 """return status of files between two nodes or node and working directory
1235 1242
1236 1243 If node1 is None, use the first dirstate parent instead.
1237 1244 If node2 is None, compare node1 with working directory.
1238 1245 """
1239 1246
1240 1247 def mfmatches(ctx):
1241 1248 mf = ctx.manifest().copy()
1242 1249 for fn in mf.keys():
1243 1250 if not match(fn):
1244 1251 del mf[fn]
1245 1252 return mf
1246 1253
1247 1254 if isinstance(node1, context.changectx):
1248 1255 ctx1 = node1
1249 1256 else:
1250 1257 ctx1 = self[node1]
1251 1258 if isinstance(node2, context.changectx):
1252 1259 ctx2 = node2
1253 1260 else:
1254 1261 ctx2 = self[node2]
1255 1262
1256 1263 working = ctx2.rev() is None
1257 1264 parentworking = working and ctx1 == self['.']
1258 1265 match = match or matchmod.always(self.root, self.getcwd())
1259 1266 listignored, listclean, listunknown = ignored, clean, unknown
1260 1267
1261 1268 # load earliest manifest first for caching reasons
1262 1269 if not working and ctx2.rev() < ctx1.rev():
1263 1270 ctx2.manifest()
1264 1271
1265 1272 if not parentworking:
1266 1273 def bad(f, msg):
1267 1274 if f not in ctx1:
1268 1275 self.ui.warn('%s: %s\n' % (self.dirstate.pathto(f), msg))
1269 1276 match.bad = bad
1270 1277
1271 1278 if working: # we need to scan the working dir
1272 1279 subrepos = []
1273 1280 if '.hgsub' in self.dirstate:
1274 1281 subrepos = ctx2.substate.keys()
1275 1282 s = self.dirstate.status(match, subrepos, listignored,
1276 1283 listclean, listunknown)
1277 1284 cmp, modified, added, removed, deleted, unknown, ignored, clean = s
1278 1285
1279 1286 # check for any possibly clean files
1280 1287 if parentworking and cmp:
1281 1288 fixup = []
1282 1289 # do a full compare of any files that might have changed
1283 1290 for f in sorted(cmp):
1284 1291 if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
1285 1292 or ctx1[f].cmp(ctx2[f])):
1286 1293 modified.append(f)
1287 1294 else:
1288 1295 fixup.append(f)
1289 1296
1290 1297 # update dirstate for files that are actually clean
1291 1298 if fixup:
1292 1299 if listclean:
1293 1300 clean += fixup
1294 1301
1295 1302 try:
1296 1303 # updating the dirstate is optional
1297 1304 # so we don't wait on the lock
1298 1305 wlock = self.wlock(False)
1299 1306 try:
1300 1307 for f in fixup:
1301 1308 self.dirstate.normal(f)
1302 1309 finally:
1303 1310 wlock.release()
1304 1311 except error.LockError:
1305 1312 pass
1306 1313
1307 1314 if not parentworking:
1308 1315 mf1 = mfmatches(ctx1)
1309 1316 if working:
1310 1317 # we are comparing working dir against non-parent
1311 1318 # generate a pseudo-manifest for the working dir
1312 1319 mf2 = mfmatches(self['.'])
1313 1320 for f in cmp + modified + added:
1314 1321 mf2[f] = None
1315 1322 mf2.set(f, ctx2.flags(f))
1316 1323 for f in removed:
1317 1324 if f in mf2:
1318 1325 del mf2[f]
1319 1326 else:
1320 1327 # we are comparing two revisions
1321 1328 deleted, unknown, ignored = [], [], []
1322 1329 mf2 = mfmatches(ctx2)
1323 1330
1324 1331 modified, added, clean = [], [], []
1325 1332 for fn in mf2:
1326 1333 if fn in mf1:
1327 1334 if (fn not in deleted and
1328 1335 (mf1.flags(fn) != mf2.flags(fn) or
1329 1336 (mf1[fn] != mf2[fn] and
1330 1337 (mf2[fn] or ctx1[fn].cmp(ctx2[fn]))))):
1331 1338 modified.append(fn)
1332 1339 elif listclean:
1333 1340 clean.append(fn)
1334 1341 del mf1[fn]
1335 1342 elif fn not in deleted:
1336 1343 added.append(fn)
1337 1344 removed = mf1.keys()
1338 1345
1339 1346 r = modified, added, removed, deleted, unknown, ignored, clean
1340 1347
1341 1348 if listsubrepos:
1342 1349 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
1343 1350 if working:
1344 1351 rev2 = None
1345 1352 else:
1346 1353 rev2 = ctx2.substate[subpath][1]
1347 1354 try:
1348 1355 submatch = matchmod.narrowmatcher(subpath, match)
1349 1356 s = sub.status(rev2, match=submatch, ignored=listignored,
1350 1357 clean=listclean, unknown=listunknown,
1351 1358 listsubrepos=True)
1352 1359 for rfiles, sfiles in zip(r, s):
1353 1360 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
1354 1361 except error.LookupError:
1355 1362 self.ui.status(_("skipping missing subrepository: %s\n")
1356 1363 % subpath)
1357 1364
1358 1365 for l in r:
1359 1366 l.sort()
1360 1367 return r
1361 1368
1362 1369 def heads(self, start=None):
1363 1370 heads = self.changelog.heads(start)
1364 1371 # sort the output in rev descending order
1365 1372 return sorted(heads, key=self.changelog.rev, reverse=True)
1366 1373
1367 1374 def branchheads(self, branch=None, start=None, closed=False):
1368 1375 '''return a (possibly filtered) list of heads for the given branch
1369 1376
1370 1377 Heads are returned in topological order, from newest to oldest.
1371 1378 If branch is None, use the dirstate branch.
1372 1379 If start is not None, return only heads reachable from start.
1373 1380 If closed is True, return heads that are marked as closed as well.
1374 1381 '''
1375 1382 if branch is None:
1376 1383 branch = self[None].branch()
1377 1384 branches = self.branchmap()
1378 1385 if branch not in branches:
1379 1386 return []
1380 1387 # the cache returns heads ordered lowest to highest
1381 1388 bheads = list(reversed(branches[branch]))
1382 1389 if start is not None:
1383 1390 # filter out the heads that cannot be reached from startrev
1384 1391 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
1385 1392 bheads = [h for h in bheads if h in fbheads]
1386 1393 if not closed:
1387 1394 bheads = [h for h in bheads if
1388 1395 ('close' not in self.changelog.read(h)[5])]
1389 1396 return bheads
1390 1397
1391 1398 def branches(self, nodes):
1392 1399 if not nodes:
1393 1400 nodes = [self.changelog.tip()]
1394 1401 b = []
1395 1402 for n in nodes:
1396 1403 t = n
1397 1404 while True:
1398 1405 p = self.changelog.parents(n)
1399 1406 if p[1] != nullid or p[0] == nullid:
1400 1407 b.append((t, n, p[0], p[1]))
1401 1408 break
1402 1409 n = p[0]
1403 1410 return b
1404 1411
1405 1412 def between(self, pairs):
1406 1413 r = []
1407 1414
1408 1415 for top, bottom in pairs:
1409 1416 n, l, i = top, [], 0
1410 1417 f = 1
1411 1418
1412 1419 while n != bottom and n != nullid:
1413 1420 p = self.changelog.parents(n)[0]
1414 1421 if i == f:
1415 1422 l.append(n)
1416 1423 f = f * 2
1417 1424 n = p
1418 1425 i += 1
1419 1426
1420 1427 r.append(l)
1421 1428
1422 1429 return r
1423 1430
1424 1431 def pull(self, remote, heads=None, force=False):
1425 1432 lock = self.lock()
1426 1433 try:
1427 1434 tmp = discovery.findcommonincoming(self, remote, heads=heads,
1428 1435 force=force)
1429 1436 common, fetch, rheads = tmp
1430 1437 if not fetch:
1431 1438 self.ui.status(_("no changes found\n"))
1432 1439 result = 0
1433 1440 else:
1434 1441 if heads is None and list(common) == [nullid]:
1435 1442 self.ui.status(_("requesting all changes\n"))
1436 1443 elif heads is None and remote.capable('changegroupsubset'):
1437 1444 # issue1320, avoid a race if remote changed after discovery
1438 1445 heads = rheads
1439 1446
1440 1447 if remote.capable('getbundle'):
1441 1448 cg = remote.getbundle('pull', common=common,
1442 1449 heads=heads or rheads)
1443 1450 elif heads is None:
1444 1451 cg = remote.changegroup(fetch, 'pull')
1445 1452 elif not remote.capable('changegroupsubset'):
1446 1453 raise util.Abort(_("partial pull cannot be done because "
1447 1454 "other repository doesn't support "
1448 1455 "changegroupsubset."))
1449 1456 else:
1450 1457 cg = remote.changegroupsubset(fetch, heads, 'pull')
1451 1458 result = self.addchangegroup(cg, 'pull', remote.url(),
1452 1459 lock=lock)
1453 1460 finally:
1454 1461 lock.release()
1455 1462
1456 1463 return result
1457 1464
1458 1465 def checkpush(self, force, revs):
1459 1466 """Extensions can override this function if additional checks have
1460 1467 to be performed before pushing, or call it if they override push
1461 1468 command.
1462 1469 """
1463 1470 pass
1464 1471
1465 1472 def push(self, remote, force=False, revs=None, newbranch=False):
1466 1473 '''Push outgoing changesets (limited by revs) from the current
1467 1474 repository to remote. Return an integer:
1468 1475 - 0 means HTTP error *or* nothing to push
1469 1476 - 1 means we pushed and remote head count is unchanged *or*
1470 1477 we have outgoing changesets but refused to push
1471 1478 - other values as described by addchangegroup()
1472 1479 '''
1473 1480 # there are two ways to push to remote repo:
1474 1481 #
1475 1482 # addchangegroup assumes local user can lock remote
1476 1483 # repo (local filesystem, old ssh servers).
1477 1484 #
1478 1485 # unbundle assumes local user cannot lock remote repo (new ssh
1479 1486 # servers, http servers).
1480 1487
1481 1488 self.checkpush(force, revs)
1482 1489 lock = None
1483 1490 unbundle = remote.capable('unbundle')
1484 1491 if not unbundle:
1485 1492 lock = remote.lock()
1486 1493 try:
1487 1494 cg, remote_heads = discovery.prepush(self, remote, force, revs,
1488 1495 newbranch)
1489 1496 ret = remote_heads
1490 1497 if cg is not None:
1491 1498 if unbundle:
1492 1499 # local repo finds heads on server, finds out what
1493 1500 # revs it must push. once revs transferred, if server
1494 1501 # finds it has different heads (someone else won
1495 1502 # commit/push race), server aborts.
1496 1503 if force:
1497 1504 remote_heads = ['force']
1498 1505 # ssh: return remote's addchangegroup()
1499 1506 # http: return remote's addchangegroup() or 0 for error
1500 1507 ret = remote.unbundle(cg, remote_heads, 'push')
1501 1508 else:
1502 1509 # we return an integer indicating remote head count change
1503 1510 ret = remote.addchangegroup(cg, 'push', self.url(),
1504 1511 lock=lock)
1505 1512 finally:
1506 1513 if lock is not None:
1507 1514 lock.release()
1508 1515
1509 1516 self.ui.debug("checking for updated bookmarks\n")
1510 1517 rb = remote.listkeys('bookmarks')
1511 1518 for k in rb.keys():
1512 1519 if k in self._bookmarks:
1513 1520 nr, nl = rb[k], hex(self._bookmarks[k])
1514 1521 if nr in self:
1515 1522 cr = self[nr]
1516 1523 cl = self[nl]
1517 1524 if cl in cr.descendants():
1518 1525 r = remote.pushkey('bookmarks', k, nr, nl)
1519 1526 if r:
1520 1527 self.ui.status(_("updating bookmark %s\n") % k)
1521 1528 else:
1522 1529 self.ui.warn(_('updating bookmark %s'
1523 1530 ' failed!\n') % k)
1524 1531
1525 1532 return ret
1526 1533
1527 1534 def changegroupinfo(self, nodes, source):
1528 1535 if self.ui.verbose or source == 'bundle':
1529 1536 self.ui.status(_("%d changesets found\n") % len(nodes))
1530 1537 if self.ui.debugflag:
1531 1538 self.ui.debug("list of changesets:\n")
1532 1539 for node in nodes:
1533 1540 self.ui.debug("%s\n" % hex(node))
1534 1541
1535 1542 def changegroupsubset(self, bases, heads, source):
1536 1543 """Compute a changegroup consisting of all the nodes that are
1537 1544 descendants of any of the bases and ancestors of any of the heads.
1538 1545 Return a chunkbuffer object whose read() method will return
1539 1546 successive changegroup chunks.
1540 1547
1541 1548 It is fairly complex as determining which filenodes and which
1542 1549 manifest nodes need to be included for the changeset to be complete
1543 1550 is non-trivial.
1544 1551
1545 1552 Another wrinkle is doing the reverse, figuring out which changeset in
1546 1553 the changegroup a particular filenode or manifestnode belongs to.
1547 1554 """
1548 1555 cl = self.changelog
1549 1556 if not bases:
1550 1557 bases = [nullid]
1551 1558 csets, bases, heads = cl.nodesbetween(bases, heads)
1552 1559 # We assume that all ancestors of bases are known
1553 1560 common = set(cl.ancestors(*[cl.rev(n) for n in bases]))
1554 1561 return self._changegroupsubset(common, csets, heads, source)
1555 1562
1556 1563 def getbundle(self, source, heads=None, common=None):
1557 1564 """Like changegroupsubset, but returns the set difference between the
1558 1565 ancestors of heads and the ancestors common.
1559 1566
1560 1567 If heads is None, use the local heads. If common is None, use [nullid].
1561 1568
1562 1569 The nodes in common might not all be known locally due to the way the
1563 1570 current discovery protocol works.
1564 1571 """
1565 1572 cl = self.changelog
1566 1573 if common:
1567 1574 nm = cl.nodemap
1568 1575 common = [n for n in common if n in nm]
1569 1576 else:
1570 1577 common = [nullid]
1571 1578 if not heads:
1572 1579 heads = cl.heads()
1573 1580 common, missing = cl.findcommonmissing(common, heads)
1574 1581 if not missing:
1575 1582 return None
1576 1583 return self._changegroupsubset(common, missing, heads, source)
1577 1584
1578 1585 def _changegroupsubset(self, commonrevs, csets, heads, source):
1579 1586
1580 1587 cl = self.changelog
1581 1588 mf = self.manifest
1582 1589 mfs = {} # needed manifests
1583 1590 fnodes = {} # needed file nodes
1584 1591 changedfiles = set()
1585 1592 fstate = ['', {}]
1586 1593 count = [0]
1587 1594
1588 1595 # can we go through the fast path ?
1589 1596 heads.sort()
1590 1597 if heads == sorted(self.heads()):
1591 1598 return self._changegroup(csets, source)
1592 1599
1593 1600 # slow path
1594 1601 self.hook('preoutgoing', throw=True, source=source)
1595 1602 self.changegroupinfo(csets, source)
1596 1603
1597 1604 # filter any nodes that claim to be part of the known set
1598 1605 def prune(revlog, missing):
1599 1606 return [n for n in missing
1600 1607 if revlog.linkrev(revlog.rev(n)) not in commonrevs]
1601 1608
1602 1609 def lookup(revlog, x):
1603 1610 if revlog == cl:
1604 1611 c = cl.read(x)
1605 1612 changedfiles.update(c[3])
1606 1613 mfs.setdefault(c[0], x)
1607 1614 count[0] += 1
1608 1615 self.ui.progress(_('bundling'), count[0],
1609 1616 unit=_('changesets'), total=len(csets))
1610 1617 return x
1611 1618 elif revlog == mf:
1612 1619 clnode = mfs[x]
1613 1620 mdata = mf.readfast(x)
1614 1621 for f in changedfiles:
1615 1622 if f in mdata:
1616 1623 fnodes.setdefault(f, {}).setdefault(mdata[f], clnode)
1617 1624 count[0] += 1
1618 1625 self.ui.progress(_('bundling'), count[0],
1619 1626 unit=_('manifests'), total=len(mfs))
1620 1627 return mfs[x]
1621 1628 else:
1622 1629 self.ui.progress(
1623 1630 _('bundling'), count[0], item=fstate[0],
1624 1631 unit=_('files'), total=len(changedfiles))
1625 1632 return fstate[1][x]
1626 1633
1627 1634 bundler = changegroup.bundle10(lookup)
1628 1635 reorder = self.ui.config('bundle', 'reorder', 'auto')
1629 1636 if reorder == 'auto':
1630 1637 reorder = None
1631 1638 else:
1632 1639 reorder = util.parsebool(reorder)
1633 1640
1634 1641 def gengroup():
1635 1642 # Create a changenode group generator that will call our functions
1636 1643 # back to lookup the owning changenode and collect information.
1637 1644 for chunk in cl.group(csets, bundler, reorder=reorder):
1638 1645 yield chunk
1639 1646 self.ui.progress(_('bundling'), None)
1640 1647
1641 1648 # Create a generator for the manifestnodes that calls our lookup
1642 1649 # and data collection functions back.
1643 1650 count[0] = 0
1644 1651 for chunk in mf.group(prune(mf, mfs), bundler, reorder=reorder):
1645 1652 yield chunk
1646 1653 self.ui.progress(_('bundling'), None)
1647 1654
1648 1655 mfs.clear()
1649 1656
1650 1657 # Go through all our files in order sorted by name.
1651 1658 count[0] = 0
1652 1659 for fname in sorted(changedfiles):
1653 1660 filerevlog = self.file(fname)
1654 1661 if not len(filerevlog):
1655 1662 raise util.Abort(_("empty or missing revlog for %s") % fname)
1656 1663 fstate[0] = fname
1657 1664 fstate[1] = fnodes.pop(fname, {})
1658 1665
1659 1666 nodelist = prune(filerevlog, fstate[1])
1660 1667 if nodelist:
1661 1668 count[0] += 1
1662 1669 yield bundler.fileheader(fname)
1663 1670 for chunk in filerevlog.group(nodelist, bundler, reorder):
1664 1671 yield chunk
1665 1672
1666 1673 # Signal that no more groups are left.
1667 1674 yield bundler.close()
1668 1675 self.ui.progress(_('bundling'), None)
1669 1676
1670 1677 if csets:
1671 1678 self.hook('outgoing', node=hex(csets[0]), source=source)
1672 1679
1673 1680 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1674 1681
1675 1682 def changegroup(self, basenodes, source):
1676 1683 # to avoid a race we use changegroupsubset() (issue1320)
1677 1684 return self.changegroupsubset(basenodes, self.heads(), source)
1678 1685
1679 1686 def _changegroup(self, nodes, source):
1680 1687 """Compute the changegroup of all nodes that we have that a recipient
1681 1688 doesn't. Return a chunkbuffer object whose read() method will return
1682 1689 successive changegroup chunks.
1683 1690
1684 1691 This is much easier than the previous function as we can assume that
1685 1692 the recipient has any changenode we aren't sending them.
1686 1693
1687 1694 nodes is the set of nodes to send"""
1688 1695
1689 1696 cl = self.changelog
1690 1697 mf = self.manifest
1691 1698 mfs = {}
1692 1699 changedfiles = set()
1693 1700 fstate = ['']
1694 1701 count = [0]
1695 1702
1696 1703 self.hook('preoutgoing', throw=True, source=source)
1697 1704 self.changegroupinfo(nodes, source)
1698 1705
1699 1706 revset = set([cl.rev(n) for n in nodes])
1700 1707
1701 1708 def gennodelst(log):
1702 1709 return [log.node(r) for r in log if log.linkrev(r) in revset]
1703 1710
1704 1711 def lookup(revlog, x):
1705 1712 if revlog == cl:
1706 1713 c = cl.read(x)
1707 1714 changedfiles.update(c[3])
1708 1715 mfs.setdefault(c[0], x)
1709 1716 count[0] += 1
1710 1717 self.ui.progress(_('bundling'), count[0],
1711 1718 unit=_('changesets'), total=len(nodes))
1712 1719 return x
1713 1720 elif revlog == mf:
1714 1721 count[0] += 1
1715 1722 self.ui.progress(_('bundling'), count[0],
1716 1723 unit=_('manifests'), total=len(mfs))
1717 1724 return cl.node(revlog.linkrev(revlog.rev(x)))
1718 1725 else:
1719 1726 self.ui.progress(
1720 1727 _('bundling'), count[0], item=fstate[0],
1721 1728 total=len(changedfiles), unit=_('files'))
1722 1729 return cl.node(revlog.linkrev(revlog.rev(x)))
1723 1730
1724 1731 bundler = changegroup.bundle10(lookup)
1725 1732 reorder = self.ui.config('bundle', 'reorder', 'auto')
1726 1733 if reorder == 'auto':
1727 1734 reorder = None
1728 1735 else:
1729 1736 reorder = util.parsebool(reorder)
1730 1737
1731 1738 def gengroup():
1732 1739 '''yield a sequence of changegroup chunks (strings)'''
1733 1740 # construct a list of all changed files
1734 1741
1735 1742 for chunk in cl.group(nodes, bundler, reorder=reorder):
1736 1743 yield chunk
1737 1744 self.ui.progress(_('bundling'), None)
1738 1745
1739 1746 count[0] = 0
1740 1747 for chunk in mf.group(gennodelst(mf), bundler, reorder=reorder):
1741 1748 yield chunk
1742 1749 self.ui.progress(_('bundling'), None)
1743 1750
1744 1751 count[0] = 0
1745 1752 for fname in sorted(changedfiles):
1746 1753 filerevlog = self.file(fname)
1747 1754 if not len(filerevlog):
1748 1755 raise util.Abort(_("empty or missing revlog for %s") % fname)
1749 1756 fstate[0] = fname
1750 1757 nodelist = gennodelst(filerevlog)
1751 1758 if nodelist:
1752 1759 count[0] += 1
1753 1760 yield bundler.fileheader(fname)
1754 1761 for chunk in filerevlog.group(nodelist, bundler, reorder):
1755 1762 yield chunk
1756 1763 yield bundler.close()
1757 1764 self.ui.progress(_('bundling'), None)
1758 1765
1759 1766 if nodes:
1760 1767 self.hook('outgoing', node=hex(nodes[0]), source=source)
1761 1768
1762 1769 return changegroup.unbundle10(util.chunkbuffer(gengroup()), 'UN')
1763 1770
1764 1771 def addchangegroup(self, source, srctype, url, emptyok=False, lock=None):
1765 1772 """Add the changegroup returned by source.read() to this repo.
1766 1773 srctype is a string like 'push', 'pull', or 'unbundle'. url is
1767 1774 the URL of the repo where this changegroup is coming from.
1768 1775 If lock is not None, the function takes ownership of the lock
1769 1776 and releases it after the changegroup is added.
1770 1777
1771 1778 Return an integer summarizing the change to this repo:
1772 1779 - nothing changed or no source: 0
1773 1780 - more heads than before: 1+added heads (2..n)
1774 1781 - fewer heads than before: -1-removed heads (-2..-n)
1775 1782 - number of heads stays the same: 1
1776 1783 """
1777 1784 def csmap(x):
1778 1785 self.ui.debug("add changeset %s\n" % short(x))
1779 1786 return len(cl)
1780 1787
1781 1788 def revmap(x):
1782 1789 return cl.rev(x)
1783 1790
1784 1791 if not source:
1785 1792 return 0
1786 1793
1787 1794 self.hook('prechangegroup', throw=True, source=srctype, url=url)
1788 1795
1789 1796 changesets = files = revisions = 0
1790 1797 efiles = set()
1791 1798
1792 1799 # write changelog data to temp files so concurrent readers will not see
1793 1800 # inconsistent view
1794 1801 cl = self.changelog
1795 1802 cl.delayupdate()
1796 1803 oldheads = cl.heads()
1797 1804
1798 1805 tr = self.transaction("\n".join([srctype, util.hidepassword(url)]))
1799 1806 try:
1800 1807 trp = weakref.proxy(tr)
1801 1808 # pull off the changeset group
1802 1809 self.ui.status(_("adding changesets\n"))
1803 1810 clstart = len(cl)
1804 1811 class prog(object):
1805 1812 step = _('changesets')
1806 1813 count = 1
1807 1814 ui = self.ui
1808 1815 total = None
1809 1816 def __call__(self):
1810 1817 self.ui.progress(self.step, self.count, unit=_('chunks'),
1811 1818 total=self.total)
1812 1819 self.count += 1
1813 1820 pr = prog()
1814 1821 source.callback = pr
1815 1822
1816 1823 source.changelogheader()
1817 1824 if (cl.addgroup(source, csmap, trp) is None
1818 1825 and not emptyok):
1819 1826 raise util.Abort(_("received changelog group is empty"))
1820 1827 clend = len(cl)
1821 1828 changesets = clend - clstart
1822 1829 for c in xrange(clstart, clend):
1823 1830 efiles.update(self[c].files())
1824 1831 efiles = len(efiles)
1825 1832 self.ui.progress(_('changesets'), None)
1826 1833
1827 1834 # pull off the manifest group
1828 1835 self.ui.status(_("adding manifests\n"))
1829 1836 pr.step = _('manifests')
1830 1837 pr.count = 1
1831 1838 pr.total = changesets # manifests <= changesets
1832 1839 # no need to check for empty manifest group here:
1833 1840 # if the result of the merge of 1 and 2 is the same in 3 and 4,
1834 1841 # no new manifest will be created and the manifest group will
1835 1842 # be empty during the pull
1836 1843 source.manifestheader()
1837 1844 self.manifest.addgroup(source, revmap, trp)
1838 1845 self.ui.progress(_('manifests'), None)
1839 1846
1840 1847 needfiles = {}
1841 1848 if self.ui.configbool('server', 'validate', default=False):
1842 1849 # validate incoming csets have their manifests
1843 1850 for cset in xrange(clstart, clend):
1844 1851 mfest = self.changelog.read(self.changelog.node(cset))[0]
1845 1852 mfest = self.manifest.readdelta(mfest)
1846 1853 # store file nodes we must see
1847 1854 for f, n in mfest.iteritems():
1848 1855 needfiles.setdefault(f, set()).add(n)
1849 1856
1850 1857 # process the files
1851 1858 self.ui.status(_("adding file changes\n"))
1852 1859 pr.step = _('files')
1853 1860 pr.count = 1
1854 1861 pr.total = efiles
1855 1862 source.callback = None
1856 1863
1857 1864 while True:
1858 1865 chunkdata = source.filelogheader()
1859 1866 if not chunkdata:
1860 1867 break
1861 1868 f = chunkdata["filename"]
1862 1869 self.ui.debug("adding %s revisions\n" % f)
1863 1870 pr()
1864 1871 fl = self.file(f)
1865 1872 o = len(fl)
1866 1873 if fl.addgroup(source, revmap, trp) is None:
1867 1874 raise util.Abort(_("received file revlog group is empty"))
1868 1875 revisions += len(fl) - o
1869 1876 files += 1
1870 1877 if f in needfiles:
1871 1878 needs = needfiles[f]
1872 1879 for new in xrange(o, len(fl)):
1873 1880 n = fl.node(new)
1874 1881 if n in needs:
1875 1882 needs.remove(n)
1876 1883 if not needs:
1877 1884 del needfiles[f]
1878 1885 self.ui.progress(_('files'), None)
1879 1886
1880 1887 for f, needs in needfiles.iteritems():
1881 1888 fl = self.file(f)
1882 1889 for n in needs:
1883 1890 try:
1884 1891 fl.rev(n)
1885 1892 except error.LookupError:
1886 1893 raise util.Abort(
1887 1894 _('missing file data for %s:%s - run hg verify') %
1888 1895 (f, hex(n)))
1889 1896
1890 1897 dh = 0
1891 1898 if oldheads:
1892 1899 heads = cl.heads()
1893 1900 dh = len(heads) - len(oldheads)
1894 1901 for h in heads:
1895 1902 if h not in oldheads and 'close' in self[h].extra():
1896 1903 dh -= 1
1897 1904 htext = ""
1898 1905 if dh:
1899 1906 htext = _(" (%+d heads)") % dh
1900 1907
1901 1908 self.ui.status(_("added %d changesets"
1902 1909 " with %d changes to %d files%s\n")
1903 1910 % (changesets, revisions, files, htext))
1904 1911
1905 1912 if changesets > 0:
1906 1913 p = lambda: cl.writepending() and self.root or ""
1907 1914 self.hook('pretxnchangegroup', throw=True,
1908 1915 node=hex(cl.node(clstart)), source=srctype,
1909 1916 url=url, pending=p)
1910 1917
1911 1918 # make changelog see real files again
1912 1919 cl.finalize(trp)
1913 1920
1914 1921 tr.close()
1915 1922 finally:
1916 1923 tr.release()
1917 1924 if lock:
1918 1925 lock.release()
1919 1926
1920 1927 if changesets > 0:
1921 1928 # forcefully update the on-disk branch cache
1922 1929 self.ui.debug("updating the branch cache\n")
1923 1930 self.updatebranchcache()
1924 1931 self.hook("changegroup", node=hex(cl.node(clstart)),
1925 1932 source=srctype, url=url)
1926 1933
1927 1934 for i in xrange(clstart, clend):
1928 1935 self.hook("incoming", node=hex(cl.node(i)),
1929 1936 source=srctype, url=url)
1930 1937
1931 1938 # never return 0 here:
1932 1939 if dh < 0:
1933 1940 return dh - 1
1934 1941 else:
1935 1942 return dh + 1
1936 1943
1937 1944 def stream_in(self, remote, requirements):
1938 1945 lock = self.lock()
1939 1946 try:
1940 1947 fp = remote.stream_out()
1941 1948 l = fp.readline()
1942 1949 try:
1943 1950 resp = int(l)
1944 1951 except ValueError:
1945 1952 raise error.ResponseError(
1946 1953 _('Unexpected response from remote server:'), l)
1947 1954 if resp == 1:
1948 1955 raise util.Abort(_('operation forbidden by server'))
1949 1956 elif resp == 2:
1950 1957 raise util.Abort(_('locking the remote repository failed'))
1951 1958 elif resp != 0:
1952 1959 raise util.Abort(_('the server sent an unknown error code'))
1953 1960 self.ui.status(_('streaming all changes\n'))
1954 1961 l = fp.readline()
1955 1962 try:
1956 1963 total_files, total_bytes = map(int, l.split(' ', 1))
1957 1964 except (ValueError, TypeError):
1958 1965 raise error.ResponseError(
1959 1966 _('Unexpected response from remote server:'), l)
1960 1967 self.ui.status(_('%d files to transfer, %s of data\n') %
1961 1968 (total_files, util.bytecount(total_bytes)))
1962 1969 start = time.time()
1963 1970 for i in xrange(total_files):
1964 1971 # XXX doesn't support '\n' or '\r' in filenames
1965 1972 l = fp.readline()
1966 1973 try:
1967 1974 name, size = l.split('\0', 1)
1968 1975 size = int(size)
1969 1976 except (ValueError, TypeError):
1970 1977 raise error.ResponseError(
1971 1978 _('Unexpected response from remote server:'), l)
1972 1979 self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
1973 1980 # for backwards compat, name was partially encoded
1974 1981 ofp = self.sopener(store.decodedir(name), 'w')
1975 1982 for chunk in util.filechunkiter(fp, limit=size):
1976 1983 ofp.write(chunk)
1977 1984 ofp.close()
1978 1985 elapsed = time.time() - start
1979 1986 if elapsed <= 0:
1980 1987 elapsed = 0.001
1981 1988 self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1982 1989 (util.bytecount(total_bytes), elapsed,
1983 1990 util.bytecount(total_bytes / elapsed)))
1984 1991
1985 1992 # new requirements = old non-format requirements + new format-related
1986 1993 # requirements from the streamed-in repository
1987 1994 requirements.update(set(self.requirements) - self.supportedformats)
1988 1995 self._applyrequirements(requirements)
1989 1996 self._writerequirements()
1990 1997
1991 1998 self.invalidate()
1992 1999 return len(self.heads()) + 1
1993 2000 finally:
1994 2001 lock.release()
1995 2002
1996 2003 def clone(self, remote, heads=[], stream=False):
1997 2004 '''clone remote repository.
1998 2005
1999 2006 keyword arguments:
2000 2007 heads: list of revs to clone (forces use of pull)
2001 2008 stream: use streaming clone if possible'''
2002 2009
2003 2010 # now, all clients that can request uncompressed clones can
2004 2011 # read repo formats supported by all servers that can serve
2005 2012 # them.
2006 2013
2007 2014 # if revlog format changes, client will have to check version
2008 2015 # and format flags on "stream" capability, and use
2009 2016 # uncompressed only if compatible.
2010 2017
2011 2018 if stream and not heads:
2012 2019 # 'stream' means remote revlog format is revlogv1 only
2013 2020 if remote.capable('stream'):
2014 2021 return self.stream_in(remote, set(('revlogv1',)))
2015 2022 # otherwise, 'streamreqs' contains the remote revlog format
2016 2023 streamreqs = remote.capable('streamreqs')
2017 2024 if streamreqs:
2018 2025 streamreqs = set(streamreqs.split(','))
2019 2026 # if we support it, stream in and adjust our requirements
2020 2027 if not streamreqs - self.supportedformats:
2021 2028 return self.stream_in(remote, streamreqs)
2022 2029 return self.pull(remote, heads)
2023 2030
2024 2031 def pushkey(self, namespace, key, old, new):
2025 2032 self.hook('prepushkey', throw=True, namespace=namespace, key=key,
2026 2033 old=old, new=new)
2027 2034 ret = pushkey.push(self, namespace, key, old, new)
2028 2035 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2029 2036 ret=ret)
2030 2037 return ret
2031 2038
2032 2039 def listkeys(self, namespace):
2033 2040 self.hook('prelistkeys', throw=True, namespace=namespace)
2034 2041 values = pushkey.list(self, namespace)
2035 2042 self.hook('listkeys', namespace=namespace, values=values)
2036 2043 return values
2037 2044
2038 2045 def debugwireargs(self, one, two, three=None, four=None, five=None):
2039 2046 '''used to test argument passing over the wire'''
2040 2047 return "%s %s %s %s %s" % (one, two, three, four, five)
2041 2048
2042 2049 def savecommitmessage(self, text):
2043 2050 fp = self.opener('last-message.txt', 'wb')
2044 2051 try:
2045 2052 fp.write(text)
2046 2053 finally:
2047 2054 fp.close()
2048 2055 return self.pathto(fp.name[len(self.root)+1:])
2049 2056
2050 2057 # used to avoid circular references so destructors work
2051 2058 def aftertrans(files):
2052 2059 renamefiles = [tuple(t) for t in files]
2053 2060 def a():
2054 2061 for src, dest in renamefiles:
2055 2062 util.rename(src, dest)
2056 2063 return a
2057 2064
2058 2065 def undoname(fn):
2059 2066 base, name = os.path.split(fn)
2060 2067 assert name.startswith('journal')
2061 2068 return os.path.join(base, name.replace('journal', 'undo', 1))
2062 2069
2063 2070 def instance(ui, path, create):
2064 2071 return localrepository(ui, util.urllocalpath(path), create)
2065 2072
2066 2073 def islocal(path):
2067 2074 return True
@@ -1,1920 +1,1910 b''
1 1 > do_push()
2 2 > {
3 3 > user=$1
4 4 > shift
5 5 > echo "Pushing as user $user"
6 6 > echo 'hgrc = """'
7 7 > sed -e 1,2d b/.hg/hgrc | grep -v fakegroups.py
8 8 > echo '"""'
9 9 > if test -f acl.config; then
10 10 > echo 'acl.config = """'
11 11 > cat acl.config
12 12 > echo '"""'
13 13 > fi
14 14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 15 > # LOGNAME=$user hg --cws a --debug push ../b
16 16 > # fails with "This variable is read only."
17 17 > # Use env to work around this.
18 18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 19 > hg --cwd b rollback
20 20 > hg --cwd b --quiet tip
21 21 > echo
22 22 > }
23 23
24 24 > init_config()
25 25 > {
26 26 > cat > fakegroups.py <<EOF
27 27 > from hgext import acl
28 28 > def fakegetusers(ui, group):
29 29 > try:
30 30 > return acl._getusersorig(ui, group)
31 31 > except:
32 32 > return ["fred", "betty"]
33 33 > acl._getusersorig = acl._getusers
34 34 > acl._getusers = fakegetusers
35 35 > EOF
36 36 > rm -f acl.config
37 37 > cat > $config <<EOF
38 38 > [hooks]
39 39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 40 > [acl]
41 41 > sources = push
42 42 > [extensions]
43 43 > f=`pwd`/fakegroups.py
44 44 > EOF
45 45 > }
46 46
47 47 $ hg init a
48 48 $ cd a
49 49 $ mkdir foo foo/Bar quux
50 50 $ echo 'in foo' > foo/file.txt
51 51 $ echo 'in foo/Bar' > foo/Bar/file.txt
52 52 $ echo 'in quux' > quux/file.py
53 53 $ hg add -q
54 54 $ hg ci -m 'add files' -d '1000000 0'
55 55 $ echo >> foo/file.txt
56 56 $ hg ci -m 'change foo/file' -d '1000001 0'
57 57 $ echo >> foo/Bar/file.txt
58 58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
59 59 $ echo >> quux/file.py
60 60 $ hg ci -m 'change quux/file' -d '1000003 0'
61 61 $ hg tip --quiet
62 62 3:911600dab2ae
63 63
64 64 $ cd ..
65 65 $ hg clone -r 0 a b
66 66 adding changesets
67 67 adding manifests
68 68 adding file changes
69 69 added 1 changesets with 3 changes to 3 files
70 70 updating to branch default
71 71 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 72
73 73 $ echo '[extensions]' >> $HGRCPATH
74 74 $ echo 'acl =' >> $HGRCPATH
75 75
76 76 $ config=b/.hg/hgrc
77 77
78 78 Extension disabled for lack of a hook
79 79
80 80 $ do_push fred
81 81 Pushing as user fred
82 82 hgrc = """
83 83 """
84 84 pushing to ../b
85 85 query 1; heads
86 86 searching for changes
87 87 all remote heads known locally
88 88 3 changesets found
89 89 list of changesets:
90 90 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
91 91 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
92 92 911600dab2ae7a9baff75958b84fe606851ce955
93 93 adding changesets
94 94 bundling: 1/3 changesets (33.33%)
95 95 bundling: 2/3 changesets (66.67%)
96 96 bundling: 3/3 changesets (100.00%)
97 97 bundling: 1/3 manifests (33.33%)
98 98 bundling: 2/3 manifests (66.67%)
99 99 bundling: 3/3 manifests (100.00%)
100 100 bundling: foo/Bar/file.txt 1/3 files (33.33%)
101 101 bundling: foo/file.txt 2/3 files (66.67%)
102 102 bundling: quux/file.py 3/3 files (100.00%)
103 103 changesets: 1 chunks
104 104 add changeset ef1ea85a6374
105 105 changesets: 2 chunks
106 106 add changeset f9cafe1212c8
107 107 changesets: 3 chunks
108 108 add changeset 911600dab2ae
109 109 adding manifests
110 110 manifests: 1/3 chunks (33.33%)
111 111 manifests: 2/3 chunks (66.67%)
112 112 manifests: 3/3 chunks (100.00%)
113 113 adding file changes
114 114 adding foo/Bar/file.txt revisions
115 115 files: 1/3 chunks (33.33%)
116 116 adding foo/file.txt revisions
117 117 files: 2/3 chunks (66.67%)
118 118 adding quux/file.py revisions
119 119 files: 3/3 chunks (100.00%)
120 120 added 3 changesets with 3 changes to 3 files
121 121 updating the branch cache
122 122 checking for updated bookmarks
123 123 repository tip rolled back to revision 0 (undo push)
124 working directory now based on revision 0
125 124 0:6675d58eff77
126 125
127 126
128 127 $ echo '[hooks]' >> $config
129 128 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
130 129
131 130 Extension disabled for lack of acl.sources
132 131
133 132 $ do_push fred
134 133 Pushing as user fred
135 134 hgrc = """
136 135 [hooks]
137 136 pretxnchangegroup.acl = python:hgext.acl.hook
138 137 """
139 138 pushing to ../b
140 139 query 1; heads
141 140 searching for changes
142 141 all remote heads known locally
143 142 invalidating branch cache (tip differs)
144 143 3 changesets found
145 144 list of changesets:
146 145 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
147 146 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
148 147 911600dab2ae7a9baff75958b84fe606851ce955
149 148 adding changesets
150 149 bundling: 1/3 changesets (33.33%)
151 150 bundling: 2/3 changesets (66.67%)
152 151 bundling: 3/3 changesets (100.00%)
153 152 bundling: 1/3 manifests (33.33%)
154 153 bundling: 2/3 manifests (66.67%)
155 154 bundling: 3/3 manifests (100.00%)
156 155 bundling: foo/Bar/file.txt 1/3 files (33.33%)
157 156 bundling: foo/file.txt 2/3 files (66.67%)
158 157 bundling: quux/file.py 3/3 files (100.00%)
159 158 changesets: 1 chunks
160 159 add changeset ef1ea85a6374
161 160 changesets: 2 chunks
162 161 add changeset f9cafe1212c8
163 162 changesets: 3 chunks
164 163 add changeset 911600dab2ae
165 164 adding manifests
166 165 manifests: 1/3 chunks (33.33%)
167 166 manifests: 2/3 chunks (66.67%)
168 167 manifests: 3/3 chunks (100.00%)
169 168 adding file changes
170 169 adding foo/Bar/file.txt revisions
171 170 files: 1/3 chunks (33.33%)
172 171 adding foo/file.txt revisions
173 172 files: 2/3 chunks (66.67%)
174 173 adding quux/file.py revisions
175 174 files: 3/3 chunks (100.00%)
176 175 added 3 changesets with 3 changes to 3 files
177 176 calling hook pretxnchangegroup.acl: hgext.acl.hook
178 177 acl: changes have source "push" - skipping
179 178 updating the branch cache
180 179 checking for updated bookmarks
181 180 repository tip rolled back to revision 0 (undo push)
182 working directory now based on revision 0
183 181 0:6675d58eff77
184 182
185 183
186 184 No [acl.allow]/[acl.deny]
187 185
188 186 $ echo '[acl]' >> $config
189 187 $ echo 'sources = push' >> $config
190 188 $ do_push fred
191 189 Pushing as user fred
192 190 hgrc = """
193 191 [hooks]
194 192 pretxnchangegroup.acl = python:hgext.acl.hook
195 193 [acl]
196 194 sources = push
197 195 """
198 196 pushing to ../b
199 197 query 1; heads
200 198 searching for changes
201 199 all remote heads known locally
202 200 invalidating branch cache (tip differs)
203 201 3 changesets found
204 202 list of changesets:
205 203 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
206 204 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
207 205 911600dab2ae7a9baff75958b84fe606851ce955
208 206 adding changesets
209 207 bundling: 1/3 changesets (33.33%)
210 208 bundling: 2/3 changesets (66.67%)
211 209 bundling: 3/3 changesets (100.00%)
212 210 bundling: 1/3 manifests (33.33%)
213 211 bundling: 2/3 manifests (66.67%)
214 212 bundling: 3/3 manifests (100.00%)
215 213 bundling: foo/Bar/file.txt 1/3 files (33.33%)
216 214 bundling: foo/file.txt 2/3 files (66.67%)
217 215 bundling: quux/file.py 3/3 files (100.00%)
218 216 changesets: 1 chunks
219 217 add changeset ef1ea85a6374
220 218 changesets: 2 chunks
221 219 add changeset f9cafe1212c8
222 220 changesets: 3 chunks
223 221 add changeset 911600dab2ae
224 222 adding manifests
225 223 manifests: 1/3 chunks (33.33%)
226 224 manifests: 2/3 chunks (66.67%)
227 225 manifests: 3/3 chunks (100.00%)
228 226 adding file changes
229 227 adding foo/Bar/file.txt revisions
230 228 files: 1/3 chunks (33.33%)
231 229 adding foo/file.txt revisions
232 230 files: 2/3 chunks (66.67%)
233 231 adding quux/file.py revisions
234 232 files: 3/3 chunks (100.00%)
235 233 added 3 changesets with 3 changes to 3 files
236 234 calling hook pretxnchangegroup.acl: hgext.acl.hook
237 235 acl: acl.allow.branches not enabled
238 236 acl: acl.deny.branches not enabled
239 237 acl: acl.allow not enabled
240 238 acl: acl.deny not enabled
241 239 acl: branch access granted: "ef1ea85a6374" on branch "default"
242 240 acl: allowing changeset ef1ea85a6374
243 241 acl: branch access granted: "f9cafe1212c8" on branch "default"
244 242 acl: allowing changeset f9cafe1212c8
245 243 acl: branch access granted: "911600dab2ae" on branch "default"
246 244 acl: allowing changeset 911600dab2ae
247 245 updating the branch cache
248 246 checking for updated bookmarks
249 247 repository tip rolled back to revision 0 (undo push)
250 working directory now based on revision 0
251 248 0:6675d58eff77
252 249
253 250
254 251 Empty [acl.allow]
255 252
256 253 $ echo '[acl.allow]' >> $config
257 254 $ do_push fred
258 255 Pushing as user fred
259 256 hgrc = """
260 257 [hooks]
261 258 pretxnchangegroup.acl = python:hgext.acl.hook
262 259 [acl]
263 260 sources = push
264 261 [acl.allow]
265 262 """
266 263 pushing to ../b
267 264 query 1; heads
268 265 searching for changes
269 266 all remote heads known locally
270 267 invalidating branch cache (tip differs)
271 268 3 changesets found
272 269 list of changesets:
273 270 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
274 271 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
275 272 911600dab2ae7a9baff75958b84fe606851ce955
276 273 adding changesets
277 274 bundling: 1/3 changesets (33.33%)
278 275 bundling: 2/3 changesets (66.67%)
279 276 bundling: 3/3 changesets (100.00%)
280 277 bundling: 1/3 manifests (33.33%)
281 278 bundling: 2/3 manifests (66.67%)
282 279 bundling: 3/3 manifests (100.00%)
283 280 bundling: foo/Bar/file.txt 1/3 files (33.33%)
284 281 bundling: foo/file.txt 2/3 files (66.67%)
285 282 bundling: quux/file.py 3/3 files (100.00%)
286 283 changesets: 1 chunks
287 284 add changeset ef1ea85a6374
288 285 changesets: 2 chunks
289 286 add changeset f9cafe1212c8
290 287 changesets: 3 chunks
291 288 add changeset 911600dab2ae
292 289 adding manifests
293 290 manifests: 1/3 chunks (33.33%)
294 291 manifests: 2/3 chunks (66.67%)
295 292 manifests: 3/3 chunks (100.00%)
296 293 adding file changes
297 294 adding foo/Bar/file.txt revisions
298 295 files: 1/3 chunks (33.33%)
299 296 adding foo/file.txt revisions
300 297 files: 2/3 chunks (66.67%)
301 298 adding quux/file.py revisions
302 299 files: 3/3 chunks (100.00%)
303 300 added 3 changesets with 3 changes to 3 files
304 301 calling hook pretxnchangegroup.acl: hgext.acl.hook
305 302 acl: acl.allow.branches not enabled
306 303 acl: acl.deny.branches not enabled
307 304 acl: acl.allow enabled, 0 entries for user fred
308 305 acl: acl.deny not enabled
309 306 acl: branch access granted: "ef1ea85a6374" on branch "default"
310 307 acl: user fred not allowed on foo/file.txt
311 308 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
312 309 transaction abort!
313 310 rollback completed
314 311 abort: acl: access denied for changeset ef1ea85a6374
315 312 no rollback information available
316 313 0:6675d58eff77
317 314
318 315
319 316 fred is allowed inside foo/
320 317
321 318 $ echo 'foo/** = fred' >> $config
322 319 $ do_push fred
323 320 Pushing as user fred
324 321 hgrc = """
325 322 [hooks]
326 323 pretxnchangegroup.acl = python:hgext.acl.hook
327 324 [acl]
328 325 sources = push
329 326 [acl.allow]
330 327 foo/** = fred
331 328 """
332 329 pushing to ../b
333 330 query 1; heads
334 331 searching for changes
335 332 all remote heads known locally
336 333 3 changesets found
337 334 list of changesets:
338 335 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
339 336 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
340 337 911600dab2ae7a9baff75958b84fe606851ce955
341 338 adding changesets
342 339 bundling: 1/3 changesets (33.33%)
343 340 bundling: 2/3 changesets (66.67%)
344 341 bundling: 3/3 changesets (100.00%)
345 342 bundling: 1/3 manifests (33.33%)
346 343 bundling: 2/3 manifests (66.67%)
347 344 bundling: 3/3 manifests (100.00%)
348 345 bundling: foo/Bar/file.txt 1/3 files (33.33%)
349 346 bundling: foo/file.txt 2/3 files (66.67%)
350 347 bundling: quux/file.py 3/3 files (100.00%)
351 348 changesets: 1 chunks
352 349 add changeset ef1ea85a6374
353 350 changesets: 2 chunks
354 351 add changeset f9cafe1212c8
355 352 changesets: 3 chunks
356 353 add changeset 911600dab2ae
357 354 adding manifests
358 355 manifests: 1/3 chunks (33.33%)
359 356 manifests: 2/3 chunks (66.67%)
360 357 manifests: 3/3 chunks (100.00%)
361 358 adding file changes
362 359 adding foo/Bar/file.txt revisions
363 360 files: 1/3 chunks (33.33%)
364 361 adding foo/file.txt revisions
365 362 files: 2/3 chunks (66.67%)
366 363 adding quux/file.py revisions
367 364 files: 3/3 chunks (100.00%)
368 365 added 3 changesets with 3 changes to 3 files
369 366 calling hook pretxnchangegroup.acl: hgext.acl.hook
370 367 acl: acl.allow.branches not enabled
371 368 acl: acl.deny.branches not enabled
372 369 acl: acl.allow enabled, 1 entries for user fred
373 370 acl: acl.deny not enabled
374 371 acl: branch access granted: "ef1ea85a6374" on branch "default"
375 372 acl: allowing changeset ef1ea85a6374
376 373 acl: branch access granted: "f9cafe1212c8" on branch "default"
377 374 acl: allowing changeset f9cafe1212c8
378 375 acl: branch access granted: "911600dab2ae" on branch "default"
379 376 acl: user fred not allowed on quux/file.py
380 377 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
381 378 transaction abort!
382 379 rollback completed
383 380 abort: acl: access denied for changeset 911600dab2ae
384 381 no rollback information available
385 382 0:6675d58eff77
386 383
387 384
388 385 Empty [acl.deny]
389 386
390 387 $ echo '[acl.deny]' >> $config
391 388 $ do_push barney
392 389 Pushing as user barney
393 390 hgrc = """
394 391 [hooks]
395 392 pretxnchangegroup.acl = python:hgext.acl.hook
396 393 [acl]
397 394 sources = push
398 395 [acl.allow]
399 396 foo/** = fred
400 397 [acl.deny]
401 398 """
402 399 pushing to ../b
403 400 query 1; heads
404 401 searching for changes
405 402 all remote heads known locally
406 403 3 changesets found
407 404 list of changesets:
408 405 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
409 406 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
410 407 911600dab2ae7a9baff75958b84fe606851ce955
411 408 adding changesets
412 409 bundling: 1/3 changesets (33.33%)
413 410 bundling: 2/3 changesets (66.67%)
414 411 bundling: 3/3 changesets (100.00%)
415 412 bundling: 1/3 manifests (33.33%)
416 413 bundling: 2/3 manifests (66.67%)
417 414 bundling: 3/3 manifests (100.00%)
418 415 bundling: foo/Bar/file.txt 1/3 files (33.33%)
419 416 bundling: foo/file.txt 2/3 files (66.67%)
420 417 bundling: quux/file.py 3/3 files (100.00%)
421 418 changesets: 1 chunks
422 419 add changeset ef1ea85a6374
423 420 changesets: 2 chunks
424 421 add changeset f9cafe1212c8
425 422 changesets: 3 chunks
426 423 add changeset 911600dab2ae
427 424 adding manifests
428 425 manifests: 1/3 chunks (33.33%)
429 426 manifests: 2/3 chunks (66.67%)
430 427 manifests: 3/3 chunks (100.00%)
431 428 adding file changes
432 429 adding foo/Bar/file.txt revisions
433 430 files: 1/3 chunks (33.33%)
434 431 adding foo/file.txt revisions
435 432 files: 2/3 chunks (66.67%)
436 433 adding quux/file.py revisions
437 434 files: 3/3 chunks (100.00%)
438 435 added 3 changesets with 3 changes to 3 files
439 436 calling hook pretxnchangegroup.acl: hgext.acl.hook
440 437 acl: acl.allow.branches not enabled
441 438 acl: acl.deny.branches not enabled
442 439 acl: acl.allow enabled, 0 entries for user barney
443 440 acl: acl.deny enabled, 0 entries for user barney
444 441 acl: branch access granted: "ef1ea85a6374" on branch "default"
445 442 acl: user barney not allowed on foo/file.txt
446 443 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
447 444 transaction abort!
448 445 rollback completed
449 446 abort: acl: access denied for changeset ef1ea85a6374
450 447 no rollback information available
451 448 0:6675d58eff77
452 449
453 450
454 451 fred is allowed inside foo/, but not foo/bar/ (case matters)
455 452
456 453 $ echo 'foo/bar/** = fred' >> $config
457 454 $ do_push fred
458 455 Pushing as user fred
459 456 hgrc = """
460 457 [hooks]
461 458 pretxnchangegroup.acl = python:hgext.acl.hook
462 459 [acl]
463 460 sources = push
464 461 [acl.allow]
465 462 foo/** = fred
466 463 [acl.deny]
467 464 foo/bar/** = fred
468 465 """
469 466 pushing to ../b
470 467 query 1; heads
471 468 searching for changes
472 469 all remote heads known locally
473 470 3 changesets found
474 471 list of changesets:
475 472 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
476 473 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
477 474 911600dab2ae7a9baff75958b84fe606851ce955
478 475 adding changesets
479 476 bundling: 1/3 changesets (33.33%)
480 477 bundling: 2/3 changesets (66.67%)
481 478 bundling: 3/3 changesets (100.00%)
482 479 bundling: 1/3 manifests (33.33%)
483 480 bundling: 2/3 manifests (66.67%)
484 481 bundling: 3/3 manifests (100.00%)
485 482 bundling: foo/Bar/file.txt 1/3 files (33.33%)
486 483 bundling: foo/file.txt 2/3 files (66.67%)
487 484 bundling: quux/file.py 3/3 files (100.00%)
488 485 changesets: 1 chunks
489 486 add changeset ef1ea85a6374
490 487 changesets: 2 chunks
491 488 add changeset f9cafe1212c8
492 489 changesets: 3 chunks
493 490 add changeset 911600dab2ae
494 491 adding manifests
495 492 manifests: 1/3 chunks (33.33%)
496 493 manifests: 2/3 chunks (66.67%)
497 494 manifests: 3/3 chunks (100.00%)
498 495 adding file changes
499 496 adding foo/Bar/file.txt revisions
500 497 files: 1/3 chunks (33.33%)
501 498 adding foo/file.txt revisions
502 499 files: 2/3 chunks (66.67%)
503 500 adding quux/file.py revisions
504 501 files: 3/3 chunks (100.00%)
505 502 added 3 changesets with 3 changes to 3 files
506 503 calling hook pretxnchangegroup.acl: hgext.acl.hook
507 504 acl: acl.allow.branches not enabled
508 505 acl: acl.deny.branches not enabled
509 506 acl: acl.allow enabled, 1 entries for user fred
510 507 acl: acl.deny enabled, 1 entries for user fred
511 508 acl: branch access granted: "ef1ea85a6374" on branch "default"
512 509 acl: allowing changeset ef1ea85a6374
513 510 acl: branch access granted: "f9cafe1212c8" on branch "default"
514 511 acl: allowing changeset f9cafe1212c8
515 512 acl: branch access granted: "911600dab2ae" on branch "default"
516 513 acl: user fred not allowed on quux/file.py
517 514 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
518 515 transaction abort!
519 516 rollback completed
520 517 abort: acl: access denied for changeset 911600dab2ae
521 518 no rollback information available
522 519 0:6675d58eff77
523 520
524 521
525 522 fred is allowed inside foo/, but not foo/Bar/
526 523
527 524 $ echo 'foo/Bar/** = fred' >> $config
528 525 $ do_push fred
529 526 Pushing as user fred
530 527 hgrc = """
531 528 [hooks]
532 529 pretxnchangegroup.acl = python:hgext.acl.hook
533 530 [acl]
534 531 sources = push
535 532 [acl.allow]
536 533 foo/** = fred
537 534 [acl.deny]
538 535 foo/bar/** = fred
539 536 foo/Bar/** = fred
540 537 """
541 538 pushing to ../b
542 539 query 1; heads
543 540 searching for changes
544 541 all remote heads known locally
545 542 3 changesets found
546 543 list of changesets:
547 544 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
548 545 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
549 546 911600dab2ae7a9baff75958b84fe606851ce955
550 547 adding changesets
551 548 bundling: 1/3 changesets (33.33%)
552 549 bundling: 2/3 changesets (66.67%)
553 550 bundling: 3/3 changesets (100.00%)
554 551 bundling: 1/3 manifests (33.33%)
555 552 bundling: 2/3 manifests (66.67%)
556 553 bundling: 3/3 manifests (100.00%)
557 554 bundling: foo/Bar/file.txt 1/3 files (33.33%)
558 555 bundling: foo/file.txt 2/3 files (66.67%)
559 556 bundling: quux/file.py 3/3 files (100.00%)
560 557 changesets: 1 chunks
561 558 add changeset ef1ea85a6374
562 559 changesets: 2 chunks
563 560 add changeset f9cafe1212c8
564 561 changesets: 3 chunks
565 562 add changeset 911600dab2ae
566 563 adding manifests
567 564 manifests: 1/3 chunks (33.33%)
568 565 manifests: 2/3 chunks (66.67%)
569 566 manifests: 3/3 chunks (100.00%)
570 567 adding file changes
571 568 adding foo/Bar/file.txt revisions
572 569 files: 1/3 chunks (33.33%)
573 570 adding foo/file.txt revisions
574 571 files: 2/3 chunks (66.67%)
575 572 adding quux/file.py revisions
576 573 files: 3/3 chunks (100.00%)
577 574 added 3 changesets with 3 changes to 3 files
578 575 calling hook pretxnchangegroup.acl: hgext.acl.hook
579 576 acl: acl.allow.branches not enabled
580 577 acl: acl.deny.branches not enabled
581 578 acl: acl.allow enabled, 1 entries for user fred
582 579 acl: acl.deny enabled, 2 entries for user fred
583 580 acl: branch access granted: "ef1ea85a6374" on branch "default"
584 581 acl: allowing changeset ef1ea85a6374
585 582 acl: branch access granted: "f9cafe1212c8" on branch "default"
586 583 acl: user fred denied on foo/Bar/file.txt
587 584 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
588 585 transaction abort!
589 586 rollback completed
590 587 abort: acl: access denied for changeset f9cafe1212c8
591 588 no rollback information available
592 589 0:6675d58eff77
593 590
594 591
595 592 $ echo 'barney is not mentioned => not allowed anywhere'
596 593 barney is not mentioned => not allowed anywhere
597 594 $ do_push barney
598 595 Pushing as user barney
599 596 hgrc = """
600 597 [hooks]
601 598 pretxnchangegroup.acl = python:hgext.acl.hook
602 599 [acl]
603 600 sources = push
604 601 [acl.allow]
605 602 foo/** = fred
606 603 [acl.deny]
607 604 foo/bar/** = fred
608 605 foo/Bar/** = fred
609 606 """
610 607 pushing to ../b
611 608 query 1; heads
612 609 searching for changes
613 610 all remote heads known locally
614 611 3 changesets found
615 612 list of changesets:
616 613 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
617 614 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
618 615 911600dab2ae7a9baff75958b84fe606851ce955
619 616 adding changesets
620 617 bundling: 1/3 changesets (33.33%)
621 618 bundling: 2/3 changesets (66.67%)
622 619 bundling: 3/3 changesets (100.00%)
623 620 bundling: 1/3 manifests (33.33%)
624 621 bundling: 2/3 manifests (66.67%)
625 622 bundling: 3/3 manifests (100.00%)
626 623 bundling: foo/Bar/file.txt 1/3 files (33.33%)
627 624 bundling: foo/file.txt 2/3 files (66.67%)
628 625 bundling: quux/file.py 3/3 files (100.00%)
629 626 changesets: 1 chunks
630 627 add changeset ef1ea85a6374
631 628 changesets: 2 chunks
632 629 add changeset f9cafe1212c8
633 630 changesets: 3 chunks
634 631 add changeset 911600dab2ae
635 632 adding manifests
636 633 manifests: 1/3 chunks (33.33%)
637 634 manifests: 2/3 chunks (66.67%)
638 635 manifests: 3/3 chunks (100.00%)
639 636 adding file changes
640 637 adding foo/Bar/file.txt revisions
641 638 files: 1/3 chunks (33.33%)
642 639 adding foo/file.txt revisions
643 640 files: 2/3 chunks (66.67%)
644 641 adding quux/file.py revisions
645 642 files: 3/3 chunks (100.00%)
646 643 added 3 changesets with 3 changes to 3 files
647 644 calling hook pretxnchangegroup.acl: hgext.acl.hook
648 645 acl: acl.allow.branches not enabled
649 646 acl: acl.deny.branches not enabled
650 647 acl: acl.allow enabled, 0 entries for user barney
651 648 acl: acl.deny enabled, 0 entries for user barney
652 649 acl: branch access granted: "ef1ea85a6374" on branch "default"
653 650 acl: user barney not allowed on foo/file.txt
654 651 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset ef1ea85a6374
655 652 transaction abort!
656 653 rollback completed
657 654 abort: acl: access denied for changeset ef1ea85a6374
658 655 no rollback information available
659 656 0:6675d58eff77
660 657
661 658
662 659 barney is allowed everywhere
663 660
664 661 $ echo '[acl.allow]' >> $config
665 662 $ echo '** = barney' >> $config
666 663 $ do_push barney
667 664 Pushing as user barney
668 665 hgrc = """
669 666 [hooks]
670 667 pretxnchangegroup.acl = python:hgext.acl.hook
671 668 [acl]
672 669 sources = push
673 670 [acl.allow]
674 671 foo/** = fred
675 672 [acl.deny]
676 673 foo/bar/** = fred
677 674 foo/Bar/** = fred
678 675 [acl.allow]
679 676 ** = barney
680 677 """
681 678 pushing to ../b
682 679 query 1; heads
683 680 searching for changes
684 681 all remote heads known locally
685 682 3 changesets found
686 683 list of changesets:
687 684 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
688 685 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
689 686 911600dab2ae7a9baff75958b84fe606851ce955
690 687 adding changesets
691 688 bundling: 1/3 changesets (33.33%)
692 689 bundling: 2/3 changesets (66.67%)
693 690 bundling: 3/3 changesets (100.00%)
694 691 bundling: 1/3 manifests (33.33%)
695 692 bundling: 2/3 manifests (66.67%)
696 693 bundling: 3/3 manifests (100.00%)
697 694 bundling: foo/Bar/file.txt 1/3 files (33.33%)
698 695 bundling: foo/file.txt 2/3 files (66.67%)
699 696 bundling: quux/file.py 3/3 files (100.00%)
700 697 changesets: 1 chunks
701 698 add changeset ef1ea85a6374
702 699 changesets: 2 chunks
703 700 add changeset f9cafe1212c8
704 701 changesets: 3 chunks
705 702 add changeset 911600dab2ae
706 703 adding manifests
707 704 manifests: 1/3 chunks (33.33%)
708 705 manifests: 2/3 chunks (66.67%)
709 706 manifests: 3/3 chunks (100.00%)
710 707 adding file changes
711 708 adding foo/Bar/file.txt revisions
712 709 files: 1/3 chunks (33.33%)
713 710 adding foo/file.txt revisions
714 711 files: 2/3 chunks (66.67%)
715 712 adding quux/file.py revisions
716 713 files: 3/3 chunks (100.00%)
717 714 added 3 changesets with 3 changes to 3 files
718 715 calling hook pretxnchangegroup.acl: hgext.acl.hook
719 716 acl: acl.allow.branches not enabled
720 717 acl: acl.deny.branches not enabled
721 718 acl: acl.allow enabled, 1 entries for user barney
722 719 acl: acl.deny enabled, 0 entries for user barney
723 720 acl: branch access granted: "ef1ea85a6374" on branch "default"
724 721 acl: allowing changeset ef1ea85a6374
725 722 acl: branch access granted: "f9cafe1212c8" on branch "default"
726 723 acl: allowing changeset f9cafe1212c8
727 724 acl: branch access granted: "911600dab2ae" on branch "default"
728 725 acl: allowing changeset 911600dab2ae
729 726 updating the branch cache
730 727 checking for updated bookmarks
731 728 repository tip rolled back to revision 0 (undo push)
732 working directory now based on revision 0
733 729 0:6675d58eff77
734 730
735 731
736 732 wilma can change files with a .txt extension
737 733
738 734 $ echo '**/*.txt = wilma' >> $config
739 735 $ do_push wilma
740 736 Pushing as user wilma
741 737 hgrc = """
742 738 [hooks]
743 739 pretxnchangegroup.acl = python:hgext.acl.hook
744 740 [acl]
745 741 sources = push
746 742 [acl.allow]
747 743 foo/** = fred
748 744 [acl.deny]
749 745 foo/bar/** = fred
750 746 foo/Bar/** = fred
751 747 [acl.allow]
752 748 ** = barney
753 749 **/*.txt = wilma
754 750 """
755 751 pushing to ../b
756 752 query 1; heads
757 753 searching for changes
758 754 all remote heads known locally
759 755 invalidating branch cache (tip differs)
760 756 3 changesets found
761 757 list of changesets:
762 758 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
763 759 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
764 760 911600dab2ae7a9baff75958b84fe606851ce955
765 761 adding changesets
766 762 bundling: 1/3 changesets (33.33%)
767 763 bundling: 2/3 changesets (66.67%)
768 764 bundling: 3/3 changesets (100.00%)
769 765 bundling: 1/3 manifests (33.33%)
770 766 bundling: 2/3 manifests (66.67%)
771 767 bundling: 3/3 manifests (100.00%)
772 768 bundling: foo/Bar/file.txt 1/3 files (33.33%)
773 769 bundling: foo/file.txt 2/3 files (66.67%)
774 770 bundling: quux/file.py 3/3 files (100.00%)
775 771 changesets: 1 chunks
776 772 add changeset ef1ea85a6374
777 773 changesets: 2 chunks
778 774 add changeset f9cafe1212c8
779 775 changesets: 3 chunks
780 776 add changeset 911600dab2ae
781 777 adding manifests
782 778 manifests: 1/3 chunks (33.33%)
783 779 manifests: 2/3 chunks (66.67%)
784 780 manifests: 3/3 chunks (100.00%)
785 781 adding file changes
786 782 adding foo/Bar/file.txt revisions
787 783 files: 1/3 chunks (33.33%)
788 784 adding foo/file.txt revisions
789 785 files: 2/3 chunks (66.67%)
790 786 adding quux/file.py revisions
791 787 files: 3/3 chunks (100.00%)
792 788 added 3 changesets with 3 changes to 3 files
793 789 calling hook pretxnchangegroup.acl: hgext.acl.hook
794 790 acl: acl.allow.branches not enabled
795 791 acl: acl.deny.branches not enabled
796 792 acl: acl.allow enabled, 1 entries for user wilma
797 793 acl: acl.deny enabled, 0 entries for user wilma
798 794 acl: branch access granted: "ef1ea85a6374" on branch "default"
799 795 acl: allowing changeset ef1ea85a6374
800 796 acl: branch access granted: "f9cafe1212c8" on branch "default"
801 797 acl: allowing changeset f9cafe1212c8
802 798 acl: branch access granted: "911600dab2ae" on branch "default"
803 799 acl: user wilma not allowed on quux/file.py
804 800 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
805 801 transaction abort!
806 802 rollback completed
807 803 abort: acl: access denied for changeset 911600dab2ae
808 804 no rollback information available
809 805 0:6675d58eff77
810 806
811 807
812 808 file specified by acl.config does not exist
813 809
814 810 $ echo '[acl]' >> $config
815 811 $ echo 'config = ../acl.config' >> $config
816 812 $ do_push barney
817 813 Pushing as user barney
818 814 hgrc = """
819 815 [hooks]
820 816 pretxnchangegroup.acl = python:hgext.acl.hook
821 817 [acl]
822 818 sources = push
823 819 [acl.allow]
824 820 foo/** = fred
825 821 [acl.deny]
826 822 foo/bar/** = fred
827 823 foo/Bar/** = fred
828 824 [acl.allow]
829 825 ** = barney
830 826 **/*.txt = wilma
831 827 [acl]
832 828 config = ../acl.config
833 829 """
834 830 pushing to ../b
835 831 query 1; heads
836 832 searching for changes
837 833 all remote heads known locally
838 834 3 changesets found
839 835 list of changesets:
840 836 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
841 837 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
842 838 911600dab2ae7a9baff75958b84fe606851ce955
843 839 adding changesets
844 840 bundling: 1/3 changesets (33.33%)
845 841 bundling: 2/3 changesets (66.67%)
846 842 bundling: 3/3 changesets (100.00%)
847 843 bundling: 1/3 manifests (33.33%)
848 844 bundling: 2/3 manifests (66.67%)
849 845 bundling: 3/3 manifests (100.00%)
850 846 bundling: foo/Bar/file.txt 1/3 files (33.33%)
851 847 bundling: foo/file.txt 2/3 files (66.67%)
852 848 bundling: quux/file.py 3/3 files (100.00%)
853 849 changesets: 1 chunks
854 850 add changeset ef1ea85a6374
855 851 changesets: 2 chunks
856 852 add changeset f9cafe1212c8
857 853 changesets: 3 chunks
858 854 add changeset 911600dab2ae
859 855 adding manifests
860 856 manifests: 1/3 chunks (33.33%)
861 857 manifests: 2/3 chunks (66.67%)
862 858 manifests: 3/3 chunks (100.00%)
863 859 adding file changes
864 860 adding foo/Bar/file.txt revisions
865 861 files: 1/3 chunks (33.33%)
866 862 adding foo/file.txt revisions
867 863 files: 2/3 chunks (66.67%)
868 864 adding quux/file.py revisions
869 865 files: 3/3 chunks (100.00%)
870 866 added 3 changesets with 3 changes to 3 files
871 867 calling hook pretxnchangegroup.acl: hgext.acl.hook
872 868 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
873 869 transaction abort!
874 870 rollback completed
875 871 abort: No such file or directory: ../acl.config
876 872 no rollback information available
877 873 0:6675d58eff77
878 874
879 875
880 876 betty is allowed inside foo/ by a acl.config file
881 877
882 878 $ echo '[acl.allow]' >> acl.config
883 879 $ echo 'foo/** = betty' >> acl.config
884 880 $ do_push betty
885 881 Pushing as user betty
886 882 hgrc = """
887 883 [hooks]
888 884 pretxnchangegroup.acl = python:hgext.acl.hook
889 885 [acl]
890 886 sources = push
891 887 [acl.allow]
892 888 foo/** = fred
893 889 [acl.deny]
894 890 foo/bar/** = fred
895 891 foo/Bar/** = fred
896 892 [acl.allow]
897 893 ** = barney
898 894 **/*.txt = wilma
899 895 [acl]
900 896 config = ../acl.config
901 897 """
902 898 acl.config = """
903 899 [acl.allow]
904 900 foo/** = betty
905 901 """
906 902 pushing to ../b
907 903 query 1; heads
908 904 searching for changes
909 905 all remote heads known locally
910 906 3 changesets found
911 907 list of changesets:
912 908 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
913 909 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
914 910 911600dab2ae7a9baff75958b84fe606851ce955
915 911 adding changesets
916 912 bundling: 1/3 changesets (33.33%)
917 913 bundling: 2/3 changesets (66.67%)
918 914 bundling: 3/3 changesets (100.00%)
919 915 bundling: 1/3 manifests (33.33%)
920 916 bundling: 2/3 manifests (66.67%)
921 917 bundling: 3/3 manifests (100.00%)
922 918 bundling: foo/Bar/file.txt 1/3 files (33.33%)
923 919 bundling: foo/file.txt 2/3 files (66.67%)
924 920 bundling: quux/file.py 3/3 files (100.00%)
925 921 changesets: 1 chunks
926 922 add changeset ef1ea85a6374
927 923 changesets: 2 chunks
928 924 add changeset f9cafe1212c8
929 925 changesets: 3 chunks
930 926 add changeset 911600dab2ae
931 927 adding manifests
932 928 manifests: 1/3 chunks (33.33%)
933 929 manifests: 2/3 chunks (66.67%)
934 930 manifests: 3/3 chunks (100.00%)
935 931 adding file changes
936 932 adding foo/Bar/file.txt revisions
937 933 files: 1/3 chunks (33.33%)
938 934 adding foo/file.txt revisions
939 935 files: 2/3 chunks (66.67%)
940 936 adding quux/file.py revisions
941 937 files: 3/3 chunks (100.00%)
942 938 added 3 changesets with 3 changes to 3 files
943 939 calling hook pretxnchangegroup.acl: hgext.acl.hook
944 940 acl: acl.allow.branches not enabled
945 941 acl: acl.deny.branches not enabled
946 942 acl: acl.allow enabled, 1 entries for user betty
947 943 acl: acl.deny enabled, 0 entries for user betty
948 944 acl: branch access granted: "ef1ea85a6374" on branch "default"
949 945 acl: allowing changeset ef1ea85a6374
950 946 acl: branch access granted: "f9cafe1212c8" on branch "default"
951 947 acl: allowing changeset f9cafe1212c8
952 948 acl: branch access granted: "911600dab2ae" on branch "default"
953 949 acl: user betty not allowed on quux/file.py
954 950 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset 911600dab2ae
955 951 transaction abort!
956 952 rollback completed
957 953 abort: acl: access denied for changeset 911600dab2ae
958 954 no rollback information available
959 955 0:6675d58eff77
960 956
961 957
962 958 acl.config can set only [acl.allow]/[acl.deny]
963 959
964 960 $ echo '[hooks]' >> acl.config
965 961 $ echo 'changegroup.acl = false' >> acl.config
966 962 $ do_push barney
967 963 Pushing as user barney
968 964 hgrc = """
969 965 [hooks]
970 966 pretxnchangegroup.acl = python:hgext.acl.hook
971 967 [acl]
972 968 sources = push
973 969 [acl.allow]
974 970 foo/** = fred
975 971 [acl.deny]
976 972 foo/bar/** = fred
977 973 foo/Bar/** = fred
978 974 [acl.allow]
979 975 ** = barney
980 976 **/*.txt = wilma
981 977 [acl]
982 978 config = ../acl.config
983 979 """
984 980 acl.config = """
985 981 [acl.allow]
986 982 foo/** = betty
987 983 [hooks]
988 984 changegroup.acl = false
989 985 """
990 986 pushing to ../b
991 987 query 1; heads
992 988 searching for changes
993 989 all remote heads known locally
994 990 3 changesets found
995 991 list of changesets:
996 992 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
997 993 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
998 994 911600dab2ae7a9baff75958b84fe606851ce955
999 995 adding changesets
1000 996 bundling: 1/3 changesets (33.33%)
1001 997 bundling: 2/3 changesets (66.67%)
1002 998 bundling: 3/3 changesets (100.00%)
1003 999 bundling: 1/3 manifests (33.33%)
1004 1000 bundling: 2/3 manifests (66.67%)
1005 1001 bundling: 3/3 manifests (100.00%)
1006 1002 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1007 1003 bundling: foo/file.txt 2/3 files (66.67%)
1008 1004 bundling: quux/file.py 3/3 files (100.00%)
1009 1005 changesets: 1 chunks
1010 1006 add changeset ef1ea85a6374
1011 1007 changesets: 2 chunks
1012 1008 add changeset f9cafe1212c8
1013 1009 changesets: 3 chunks
1014 1010 add changeset 911600dab2ae
1015 1011 adding manifests
1016 1012 manifests: 1/3 chunks (33.33%)
1017 1013 manifests: 2/3 chunks (66.67%)
1018 1014 manifests: 3/3 chunks (100.00%)
1019 1015 adding file changes
1020 1016 adding foo/Bar/file.txt revisions
1021 1017 files: 1/3 chunks (33.33%)
1022 1018 adding foo/file.txt revisions
1023 1019 files: 2/3 chunks (66.67%)
1024 1020 adding quux/file.py revisions
1025 1021 files: 3/3 chunks (100.00%)
1026 1022 added 3 changesets with 3 changes to 3 files
1027 1023 calling hook pretxnchangegroup.acl: hgext.acl.hook
1028 1024 acl: acl.allow.branches not enabled
1029 1025 acl: acl.deny.branches not enabled
1030 1026 acl: acl.allow enabled, 1 entries for user barney
1031 1027 acl: acl.deny enabled, 0 entries for user barney
1032 1028 acl: branch access granted: "ef1ea85a6374" on branch "default"
1033 1029 acl: allowing changeset ef1ea85a6374
1034 1030 acl: branch access granted: "f9cafe1212c8" on branch "default"
1035 1031 acl: allowing changeset f9cafe1212c8
1036 1032 acl: branch access granted: "911600dab2ae" on branch "default"
1037 1033 acl: allowing changeset 911600dab2ae
1038 1034 updating the branch cache
1039 1035 checking for updated bookmarks
1040 1036 repository tip rolled back to revision 0 (undo push)
1041 working directory now based on revision 0
1042 1037 0:6675d58eff77
1043 1038
1044 1039
1045 1040 asterisk
1046 1041
1047 1042 $ init_config
1048 1043
1049 1044 asterisk test
1050 1045
1051 1046 $ echo '[acl.allow]' >> $config
1052 1047 $ echo "** = fred" >> $config
1053 1048
1054 1049 fred is always allowed
1055 1050
1056 1051 $ do_push fred
1057 1052 Pushing as user fred
1058 1053 hgrc = """
1059 1054 [acl]
1060 1055 sources = push
1061 1056 [extensions]
1062 1057 [acl.allow]
1063 1058 ** = fred
1064 1059 """
1065 1060 pushing to ../b
1066 1061 query 1; heads
1067 1062 searching for changes
1068 1063 all remote heads known locally
1069 1064 invalidating branch cache (tip differs)
1070 1065 3 changesets found
1071 1066 list of changesets:
1072 1067 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1073 1068 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1074 1069 911600dab2ae7a9baff75958b84fe606851ce955
1075 1070 adding changesets
1076 1071 bundling: 1/3 changesets (33.33%)
1077 1072 bundling: 2/3 changesets (66.67%)
1078 1073 bundling: 3/3 changesets (100.00%)
1079 1074 bundling: 1/3 manifests (33.33%)
1080 1075 bundling: 2/3 manifests (66.67%)
1081 1076 bundling: 3/3 manifests (100.00%)
1082 1077 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1083 1078 bundling: foo/file.txt 2/3 files (66.67%)
1084 1079 bundling: quux/file.py 3/3 files (100.00%)
1085 1080 changesets: 1 chunks
1086 1081 add changeset ef1ea85a6374
1087 1082 changesets: 2 chunks
1088 1083 add changeset f9cafe1212c8
1089 1084 changesets: 3 chunks
1090 1085 add changeset 911600dab2ae
1091 1086 adding manifests
1092 1087 manifests: 1/3 chunks (33.33%)
1093 1088 manifests: 2/3 chunks (66.67%)
1094 1089 manifests: 3/3 chunks (100.00%)
1095 1090 adding file changes
1096 1091 adding foo/Bar/file.txt revisions
1097 1092 files: 1/3 chunks (33.33%)
1098 1093 adding foo/file.txt revisions
1099 1094 files: 2/3 chunks (66.67%)
1100 1095 adding quux/file.py revisions
1101 1096 files: 3/3 chunks (100.00%)
1102 1097 added 3 changesets with 3 changes to 3 files
1103 1098 calling hook pretxnchangegroup.acl: hgext.acl.hook
1104 1099 acl: acl.allow.branches not enabled
1105 1100 acl: acl.deny.branches not enabled
1106 1101 acl: acl.allow enabled, 1 entries for user fred
1107 1102 acl: acl.deny not enabled
1108 1103 acl: branch access granted: "ef1ea85a6374" on branch "default"
1109 1104 acl: allowing changeset ef1ea85a6374
1110 1105 acl: branch access granted: "f9cafe1212c8" on branch "default"
1111 1106 acl: allowing changeset f9cafe1212c8
1112 1107 acl: branch access granted: "911600dab2ae" on branch "default"
1113 1108 acl: allowing changeset 911600dab2ae
1114 1109 updating the branch cache
1115 1110 checking for updated bookmarks
1116 1111 repository tip rolled back to revision 0 (undo push)
1117 working directory now based on revision 0
1118 1112 0:6675d58eff77
1119 1113
1120 1114
1121 1115 $ echo '[acl.deny]' >> $config
1122 1116 $ echo "foo/Bar/** = *" >> $config
1123 1117
1124 1118 no one is allowed inside foo/Bar/
1125 1119
1126 1120 $ do_push fred
1127 1121 Pushing as user fred
1128 1122 hgrc = """
1129 1123 [acl]
1130 1124 sources = push
1131 1125 [extensions]
1132 1126 [acl.allow]
1133 1127 ** = fred
1134 1128 [acl.deny]
1135 1129 foo/Bar/** = *
1136 1130 """
1137 1131 pushing to ../b
1138 1132 query 1; heads
1139 1133 searching for changes
1140 1134 all remote heads known locally
1141 1135 invalidating branch cache (tip differs)
1142 1136 3 changesets found
1143 1137 list of changesets:
1144 1138 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1145 1139 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1146 1140 911600dab2ae7a9baff75958b84fe606851ce955
1147 1141 adding changesets
1148 1142 bundling: 1/3 changesets (33.33%)
1149 1143 bundling: 2/3 changesets (66.67%)
1150 1144 bundling: 3/3 changesets (100.00%)
1151 1145 bundling: 1/3 manifests (33.33%)
1152 1146 bundling: 2/3 manifests (66.67%)
1153 1147 bundling: 3/3 manifests (100.00%)
1154 1148 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1155 1149 bundling: foo/file.txt 2/3 files (66.67%)
1156 1150 bundling: quux/file.py 3/3 files (100.00%)
1157 1151 changesets: 1 chunks
1158 1152 add changeset ef1ea85a6374
1159 1153 changesets: 2 chunks
1160 1154 add changeset f9cafe1212c8
1161 1155 changesets: 3 chunks
1162 1156 add changeset 911600dab2ae
1163 1157 adding manifests
1164 1158 manifests: 1/3 chunks (33.33%)
1165 1159 manifests: 2/3 chunks (66.67%)
1166 1160 manifests: 3/3 chunks (100.00%)
1167 1161 adding file changes
1168 1162 adding foo/Bar/file.txt revisions
1169 1163 files: 1/3 chunks (33.33%)
1170 1164 adding foo/file.txt revisions
1171 1165 files: 2/3 chunks (66.67%)
1172 1166 adding quux/file.py revisions
1173 1167 files: 3/3 chunks (100.00%)
1174 1168 added 3 changesets with 3 changes to 3 files
1175 1169 calling hook pretxnchangegroup.acl: hgext.acl.hook
1176 1170 acl: acl.allow.branches not enabled
1177 1171 acl: acl.deny.branches not enabled
1178 1172 acl: acl.allow enabled, 1 entries for user fred
1179 1173 acl: acl.deny enabled, 1 entries for user fred
1180 1174 acl: branch access granted: "ef1ea85a6374" on branch "default"
1181 1175 acl: allowing changeset ef1ea85a6374
1182 1176 acl: branch access granted: "f9cafe1212c8" on branch "default"
1183 1177 acl: user fred denied on foo/Bar/file.txt
1184 1178 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1185 1179 transaction abort!
1186 1180 rollback completed
1187 1181 abort: acl: access denied for changeset f9cafe1212c8
1188 1182 no rollback information available
1189 1183 0:6675d58eff77
1190 1184
1191 1185
1192 1186 Groups
1193 1187
1194 1188 $ init_config
1195 1189
1196 1190 OS-level groups
1197 1191
1198 1192 $ echo '[acl.allow]' >> $config
1199 1193 $ echo "** = @group1" >> $config
1200 1194
1201 1195 @group1 is always allowed
1202 1196
1203 1197 $ do_push fred
1204 1198 Pushing as user fred
1205 1199 hgrc = """
1206 1200 [acl]
1207 1201 sources = push
1208 1202 [extensions]
1209 1203 [acl.allow]
1210 1204 ** = @group1
1211 1205 """
1212 1206 pushing to ../b
1213 1207 query 1; heads
1214 1208 searching for changes
1215 1209 all remote heads known locally
1216 1210 3 changesets found
1217 1211 list of changesets:
1218 1212 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1219 1213 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1220 1214 911600dab2ae7a9baff75958b84fe606851ce955
1221 1215 adding changesets
1222 1216 bundling: 1/3 changesets (33.33%)
1223 1217 bundling: 2/3 changesets (66.67%)
1224 1218 bundling: 3/3 changesets (100.00%)
1225 1219 bundling: 1/3 manifests (33.33%)
1226 1220 bundling: 2/3 manifests (66.67%)
1227 1221 bundling: 3/3 manifests (100.00%)
1228 1222 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1229 1223 bundling: foo/file.txt 2/3 files (66.67%)
1230 1224 bundling: quux/file.py 3/3 files (100.00%)
1231 1225 changesets: 1 chunks
1232 1226 add changeset ef1ea85a6374
1233 1227 changesets: 2 chunks
1234 1228 add changeset f9cafe1212c8
1235 1229 changesets: 3 chunks
1236 1230 add changeset 911600dab2ae
1237 1231 adding manifests
1238 1232 manifests: 1/3 chunks (33.33%)
1239 1233 manifests: 2/3 chunks (66.67%)
1240 1234 manifests: 3/3 chunks (100.00%)
1241 1235 adding file changes
1242 1236 adding foo/Bar/file.txt revisions
1243 1237 files: 1/3 chunks (33.33%)
1244 1238 adding foo/file.txt revisions
1245 1239 files: 2/3 chunks (66.67%)
1246 1240 adding quux/file.py revisions
1247 1241 files: 3/3 chunks (100.00%)
1248 1242 added 3 changesets with 3 changes to 3 files
1249 1243 calling hook pretxnchangegroup.acl: hgext.acl.hook
1250 1244 acl: acl.allow.branches not enabled
1251 1245 acl: acl.deny.branches not enabled
1252 1246 acl: "group1" not defined in [acl.groups]
1253 1247 acl: acl.allow enabled, 1 entries for user fred
1254 1248 acl: acl.deny not enabled
1255 1249 acl: branch access granted: "ef1ea85a6374" on branch "default"
1256 1250 acl: allowing changeset ef1ea85a6374
1257 1251 acl: branch access granted: "f9cafe1212c8" on branch "default"
1258 1252 acl: allowing changeset f9cafe1212c8
1259 1253 acl: branch access granted: "911600dab2ae" on branch "default"
1260 1254 acl: allowing changeset 911600dab2ae
1261 1255 updating the branch cache
1262 1256 checking for updated bookmarks
1263 1257 repository tip rolled back to revision 0 (undo push)
1264 working directory now based on revision 0
1265 1258 0:6675d58eff77
1266 1259
1267 1260
1268 1261 $ echo '[acl.deny]' >> $config
1269 1262 $ echo "foo/Bar/** = @group1" >> $config
1270 1263
1271 1264 @group is allowed inside anything but foo/Bar/
1272 1265
1273 1266 $ do_push fred
1274 1267 Pushing as user fred
1275 1268 hgrc = """
1276 1269 [acl]
1277 1270 sources = push
1278 1271 [extensions]
1279 1272 [acl.allow]
1280 1273 ** = @group1
1281 1274 [acl.deny]
1282 1275 foo/Bar/** = @group1
1283 1276 """
1284 1277 pushing to ../b
1285 1278 query 1; heads
1286 1279 searching for changes
1287 1280 all remote heads known locally
1288 1281 invalidating branch cache (tip differs)
1289 1282 3 changesets found
1290 1283 list of changesets:
1291 1284 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1292 1285 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1293 1286 911600dab2ae7a9baff75958b84fe606851ce955
1294 1287 adding changesets
1295 1288 bundling: 1/3 changesets (33.33%)
1296 1289 bundling: 2/3 changesets (66.67%)
1297 1290 bundling: 3/3 changesets (100.00%)
1298 1291 bundling: 1/3 manifests (33.33%)
1299 1292 bundling: 2/3 manifests (66.67%)
1300 1293 bundling: 3/3 manifests (100.00%)
1301 1294 bundling: foo/Bar/file.txt 1/3 files (33.33%)
1302 1295 bundling: foo/file.txt 2/3 files (66.67%)
1303 1296 bundling: quux/file.py 3/3 files (100.00%)
1304 1297 changesets: 1 chunks
1305 1298 add changeset ef1ea85a6374
1306 1299 changesets: 2 chunks
1307 1300 add changeset f9cafe1212c8
1308 1301 changesets: 3 chunks
1309 1302 add changeset 911600dab2ae
1310 1303 adding manifests
1311 1304 manifests: 1/3 chunks (33.33%)
1312 1305 manifests: 2/3 chunks (66.67%)
1313 1306 manifests: 3/3 chunks (100.00%)
1314 1307 adding file changes
1315 1308 adding foo/Bar/file.txt revisions
1316 1309 files: 1/3 chunks (33.33%)
1317 1310 adding foo/file.txt revisions
1318 1311 files: 2/3 chunks (66.67%)
1319 1312 adding quux/file.py revisions
1320 1313 files: 3/3 chunks (100.00%)
1321 1314 added 3 changesets with 3 changes to 3 files
1322 1315 calling hook pretxnchangegroup.acl: hgext.acl.hook
1323 1316 acl: acl.allow.branches not enabled
1324 1317 acl: acl.deny.branches not enabled
1325 1318 acl: "group1" not defined in [acl.groups]
1326 1319 acl: acl.allow enabled, 1 entries for user fred
1327 1320 acl: "group1" not defined in [acl.groups]
1328 1321 acl: acl.deny enabled, 1 entries for user fred
1329 1322 acl: branch access granted: "ef1ea85a6374" on branch "default"
1330 1323 acl: allowing changeset ef1ea85a6374
1331 1324 acl: branch access granted: "f9cafe1212c8" on branch "default"
1332 1325 acl: user fred denied on foo/Bar/file.txt
1333 1326 error: pretxnchangegroup.acl hook failed: acl: access denied for changeset f9cafe1212c8
1334 1327 transaction abort!
1335 1328 rollback completed
1336 1329 abort: acl: access denied for changeset f9cafe1212c8
1337 1330 no rollback information available
1338 1331 0:6675d58eff77
1339 1332
1340 1333
1341 1334 Invalid group
1342 1335
1343 1336 Disable the fakegroups trick to get real failures
1344 1337
1345 1338 $ grep -v fakegroups $config > config.tmp
1346 1339 $ mv config.tmp $config
1347 1340 $ echo '[acl.allow]' >> $config
1348 1341 $ echo "** = @unlikelytoexist" >> $config
1349 1342 $ do_push fred 2>&1 | grep unlikelytoexist
1350 1343 ** = @unlikelytoexist
1351 1344 acl: "unlikelytoexist" not defined in [acl.groups]
1352 1345 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1353 1346 abort: group 'unlikelytoexist' is undefined
1354 1347
1355 1348
1356 1349 Branch acl tests setup
1357 1350
1358 1351 $ init_config
1359 1352 $ cd b
1360 1353 $ hg up
1361 1354 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1362 1355 $ hg branch foobar
1363 1356 marked working directory as branch foobar
1364 1357 $ hg commit -m 'create foobar'
1365 1358 $ echo 'foo contents' > abc.txt
1366 1359 $ hg add abc.txt
1367 1360 $ hg commit -m 'foobar contents'
1368 1361 $ cd ..
1369 1362 $ hg --cwd a pull ../b
1370 1363 pulling from ../b
1371 1364 searching for changes
1372 1365 adding changesets
1373 1366 adding manifests
1374 1367 adding file changes
1375 1368 added 2 changesets with 1 changes to 1 files (+1 heads)
1376 1369 (run 'hg heads' to see heads)
1377 1370
1378 1371 Create additional changeset on foobar branch
1379 1372
1380 1373 $ cd a
1381 1374 $ hg up -C foobar
1382 1375 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1383 1376 $ echo 'foo contents2' > abc.txt
1384 1377 $ hg commit -m 'foobar contents2'
1385 1378 $ cd ..
1386 1379
1387 1380
1388 1381 No branch acls specified
1389 1382
1390 1383 $ do_push astro
1391 1384 Pushing as user astro
1392 1385 hgrc = """
1393 1386 [acl]
1394 1387 sources = push
1395 1388 [extensions]
1396 1389 """
1397 1390 pushing to ../b
1398 1391 query 1; heads
1399 1392 searching for changes
1400 1393 all remote heads known locally
1401 1394 4 changesets found
1402 1395 list of changesets:
1403 1396 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1404 1397 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1405 1398 911600dab2ae7a9baff75958b84fe606851ce955
1406 1399 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1407 1400 adding changesets
1408 1401 bundling: 1/4 changesets (25.00%)
1409 1402 bundling: 2/4 changesets (50.00%)
1410 1403 bundling: 3/4 changesets (75.00%)
1411 1404 bundling: 4/4 changesets (100.00%)
1412 1405 bundling: 1/4 manifests (25.00%)
1413 1406 bundling: 2/4 manifests (50.00%)
1414 1407 bundling: 3/4 manifests (75.00%)
1415 1408 bundling: 4/4 manifests (100.00%)
1416 1409 bundling: abc.txt 1/4 files (25.00%)
1417 1410 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1418 1411 bundling: foo/file.txt 3/4 files (75.00%)
1419 1412 bundling: quux/file.py 4/4 files (100.00%)
1420 1413 changesets: 1 chunks
1421 1414 add changeset ef1ea85a6374
1422 1415 changesets: 2 chunks
1423 1416 add changeset f9cafe1212c8
1424 1417 changesets: 3 chunks
1425 1418 add changeset 911600dab2ae
1426 1419 changesets: 4 chunks
1427 1420 add changeset e8fc755d4d82
1428 1421 adding manifests
1429 1422 manifests: 1/4 chunks (25.00%)
1430 1423 manifests: 2/4 chunks (50.00%)
1431 1424 manifests: 3/4 chunks (75.00%)
1432 1425 manifests: 4/4 chunks (100.00%)
1433 1426 adding file changes
1434 1427 adding abc.txt revisions
1435 1428 files: 1/4 chunks (25.00%)
1436 1429 adding foo/Bar/file.txt revisions
1437 1430 files: 2/4 chunks (50.00%)
1438 1431 adding foo/file.txt revisions
1439 1432 files: 3/4 chunks (75.00%)
1440 1433 adding quux/file.py revisions
1441 1434 files: 4/4 chunks (100.00%)
1442 1435 added 4 changesets with 4 changes to 4 files (+1 heads)
1443 1436 calling hook pretxnchangegroup.acl: hgext.acl.hook
1444 1437 acl: acl.allow.branches not enabled
1445 1438 acl: acl.deny.branches not enabled
1446 1439 acl: acl.allow not enabled
1447 1440 acl: acl.deny not enabled
1448 1441 acl: branch access granted: "ef1ea85a6374" on branch "default"
1449 1442 acl: allowing changeset ef1ea85a6374
1450 1443 acl: branch access granted: "f9cafe1212c8" on branch "default"
1451 1444 acl: allowing changeset f9cafe1212c8
1452 1445 acl: branch access granted: "911600dab2ae" on branch "default"
1453 1446 acl: allowing changeset 911600dab2ae
1454 1447 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1455 1448 acl: allowing changeset e8fc755d4d82
1456 1449 updating the branch cache
1457 1450 checking for updated bookmarks
1458 1451 repository tip rolled back to revision 2 (undo push)
1459 working directory now based on revision 2
1460 1452 2:fb35475503ef
1461 1453
1462 1454
1463 1455 Branch acl deny test
1464 1456
1465 1457 $ echo "[acl.deny.branches]" >> $config
1466 1458 $ echo "foobar = *" >> $config
1467 1459 $ do_push astro
1468 1460 Pushing as user astro
1469 1461 hgrc = """
1470 1462 [acl]
1471 1463 sources = push
1472 1464 [extensions]
1473 1465 [acl.deny.branches]
1474 1466 foobar = *
1475 1467 """
1476 1468 pushing to ../b
1477 1469 query 1; heads
1478 1470 searching for changes
1479 1471 all remote heads known locally
1480 1472 invalidating branch cache (tip differs)
1481 1473 4 changesets found
1482 1474 list of changesets:
1483 1475 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1484 1476 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1485 1477 911600dab2ae7a9baff75958b84fe606851ce955
1486 1478 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1487 1479 adding changesets
1488 1480 bundling: 1/4 changesets (25.00%)
1489 1481 bundling: 2/4 changesets (50.00%)
1490 1482 bundling: 3/4 changesets (75.00%)
1491 1483 bundling: 4/4 changesets (100.00%)
1492 1484 bundling: 1/4 manifests (25.00%)
1493 1485 bundling: 2/4 manifests (50.00%)
1494 1486 bundling: 3/4 manifests (75.00%)
1495 1487 bundling: 4/4 manifests (100.00%)
1496 1488 bundling: abc.txt 1/4 files (25.00%)
1497 1489 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1498 1490 bundling: foo/file.txt 3/4 files (75.00%)
1499 1491 bundling: quux/file.py 4/4 files (100.00%)
1500 1492 changesets: 1 chunks
1501 1493 add changeset ef1ea85a6374
1502 1494 changesets: 2 chunks
1503 1495 add changeset f9cafe1212c8
1504 1496 changesets: 3 chunks
1505 1497 add changeset 911600dab2ae
1506 1498 changesets: 4 chunks
1507 1499 add changeset e8fc755d4d82
1508 1500 adding manifests
1509 1501 manifests: 1/4 chunks (25.00%)
1510 1502 manifests: 2/4 chunks (50.00%)
1511 1503 manifests: 3/4 chunks (75.00%)
1512 1504 manifests: 4/4 chunks (100.00%)
1513 1505 adding file changes
1514 1506 adding abc.txt revisions
1515 1507 files: 1/4 chunks (25.00%)
1516 1508 adding foo/Bar/file.txt revisions
1517 1509 files: 2/4 chunks (50.00%)
1518 1510 adding foo/file.txt revisions
1519 1511 files: 3/4 chunks (75.00%)
1520 1512 adding quux/file.py revisions
1521 1513 files: 4/4 chunks (100.00%)
1522 1514 added 4 changesets with 4 changes to 4 files (+1 heads)
1523 1515 calling hook pretxnchangegroup.acl: hgext.acl.hook
1524 1516 acl: acl.allow.branches not enabled
1525 1517 acl: acl.deny.branches enabled, 1 entries for user astro
1526 1518 acl: acl.allow not enabled
1527 1519 acl: acl.deny not enabled
1528 1520 acl: branch access granted: "ef1ea85a6374" on branch "default"
1529 1521 acl: allowing changeset ef1ea85a6374
1530 1522 acl: branch access granted: "f9cafe1212c8" on branch "default"
1531 1523 acl: allowing changeset f9cafe1212c8
1532 1524 acl: branch access granted: "911600dab2ae" on branch "default"
1533 1525 acl: allowing changeset 911600dab2ae
1534 1526 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1535 1527 transaction abort!
1536 1528 rollback completed
1537 1529 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1538 1530 no rollback information available
1539 1531 2:fb35475503ef
1540 1532
1541 1533
1542 1534 Branch acl empty allow test
1543 1535
1544 1536 $ init_config
1545 1537 $ echo "[acl.allow.branches]" >> $config
1546 1538 $ do_push astro
1547 1539 Pushing as user astro
1548 1540 hgrc = """
1549 1541 [acl]
1550 1542 sources = push
1551 1543 [extensions]
1552 1544 [acl.allow.branches]
1553 1545 """
1554 1546 pushing to ../b
1555 1547 query 1; heads
1556 1548 searching for changes
1557 1549 all remote heads known locally
1558 1550 4 changesets found
1559 1551 list of changesets:
1560 1552 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1561 1553 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1562 1554 911600dab2ae7a9baff75958b84fe606851ce955
1563 1555 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1564 1556 adding changesets
1565 1557 bundling: 1/4 changesets (25.00%)
1566 1558 bundling: 2/4 changesets (50.00%)
1567 1559 bundling: 3/4 changesets (75.00%)
1568 1560 bundling: 4/4 changesets (100.00%)
1569 1561 bundling: 1/4 manifests (25.00%)
1570 1562 bundling: 2/4 manifests (50.00%)
1571 1563 bundling: 3/4 manifests (75.00%)
1572 1564 bundling: 4/4 manifests (100.00%)
1573 1565 bundling: abc.txt 1/4 files (25.00%)
1574 1566 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1575 1567 bundling: foo/file.txt 3/4 files (75.00%)
1576 1568 bundling: quux/file.py 4/4 files (100.00%)
1577 1569 changesets: 1 chunks
1578 1570 add changeset ef1ea85a6374
1579 1571 changesets: 2 chunks
1580 1572 add changeset f9cafe1212c8
1581 1573 changesets: 3 chunks
1582 1574 add changeset 911600dab2ae
1583 1575 changesets: 4 chunks
1584 1576 add changeset e8fc755d4d82
1585 1577 adding manifests
1586 1578 manifests: 1/4 chunks (25.00%)
1587 1579 manifests: 2/4 chunks (50.00%)
1588 1580 manifests: 3/4 chunks (75.00%)
1589 1581 manifests: 4/4 chunks (100.00%)
1590 1582 adding file changes
1591 1583 adding abc.txt revisions
1592 1584 files: 1/4 chunks (25.00%)
1593 1585 adding foo/Bar/file.txt revisions
1594 1586 files: 2/4 chunks (50.00%)
1595 1587 adding foo/file.txt revisions
1596 1588 files: 3/4 chunks (75.00%)
1597 1589 adding quux/file.py revisions
1598 1590 files: 4/4 chunks (100.00%)
1599 1591 added 4 changesets with 4 changes to 4 files (+1 heads)
1600 1592 calling hook pretxnchangegroup.acl: hgext.acl.hook
1601 1593 acl: acl.allow.branches enabled, 0 entries for user astro
1602 1594 acl: acl.deny.branches not enabled
1603 1595 acl: acl.allow not enabled
1604 1596 acl: acl.deny not enabled
1605 1597 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1606 1598 transaction abort!
1607 1599 rollback completed
1608 1600 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1609 1601 no rollback information available
1610 1602 2:fb35475503ef
1611 1603
1612 1604
1613 1605 Branch acl allow other
1614 1606
1615 1607 $ init_config
1616 1608 $ echo "[acl.allow.branches]" >> $config
1617 1609 $ echo "* = george" >> $config
1618 1610 $ do_push astro
1619 1611 Pushing as user astro
1620 1612 hgrc = """
1621 1613 [acl]
1622 1614 sources = push
1623 1615 [extensions]
1624 1616 [acl.allow.branches]
1625 1617 * = george
1626 1618 """
1627 1619 pushing to ../b
1628 1620 query 1; heads
1629 1621 searching for changes
1630 1622 all remote heads known locally
1631 1623 4 changesets found
1632 1624 list of changesets:
1633 1625 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1634 1626 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1635 1627 911600dab2ae7a9baff75958b84fe606851ce955
1636 1628 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1637 1629 adding changesets
1638 1630 bundling: 1/4 changesets (25.00%)
1639 1631 bundling: 2/4 changesets (50.00%)
1640 1632 bundling: 3/4 changesets (75.00%)
1641 1633 bundling: 4/4 changesets (100.00%)
1642 1634 bundling: 1/4 manifests (25.00%)
1643 1635 bundling: 2/4 manifests (50.00%)
1644 1636 bundling: 3/4 manifests (75.00%)
1645 1637 bundling: 4/4 manifests (100.00%)
1646 1638 bundling: abc.txt 1/4 files (25.00%)
1647 1639 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1648 1640 bundling: foo/file.txt 3/4 files (75.00%)
1649 1641 bundling: quux/file.py 4/4 files (100.00%)
1650 1642 changesets: 1 chunks
1651 1643 add changeset ef1ea85a6374
1652 1644 changesets: 2 chunks
1653 1645 add changeset f9cafe1212c8
1654 1646 changesets: 3 chunks
1655 1647 add changeset 911600dab2ae
1656 1648 changesets: 4 chunks
1657 1649 add changeset e8fc755d4d82
1658 1650 adding manifests
1659 1651 manifests: 1/4 chunks (25.00%)
1660 1652 manifests: 2/4 chunks (50.00%)
1661 1653 manifests: 3/4 chunks (75.00%)
1662 1654 manifests: 4/4 chunks (100.00%)
1663 1655 adding file changes
1664 1656 adding abc.txt revisions
1665 1657 files: 1/4 chunks (25.00%)
1666 1658 adding foo/Bar/file.txt revisions
1667 1659 files: 2/4 chunks (50.00%)
1668 1660 adding foo/file.txt revisions
1669 1661 files: 3/4 chunks (75.00%)
1670 1662 adding quux/file.py revisions
1671 1663 files: 4/4 chunks (100.00%)
1672 1664 added 4 changesets with 4 changes to 4 files (+1 heads)
1673 1665 calling hook pretxnchangegroup.acl: hgext.acl.hook
1674 1666 acl: acl.allow.branches enabled, 0 entries for user astro
1675 1667 acl: acl.deny.branches not enabled
1676 1668 acl: acl.allow not enabled
1677 1669 acl: acl.deny not enabled
1678 1670 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1679 1671 transaction abort!
1680 1672 rollback completed
1681 1673 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1682 1674 no rollback information available
1683 1675 2:fb35475503ef
1684 1676
1685 1677 $ do_push george
1686 1678 Pushing as user george
1687 1679 hgrc = """
1688 1680 [acl]
1689 1681 sources = push
1690 1682 [extensions]
1691 1683 [acl.allow.branches]
1692 1684 * = george
1693 1685 """
1694 1686 pushing to ../b
1695 1687 query 1; heads
1696 1688 searching for changes
1697 1689 all remote heads known locally
1698 1690 4 changesets found
1699 1691 list of changesets:
1700 1692 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1701 1693 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1702 1694 911600dab2ae7a9baff75958b84fe606851ce955
1703 1695 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1704 1696 adding changesets
1705 1697 bundling: 1/4 changesets (25.00%)
1706 1698 bundling: 2/4 changesets (50.00%)
1707 1699 bundling: 3/4 changesets (75.00%)
1708 1700 bundling: 4/4 changesets (100.00%)
1709 1701 bundling: 1/4 manifests (25.00%)
1710 1702 bundling: 2/4 manifests (50.00%)
1711 1703 bundling: 3/4 manifests (75.00%)
1712 1704 bundling: 4/4 manifests (100.00%)
1713 1705 bundling: abc.txt 1/4 files (25.00%)
1714 1706 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1715 1707 bundling: foo/file.txt 3/4 files (75.00%)
1716 1708 bundling: quux/file.py 4/4 files (100.00%)
1717 1709 changesets: 1 chunks
1718 1710 add changeset ef1ea85a6374
1719 1711 changesets: 2 chunks
1720 1712 add changeset f9cafe1212c8
1721 1713 changesets: 3 chunks
1722 1714 add changeset 911600dab2ae
1723 1715 changesets: 4 chunks
1724 1716 add changeset e8fc755d4d82
1725 1717 adding manifests
1726 1718 manifests: 1/4 chunks (25.00%)
1727 1719 manifests: 2/4 chunks (50.00%)
1728 1720 manifests: 3/4 chunks (75.00%)
1729 1721 manifests: 4/4 chunks (100.00%)
1730 1722 adding file changes
1731 1723 adding abc.txt revisions
1732 1724 files: 1/4 chunks (25.00%)
1733 1725 adding foo/Bar/file.txt revisions
1734 1726 files: 2/4 chunks (50.00%)
1735 1727 adding foo/file.txt revisions
1736 1728 files: 3/4 chunks (75.00%)
1737 1729 adding quux/file.py revisions
1738 1730 files: 4/4 chunks (100.00%)
1739 1731 added 4 changesets with 4 changes to 4 files (+1 heads)
1740 1732 calling hook pretxnchangegroup.acl: hgext.acl.hook
1741 1733 acl: acl.allow.branches enabled, 1 entries for user george
1742 1734 acl: acl.deny.branches not enabled
1743 1735 acl: acl.allow not enabled
1744 1736 acl: acl.deny not enabled
1745 1737 acl: branch access granted: "ef1ea85a6374" on branch "default"
1746 1738 acl: allowing changeset ef1ea85a6374
1747 1739 acl: branch access granted: "f9cafe1212c8" on branch "default"
1748 1740 acl: allowing changeset f9cafe1212c8
1749 1741 acl: branch access granted: "911600dab2ae" on branch "default"
1750 1742 acl: allowing changeset 911600dab2ae
1751 1743 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1752 1744 acl: allowing changeset e8fc755d4d82
1753 1745 updating the branch cache
1754 1746 checking for updated bookmarks
1755 1747 repository tip rolled back to revision 2 (undo push)
1756 working directory now based on revision 2
1757 1748 2:fb35475503ef
1758 1749
1759 1750
1760 1751 Branch acl conflicting allow
1761 1752 asterisk ends up applying to all branches and allowing george to
1762 1753 push foobar into the remote
1763 1754
1764 1755 $ init_config
1765 1756 $ echo "[acl.allow.branches]" >> $config
1766 1757 $ echo "foobar = astro" >> $config
1767 1758 $ echo "* = george" >> $config
1768 1759 $ do_push george
1769 1760 Pushing as user george
1770 1761 hgrc = """
1771 1762 [acl]
1772 1763 sources = push
1773 1764 [extensions]
1774 1765 [acl.allow.branches]
1775 1766 foobar = astro
1776 1767 * = george
1777 1768 """
1778 1769 pushing to ../b
1779 1770 query 1; heads
1780 1771 searching for changes
1781 1772 all remote heads known locally
1782 1773 invalidating branch cache (tip differs)
1783 1774 4 changesets found
1784 1775 list of changesets:
1785 1776 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1786 1777 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1787 1778 911600dab2ae7a9baff75958b84fe606851ce955
1788 1779 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1789 1780 adding changesets
1790 1781 bundling: 1/4 changesets (25.00%)
1791 1782 bundling: 2/4 changesets (50.00%)
1792 1783 bundling: 3/4 changesets (75.00%)
1793 1784 bundling: 4/4 changesets (100.00%)
1794 1785 bundling: 1/4 manifests (25.00%)
1795 1786 bundling: 2/4 manifests (50.00%)
1796 1787 bundling: 3/4 manifests (75.00%)
1797 1788 bundling: 4/4 manifests (100.00%)
1798 1789 bundling: abc.txt 1/4 files (25.00%)
1799 1790 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1800 1791 bundling: foo/file.txt 3/4 files (75.00%)
1801 1792 bundling: quux/file.py 4/4 files (100.00%)
1802 1793 changesets: 1 chunks
1803 1794 add changeset ef1ea85a6374
1804 1795 changesets: 2 chunks
1805 1796 add changeset f9cafe1212c8
1806 1797 changesets: 3 chunks
1807 1798 add changeset 911600dab2ae
1808 1799 changesets: 4 chunks
1809 1800 add changeset e8fc755d4d82
1810 1801 adding manifests
1811 1802 manifests: 1/4 chunks (25.00%)
1812 1803 manifests: 2/4 chunks (50.00%)
1813 1804 manifests: 3/4 chunks (75.00%)
1814 1805 manifests: 4/4 chunks (100.00%)
1815 1806 adding file changes
1816 1807 adding abc.txt revisions
1817 1808 files: 1/4 chunks (25.00%)
1818 1809 adding foo/Bar/file.txt revisions
1819 1810 files: 2/4 chunks (50.00%)
1820 1811 adding foo/file.txt revisions
1821 1812 files: 3/4 chunks (75.00%)
1822 1813 adding quux/file.py revisions
1823 1814 files: 4/4 chunks (100.00%)
1824 1815 added 4 changesets with 4 changes to 4 files (+1 heads)
1825 1816 calling hook pretxnchangegroup.acl: hgext.acl.hook
1826 1817 acl: acl.allow.branches enabled, 1 entries for user george
1827 1818 acl: acl.deny.branches not enabled
1828 1819 acl: acl.allow not enabled
1829 1820 acl: acl.deny not enabled
1830 1821 acl: branch access granted: "ef1ea85a6374" on branch "default"
1831 1822 acl: allowing changeset ef1ea85a6374
1832 1823 acl: branch access granted: "f9cafe1212c8" on branch "default"
1833 1824 acl: allowing changeset f9cafe1212c8
1834 1825 acl: branch access granted: "911600dab2ae" on branch "default"
1835 1826 acl: allowing changeset 911600dab2ae
1836 1827 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1837 1828 acl: allowing changeset e8fc755d4d82
1838 1829 updating the branch cache
1839 1830 checking for updated bookmarks
1840 1831 repository tip rolled back to revision 2 (undo push)
1841 working directory now based on revision 2
1842 1832 2:fb35475503ef
1843 1833
1844 1834 Branch acl conflicting deny
1845 1835
1846 1836 $ init_config
1847 1837 $ echo "[acl.deny.branches]" >> $config
1848 1838 $ echo "foobar = astro" >> $config
1849 1839 $ echo "default = astro" >> $config
1850 1840 $ echo "* = george" >> $config
1851 1841 $ do_push george
1852 1842 Pushing as user george
1853 1843 hgrc = """
1854 1844 [acl]
1855 1845 sources = push
1856 1846 [extensions]
1857 1847 [acl.deny.branches]
1858 1848 foobar = astro
1859 1849 default = astro
1860 1850 * = george
1861 1851 """
1862 1852 pushing to ../b
1863 1853 query 1; heads
1864 1854 searching for changes
1865 1855 all remote heads known locally
1866 1856 invalidating branch cache (tip differs)
1867 1857 4 changesets found
1868 1858 list of changesets:
1869 1859 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1870 1860 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1871 1861 911600dab2ae7a9baff75958b84fe606851ce955
1872 1862 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1873 1863 adding changesets
1874 1864 bundling: 1/4 changesets (25.00%)
1875 1865 bundling: 2/4 changesets (50.00%)
1876 1866 bundling: 3/4 changesets (75.00%)
1877 1867 bundling: 4/4 changesets (100.00%)
1878 1868 bundling: 1/4 manifests (25.00%)
1879 1869 bundling: 2/4 manifests (50.00%)
1880 1870 bundling: 3/4 manifests (75.00%)
1881 1871 bundling: 4/4 manifests (100.00%)
1882 1872 bundling: abc.txt 1/4 files (25.00%)
1883 1873 bundling: foo/Bar/file.txt 2/4 files (50.00%)
1884 1874 bundling: foo/file.txt 3/4 files (75.00%)
1885 1875 bundling: quux/file.py 4/4 files (100.00%)
1886 1876 changesets: 1 chunks
1887 1877 add changeset ef1ea85a6374
1888 1878 changesets: 2 chunks
1889 1879 add changeset f9cafe1212c8
1890 1880 changesets: 3 chunks
1891 1881 add changeset 911600dab2ae
1892 1882 changesets: 4 chunks
1893 1883 add changeset e8fc755d4d82
1894 1884 adding manifests
1895 1885 manifests: 1/4 chunks (25.00%)
1896 1886 manifests: 2/4 chunks (50.00%)
1897 1887 manifests: 3/4 chunks (75.00%)
1898 1888 manifests: 4/4 chunks (100.00%)
1899 1889 adding file changes
1900 1890 adding abc.txt revisions
1901 1891 files: 1/4 chunks (25.00%)
1902 1892 adding foo/Bar/file.txt revisions
1903 1893 files: 2/4 chunks (50.00%)
1904 1894 adding foo/file.txt revisions
1905 1895 files: 3/4 chunks (75.00%)
1906 1896 adding quux/file.py revisions
1907 1897 files: 4/4 chunks (100.00%)
1908 1898 added 4 changesets with 4 changes to 4 files (+1 heads)
1909 1899 calling hook pretxnchangegroup.acl: hgext.acl.hook
1910 1900 acl: acl.allow.branches not enabled
1911 1901 acl: acl.deny.branches enabled, 1 entries for user george
1912 1902 acl: acl.allow not enabled
1913 1903 acl: acl.deny not enabled
1914 1904 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1915 1905 transaction abort!
1916 1906 rollback completed
1917 1907 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
1918 1908 no rollback information available
1919 1909 2:fb35475503ef
1920 1910
@@ -1,330 +1,326 b''
1 1 $ hg init test
2 2 $ cd test
3 3 $ hg unbundle $TESTDIR/bundles/remote.hg
4 4 adding changesets
5 5 adding manifests
6 6 adding file changes
7 7 added 9 changesets with 7 changes to 4 files (+1 heads)
8 8 (run 'hg heads' to see heads, 'hg merge' to merge)
9 9 $ hg up tip
10 10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 11 $ cd ..
12 12
13 13 $ for i in 0 1 2 3 4 5 6 7 8; do
14 14 > mkdir test-"$i"
15 15 > hg --cwd test-"$i" init
16 16 > hg -R test bundle -r "$i" test-"$i".hg test-"$i"
17 17 > cd test-"$i"
18 18 > hg unbundle ../test-"$i".hg
19 19 > hg verify
20 20 > hg tip -q
21 21 > cd ..
22 22 > done
23 23 searching for changes
24 24 1 changesets found
25 25 adding changesets
26 26 adding manifests
27 27 adding file changes
28 28 added 1 changesets with 1 changes to 1 files
29 29 (run 'hg update' to get a working copy)
30 30 checking changesets
31 31 checking manifests
32 32 crosschecking files in changesets and manifests
33 33 checking files
34 34 1 files, 1 changesets, 1 total revisions
35 35 0:bfaf4b5cbf01
36 36 searching for changes
37 37 2 changesets found
38 38 adding changesets
39 39 adding manifests
40 40 adding file changes
41 41 added 2 changesets with 2 changes to 1 files
42 42 (run 'hg update' to get a working copy)
43 43 checking changesets
44 44 checking manifests
45 45 crosschecking files in changesets and manifests
46 46 checking files
47 47 1 files, 2 changesets, 2 total revisions
48 48 1:21f32785131f
49 49 searching for changes
50 50 3 changesets found
51 51 adding changesets
52 52 adding manifests
53 53 adding file changes
54 54 added 3 changesets with 3 changes to 1 files
55 55 (run 'hg update' to get a working copy)
56 56 checking changesets
57 57 checking manifests
58 58 crosschecking files in changesets and manifests
59 59 checking files
60 60 1 files, 3 changesets, 3 total revisions
61 61 2:4ce51a113780
62 62 searching for changes
63 63 4 changesets found
64 64 adding changesets
65 65 adding manifests
66 66 adding file changes
67 67 added 4 changesets with 4 changes to 1 files
68 68 (run 'hg update' to get a working copy)
69 69 checking changesets
70 70 checking manifests
71 71 crosschecking files in changesets and manifests
72 72 checking files
73 73 1 files, 4 changesets, 4 total revisions
74 74 3:93ee6ab32777
75 75 searching for changes
76 76 2 changesets found
77 77 adding changesets
78 78 adding manifests
79 79 adding file changes
80 80 added 2 changesets with 2 changes to 1 files
81 81 (run 'hg update' to get a working copy)
82 82 checking changesets
83 83 checking manifests
84 84 crosschecking files in changesets and manifests
85 85 checking files
86 86 1 files, 2 changesets, 2 total revisions
87 87 1:c70afb1ee985
88 88 searching for changes
89 89 3 changesets found
90 90 adding changesets
91 91 adding manifests
92 92 adding file changes
93 93 added 3 changesets with 3 changes to 1 files
94 94 (run 'hg update' to get a working copy)
95 95 checking changesets
96 96 checking manifests
97 97 crosschecking files in changesets and manifests
98 98 checking files
99 99 1 files, 3 changesets, 3 total revisions
100 100 2:f03ae5a9b979
101 101 searching for changes
102 102 4 changesets found
103 103 adding changesets
104 104 adding manifests
105 105 adding file changes
106 106 added 4 changesets with 5 changes to 2 files
107 107 (run 'hg update' to get a working copy)
108 108 checking changesets
109 109 checking manifests
110 110 crosschecking files in changesets and manifests
111 111 checking files
112 112 2 files, 4 changesets, 5 total revisions
113 113 3:095cb14b1b4d
114 114 searching for changes
115 115 5 changesets found
116 116 adding changesets
117 117 adding manifests
118 118 adding file changes
119 119 added 5 changesets with 6 changes to 3 files
120 120 (run 'hg update' to get a working copy)
121 121 checking changesets
122 122 checking manifests
123 123 crosschecking files in changesets and manifests
124 124 checking files
125 125 3 files, 5 changesets, 6 total revisions
126 126 4:faa2e4234c7a
127 127 searching for changes
128 128 5 changesets found
129 129 adding changesets
130 130 adding manifests
131 131 adding file changes
132 132 added 5 changesets with 5 changes to 2 files
133 133 (run 'hg update' to get a working copy)
134 134 checking changesets
135 135 checking manifests
136 136 crosschecking files in changesets and manifests
137 137 checking files
138 138 2 files, 5 changesets, 5 total revisions
139 139 4:916f1afdef90
140 140 $ cd test-8
141 141 $ hg pull ../test-7
142 142 pulling from ../test-7
143 143 searching for changes
144 144 adding changesets
145 145 adding manifests
146 146 adding file changes
147 147 added 4 changesets with 2 changes to 3 files (+1 heads)
148 148 (run 'hg heads' to see heads, 'hg merge' to merge)
149 149 $ hg verify
150 150 checking changesets
151 151 checking manifests
152 152 crosschecking files in changesets and manifests
153 153 checking files
154 154 4 files, 9 changesets, 7 total revisions
155 155 $ hg rollback
156 156 repository tip rolled back to revision 4 (undo pull)
157 working directory now based on revision -1
158 157 $ cd ..
159 158
160 159 should fail
161 160
162 161 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg test-3
163 162 abort: --base is incompatible with specifying a destination
164 163 [255]
165 164 $ hg -R test bundle -r tip test-bundle-branch1.hg
166 165 abort: repository default-push not found!
167 166 [255]
168 167
169 168 $ hg -R test bundle --base 2 -r tip test-bundle-branch1.hg
170 169 2 changesets found
171 170 $ hg -R test bundle --base 2 -r 7 test-bundle-branch2.hg
172 171 4 changesets found
173 172 $ hg -R test bundle --base 2 test-bundle-all.hg
174 173 6 changesets found
175 174 $ hg -R test bundle --base 3 -r tip test-bundle-should-fail.hg
176 175 1 changesets found
177 176
178 177 empty bundle
179 178
180 179 $ hg -R test bundle --base 7 --base 8 test-bundle-empty.hg
181 180 no changes found
182 181 [1]
183 182
184 183 issue76 msg2163
185 184
186 185 $ hg -R test bundle --base 3 -r 3 -r 3 test-bundle-cset-3.hg
187 186 no changes found
188 187 [1]
189 188
190 189 Issue1910: 'hg bundle --base $head' does not exclude $head from
191 190 result
192 191
193 192 $ hg -R test bundle --base 7 test-bundle-cset-7.hg
194 193 4 changesets found
195 194
196 195 $ hg clone test-2 test-9
197 196 updating to branch default
198 197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 198 $ cd test-9
200 199
201 200 revision 2
202 201
203 202 $ hg tip -q
204 203 2:4ce51a113780
205 204 $ hg unbundle ../test-bundle-should-fail.hg
206 205 adding changesets
207 206 transaction abort!
208 207 rollback completed
209 208 abort: 00changelog.i@93ee6ab32777: unknown parent!
210 209 [255]
211 210
212 211 revision 2
213 212
214 213 $ hg tip -q
215 214 2:4ce51a113780
216 215 $ hg unbundle ../test-bundle-all.hg
217 216 adding changesets
218 217 adding manifests
219 218 adding file changes
220 219 added 6 changesets with 4 changes to 4 files (+1 heads)
221 220 (run 'hg heads' to see heads, 'hg merge' to merge)
222 221
223 222 revision 8
224 223
225 224 $ hg tip -q
226 225 8:916f1afdef90
227 226 $ hg verify
228 227 checking changesets
229 228 checking manifests
230 229 crosschecking files in changesets and manifests
231 230 checking files
232 231 4 files, 9 changesets, 7 total revisions
233 232 $ hg rollback
234 233 repository tip rolled back to revision 2 (undo unbundle)
235 working directory now based on revision 2
236 234
237 235 revision 2
238 236
239 237 $ hg tip -q
240 238 2:4ce51a113780
241 239 $ hg unbundle ../test-bundle-branch1.hg
242 240 adding changesets
243 241 adding manifests
244 242 adding file changes
245 243 added 2 changesets with 2 changes to 2 files
246 244 (run 'hg update' to get a working copy)
247 245
248 246 revision 4
249 247
250 248 $ hg tip -q
251 249 4:916f1afdef90
252 250 $ hg verify
253 251 checking changesets
254 252 checking manifests
255 253 crosschecking files in changesets and manifests
256 254 checking files
257 255 2 files, 5 changesets, 5 total revisions
258 256 $ hg rollback
259 257 repository tip rolled back to revision 2 (undo unbundle)
260 working directory now based on revision 2
261 258 $ hg unbundle ../test-bundle-branch2.hg
262 259 adding changesets
263 260 adding manifests
264 261 adding file changes
265 262 added 4 changesets with 3 changes to 3 files (+1 heads)
266 263 (run 'hg heads' to see heads, 'hg merge' to merge)
267 264
268 265 revision 6
269 266
270 267 $ hg tip -q
271 268 6:faa2e4234c7a
272 269 $ hg verify
273 270 checking changesets
274 271 checking manifests
275 272 crosschecking files in changesets and manifests
276 273 checking files
277 274 3 files, 7 changesets, 6 total revisions
278 275 $ hg rollback
279 276 repository tip rolled back to revision 2 (undo unbundle)
280 working directory now based on revision 2
281 277 $ hg unbundle ../test-bundle-cset-7.hg
282 278 adding changesets
283 279 adding manifests
284 280 adding file changes
285 281 added 2 changesets with 2 changes to 2 files
286 282 (run 'hg update' to get a working copy)
287 283
288 284 revision 4
289 285
290 286 $ hg tip -q
291 287 4:916f1afdef90
292 288 $ hg verify
293 289 checking changesets
294 290 checking manifests
295 291 crosschecking files in changesets and manifests
296 292 checking files
297 293 2 files, 5 changesets, 5 total revisions
298 294
299 295 $ cd ../test
300 296 $ hg merge 7
301 297 note: possible conflict - afile was renamed multiple times to:
302 298 anotherfile
303 299 adifferentfile
304 300 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 301 (branch merge, don't forget to commit)
306 302 $ hg ci -m merge
307 303 $ cd ..
308 304 $ hg -R test bundle --base 2 test-bundle-head.hg
309 305 7 changesets found
310 306 $ hg clone test-2 test-10
311 307 updating to branch default
312 308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 309 $ cd test-10
314 310 $ hg unbundle ../test-bundle-head.hg
315 311 adding changesets
316 312 adding manifests
317 313 adding file changes
318 314 added 7 changesets with 4 changes to 4 files
319 315 (run 'hg update' to get a working copy)
320 316
321 317 revision 9
322 318
323 319 $ hg tip -q
324 320 9:03fc0b0e347c
325 321 $ hg verify
326 322 checking changesets
327 323 checking manifests
328 324 crosschecking files in changesets and manifests
329 325 checking files
330 326 4 files, 10 changesets, 7 total revisions
@@ -1,577 +1,574 b''
1 1 Setting up test
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo 0 > afile
6 6 $ hg add afile
7 7 $ hg commit -m "0.0"
8 8 $ echo 1 >> afile
9 9 $ hg commit -m "0.1"
10 10 $ echo 2 >> afile
11 11 $ hg commit -m "0.2"
12 12 $ echo 3 >> afile
13 13 $ hg commit -m "0.3"
14 14 $ hg update -C 0
15 15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 16 $ echo 1 >> afile
17 17 $ hg commit -m "1.1"
18 18 created new head
19 19 $ echo 2 >> afile
20 20 $ hg commit -m "1.2"
21 21 $ echo "a line" > fred
22 22 $ echo 3 >> afile
23 23 $ hg add fred
24 24 $ hg commit -m "1.3"
25 25 $ hg mv afile adifferentfile
26 26 $ hg commit -m "1.3m"
27 27 $ hg update -C 3
28 28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 29 $ hg mv afile anotherfile
30 30 $ hg commit -m "0.3m"
31 31 $ hg verify
32 32 checking changesets
33 33 checking manifests
34 34 crosschecking files in changesets and manifests
35 35 checking files
36 36 4 files, 9 changesets, 7 total revisions
37 37 $ cd ..
38 38 $ hg init empty
39 39
40 40 Bundle --all
41 41
42 42 $ hg -R test bundle --all all.hg
43 43 9 changesets found
44 44
45 45 Bundle test to full.hg
46 46
47 47 $ hg -R test bundle full.hg empty
48 48 searching for changes
49 49 9 changesets found
50 50
51 51 Unbundle full.hg in test
52 52
53 53 $ hg -R test unbundle full.hg
54 54 adding changesets
55 55 adding manifests
56 56 adding file changes
57 57 added 0 changesets with 0 changes to 4 files
58 58 (run 'hg update' to get a working copy)
59 59
60 60 Verify empty
61 61
62 62 $ hg -R empty heads
63 63 [1]
64 64 $ hg -R empty verify
65 65 checking changesets
66 66 checking manifests
67 67 crosschecking files in changesets and manifests
68 68 checking files
69 69 0 files, 0 changesets, 0 total revisions
70 70
71 71 Pull full.hg into test (using --cwd)
72 72
73 73 $ hg --cwd test pull ../full.hg
74 74 pulling from ../full.hg
75 75 searching for changes
76 76 no changes found
77 77
78 78 Pull full.hg into empty (using --cwd)
79 79
80 80 $ hg --cwd empty pull ../full.hg
81 81 pulling from ../full.hg
82 82 requesting all changes
83 83 adding changesets
84 84 adding manifests
85 85 adding file changes
86 86 added 9 changesets with 7 changes to 4 files (+1 heads)
87 87 (run 'hg heads' to see heads, 'hg merge' to merge)
88 88
89 89 Rollback empty
90 90
91 91 $ hg -R empty rollback
92 92 repository tip rolled back to revision -1 (undo pull)
93 working directory now based on revision -1
94 93
95 94 Pull full.hg into empty again (using --cwd)
96 95
97 96 $ hg --cwd empty pull ../full.hg
98 97 pulling from ../full.hg
99 98 requesting all changes
100 99 adding changesets
101 100 adding manifests
102 101 adding file changes
103 102 added 9 changesets with 7 changes to 4 files (+1 heads)
104 103 (run 'hg heads' to see heads, 'hg merge' to merge)
105 104
106 105 Pull full.hg into test (using -R)
107 106
108 107 $ hg -R test pull full.hg
109 108 pulling from full.hg
110 109 searching for changes
111 110 no changes found
112 111
113 112 Pull full.hg into empty (using -R)
114 113
115 114 $ hg -R empty pull full.hg
116 115 pulling from full.hg
117 116 searching for changes
118 117 no changes found
119 118
120 119 Rollback empty
121 120
122 121 $ hg -R empty rollback
123 122 repository tip rolled back to revision -1 (undo pull)
124 working directory now based on revision -1
125 123
126 124 Pull full.hg into empty again (using -R)
127 125
128 126 $ hg -R empty pull full.hg
129 127 pulling from full.hg
130 128 requesting all changes
131 129 adding changesets
132 130 adding manifests
133 131 adding file changes
134 132 added 9 changesets with 7 changes to 4 files (+1 heads)
135 133 (run 'hg heads' to see heads, 'hg merge' to merge)
136 134
137 135 Log -R full.hg in fresh empty
138 136
139 137 $ rm -r empty
140 138 $ hg init empty
141 139 $ cd empty
142 140 $ hg -R bundle://../full.hg log
143 141 changeset: 8:aa35859c02ea
144 142 tag: tip
145 143 parent: 3:eebf5a27f8ca
146 144 user: test
147 145 date: Thu Jan 01 00:00:00 1970 +0000
148 146 summary: 0.3m
149 147
150 148 changeset: 7:a6a34bfa0076
151 149 user: test
152 150 date: Thu Jan 01 00:00:00 1970 +0000
153 151 summary: 1.3m
154 152
155 153 changeset: 6:7373c1169842
156 154 user: test
157 155 date: Thu Jan 01 00:00:00 1970 +0000
158 156 summary: 1.3
159 157
160 158 changeset: 5:1bb50a9436a7
161 159 user: test
162 160 date: Thu Jan 01 00:00:00 1970 +0000
163 161 summary: 1.2
164 162
165 163 changeset: 4:095197eb4973
166 164 parent: 0:f9ee2f85a263
167 165 user: test
168 166 date: Thu Jan 01 00:00:00 1970 +0000
169 167 summary: 1.1
170 168
171 169 changeset: 3:eebf5a27f8ca
172 170 user: test
173 171 date: Thu Jan 01 00:00:00 1970 +0000
174 172 summary: 0.3
175 173
176 174 changeset: 2:e38ba6f5b7e0
177 175 user: test
178 176 date: Thu Jan 01 00:00:00 1970 +0000
179 177 summary: 0.2
180 178
181 179 changeset: 1:34c2bf6b0626
182 180 user: test
183 181 date: Thu Jan 01 00:00:00 1970 +0000
184 182 summary: 0.1
185 183
186 184 changeset: 0:f9ee2f85a263
187 185 user: test
188 186 date: Thu Jan 01 00:00:00 1970 +0000
189 187 summary: 0.0
190 188
191 189 Make sure bundlerepo doesn't leak tempfiles (issue2491)
192 190
193 191 $ ls .hg
194 192 00changelog.i
195 193 cache
196 194 requires
197 195 store
198 196
199 197 Pull ../full.hg into empty (with hook)
200 198
201 199 $ echo '[hooks]' >> .hg/hgrc
202 200 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
203 201
204 202 doesn't work (yet ?)
205 203
206 204 hg -R bundle://../full.hg verify
207 205
208 206 $ hg pull bundle://../full.hg
209 207 pulling from bundle:../full.hg
210 208 requesting all changes
211 209 adding changesets
212 210 adding manifests
213 211 adding file changes
214 212 added 9 changesets with 7 changes to 4 files (+1 heads)
215 213 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:../full.hg
216 214 (run 'hg heads' to see heads, 'hg merge' to merge)
217 215
218 216 Rollback empty
219 217
220 218 $ hg rollback
221 219 repository tip rolled back to revision -1 (undo pull)
222 working directory now based on revision -1
223 220 $ cd ..
224 221
225 222 Log -R bundle:empty+full.hg
226 223
227 224 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
228 225 8 7 6 5 4 3 2 1 0
229 226
230 227 Pull full.hg into empty again (using -R; with hook)
231 228
232 229 $ hg -R empty pull full.hg
233 230 pulling from full.hg
234 231 requesting all changes
235 232 adding changesets
236 233 adding manifests
237 234 adding file changes
238 235 added 9 changesets with 7 changes to 4 files (+1 heads)
239 236 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_SOURCE=pull HG_URL=bundle:empty+full.hg
240 237 (run 'hg heads' to see heads, 'hg merge' to merge)
241 238
242 239 Create partial clones
243 240
244 241 $ rm -r empty
245 242 $ hg init empty
246 243 $ hg clone -r 3 test partial
247 244 adding changesets
248 245 adding manifests
249 246 adding file changes
250 247 added 4 changesets with 4 changes to 1 files
251 248 updating to branch default
252 249 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 250 $ hg clone partial partial2
254 251 updating to branch default
255 252 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 253 $ cd partial
257 254
258 255 Log -R full.hg in partial
259 256
260 257 $ hg -R bundle://../full.hg log
261 258 changeset: 8:aa35859c02ea
262 259 tag: tip
263 260 parent: 3:eebf5a27f8ca
264 261 user: test
265 262 date: Thu Jan 01 00:00:00 1970 +0000
266 263 summary: 0.3m
267 264
268 265 changeset: 7:a6a34bfa0076
269 266 user: test
270 267 date: Thu Jan 01 00:00:00 1970 +0000
271 268 summary: 1.3m
272 269
273 270 changeset: 6:7373c1169842
274 271 user: test
275 272 date: Thu Jan 01 00:00:00 1970 +0000
276 273 summary: 1.3
277 274
278 275 changeset: 5:1bb50a9436a7
279 276 user: test
280 277 date: Thu Jan 01 00:00:00 1970 +0000
281 278 summary: 1.2
282 279
283 280 changeset: 4:095197eb4973
284 281 parent: 0:f9ee2f85a263
285 282 user: test
286 283 date: Thu Jan 01 00:00:00 1970 +0000
287 284 summary: 1.1
288 285
289 286 changeset: 3:eebf5a27f8ca
290 287 user: test
291 288 date: Thu Jan 01 00:00:00 1970 +0000
292 289 summary: 0.3
293 290
294 291 changeset: 2:e38ba6f5b7e0
295 292 user: test
296 293 date: Thu Jan 01 00:00:00 1970 +0000
297 294 summary: 0.2
298 295
299 296 changeset: 1:34c2bf6b0626
300 297 user: test
301 298 date: Thu Jan 01 00:00:00 1970 +0000
302 299 summary: 0.1
303 300
304 301 changeset: 0:f9ee2f85a263
305 302 user: test
306 303 date: Thu Jan 01 00:00:00 1970 +0000
307 304 summary: 0.0
308 305
309 306
310 307 Incoming full.hg in partial
311 308
312 309 $ hg incoming bundle://../full.hg
313 310 comparing with bundle:../full.hg
314 311 searching for changes
315 312 changeset: 4:095197eb4973
316 313 parent: 0:f9ee2f85a263
317 314 user: test
318 315 date: Thu Jan 01 00:00:00 1970 +0000
319 316 summary: 1.1
320 317
321 318 changeset: 5:1bb50a9436a7
322 319 user: test
323 320 date: Thu Jan 01 00:00:00 1970 +0000
324 321 summary: 1.2
325 322
326 323 changeset: 6:7373c1169842
327 324 user: test
328 325 date: Thu Jan 01 00:00:00 1970 +0000
329 326 summary: 1.3
330 327
331 328 changeset: 7:a6a34bfa0076
332 329 user: test
333 330 date: Thu Jan 01 00:00:00 1970 +0000
334 331 summary: 1.3m
335 332
336 333 changeset: 8:aa35859c02ea
337 334 tag: tip
338 335 parent: 3:eebf5a27f8ca
339 336 user: test
340 337 date: Thu Jan 01 00:00:00 1970 +0000
341 338 summary: 0.3m
342 339
343 340
344 341 Outgoing -R full.hg vs partial2 in partial
345 342
346 343 $ hg -R bundle://../full.hg outgoing ../partial2
347 344 comparing with ../partial2
348 345 searching for changes
349 346 changeset: 4:095197eb4973
350 347 parent: 0:f9ee2f85a263
351 348 user: test
352 349 date: Thu Jan 01 00:00:00 1970 +0000
353 350 summary: 1.1
354 351
355 352 changeset: 5:1bb50a9436a7
356 353 user: test
357 354 date: Thu Jan 01 00:00:00 1970 +0000
358 355 summary: 1.2
359 356
360 357 changeset: 6:7373c1169842
361 358 user: test
362 359 date: Thu Jan 01 00:00:00 1970 +0000
363 360 summary: 1.3
364 361
365 362 changeset: 7:a6a34bfa0076
366 363 user: test
367 364 date: Thu Jan 01 00:00:00 1970 +0000
368 365 summary: 1.3m
369 366
370 367 changeset: 8:aa35859c02ea
371 368 tag: tip
372 369 parent: 3:eebf5a27f8ca
373 370 user: test
374 371 date: Thu Jan 01 00:00:00 1970 +0000
375 372 summary: 0.3m
376 373
377 374
378 375 Outgoing -R does-not-exist.hg vs partial2 in partial
379 376
380 377 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
381 378 abort: No such file or directory: ../does-not-exist.hg
382 379 [255]
383 380 $ cd ..
384 381
385 382 Direct clone from bundle (all-history)
386 383
387 384 $ hg clone full.hg full-clone
388 385 requesting all changes
389 386 adding changesets
390 387 adding manifests
391 388 adding file changes
392 389 added 9 changesets with 7 changes to 4 files (+1 heads)
393 390 updating to branch default
394 391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 392 $ hg -R full-clone heads
396 393 changeset: 8:aa35859c02ea
397 394 tag: tip
398 395 parent: 3:eebf5a27f8ca
399 396 user: test
400 397 date: Thu Jan 01 00:00:00 1970 +0000
401 398 summary: 0.3m
402 399
403 400 changeset: 7:a6a34bfa0076
404 401 user: test
405 402 date: Thu Jan 01 00:00:00 1970 +0000
406 403 summary: 1.3m
407 404
408 405 $ rm -r full-clone
409 406
410 407 When cloning from a non-copiable repository into '', do not
411 408 recurse infinitely (issue 2528)
412 409
413 410 $ hg clone full.hg ''
414 411 abort: No such file or directory
415 412 [255]
416 413
417 414 test for http://mercurial.selenic.com/bts/issue216
418 415
419 416 Unbundle incremental bundles into fresh empty in one go
420 417
421 418 $ rm -r empty
422 419 $ hg init empty
423 420 $ hg -R test bundle --base null -r 0 ../0.hg
424 421 1 changesets found
425 422 $ hg -R test bundle --base 0 -r 1 ../1.hg
426 423 1 changesets found
427 424 $ hg -R empty unbundle -u ../0.hg ../1.hg
428 425 adding changesets
429 426 adding manifests
430 427 adding file changes
431 428 added 1 changesets with 1 changes to 1 files
432 429 adding changesets
433 430 adding manifests
434 431 adding file changes
435 432 added 1 changesets with 1 changes to 1 files
436 433 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 434
438 435 test for 540d1059c802
439 436
440 437 test for 540d1059c802
441 438
442 439 $ hg init orig
443 440 $ cd orig
444 441 $ echo foo > foo
445 442 $ hg add foo
446 443 $ hg ci -m 'add foo'
447 444
448 445 $ hg clone . ../copy
449 446 updating to branch default
450 447 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 448 $ hg tag foo
452 449
453 450 $ cd ../copy
454 451 $ echo >> foo
455 452 $ hg ci -m 'change foo'
456 453 $ hg bundle ../bundle.hg ../orig
457 454 searching for changes
458 455 1 changesets found
459 456
460 457 $ cd ../orig
461 458 $ hg incoming ../bundle.hg
462 459 comparing with ../bundle.hg
463 460 searching for changes
464 461 changeset: 2:ed1b79f46b9a
465 462 tag: tip
466 463 parent: 0:bbd179dfa0a7
467 464 user: test
468 465 date: Thu Jan 01 00:00:00 1970 +0000
469 466 summary: change foo
470 467
471 468 $ cd ..
472 469
473 470 test bundle with # in the filename (issue2154):
474 471
475 472 $ cp bundle.hg 'test#bundle.hg'
476 473 $ cd orig
477 474 $ hg incoming '../test#bundle.hg'
478 475 comparing with ../test
479 476 abort: unknown revision 'bundle.hg'!
480 477 [255]
481 478
482 479 note that percent encoding is not handled:
483 480
484 481 $ hg incoming ../test%23bundle.hg
485 482 abort: repository ../test%23bundle.hg not found!
486 483 [255]
487 484 $ cd ..
488 485
489 486 test for http://mercurial.selenic.com/bts/issue1144
490 487
491 488 test that verify bundle does not traceback
492 489
493 490 partial history bundle, fails w/ unkown parent
494 491
495 492 $ hg -R bundle.hg verify
496 493 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
497 494 [255]
498 495
499 496 full history bundle, refuses to verify non-local repo
500 497
501 498 $ hg -R all.hg verify
502 499 abort: cannot verify bundle or remote repos
503 500 [255]
504 501
505 502 but, regular verify must continue to work
506 503
507 504 $ hg -R orig verify
508 505 checking changesets
509 506 checking manifests
510 507 crosschecking files in changesets and manifests
511 508 checking files
512 509 2 files, 2 changesets, 2 total revisions
513 510
514 511 diff against bundle
515 512
516 513 $ hg init b
517 514 $ cd b
518 515 $ hg -R ../all.hg diff -r tip
519 516 diff -r aa35859c02ea anotherfile
520 517 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
521 518 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
522 519 @@ -1,4 +0,0 @@
523 520 -0
524 521 -1
525 522 -2
526 523 -3
527 524 $ cd ..
528 525
529 526 bundle single branch
530 527
531 528 $ hg init branchy
532 529 $ cd branchy
533 530 $ echo a >a
534 531 $ hg ci -Ama
535 532 adding a
536 533 $ echo b >b
537 534 $ hg ci -Amb
538 535 adding b
539 536 $ echo b1 >b1
540 537 $ hg ci -Amb1
541 538 adding b1
542 539 $ hg up 0
543 540 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
544 541 $ echo c >c
545 542 $ hg ci -Amc
546 543 adding c
547 544 created new head
548 545 $ echo c1 >c1
549 546 $ hg ci -Amc1
550 547 adding c1
551 548 $ hg clone -q .#tip part
552 549
553 550 == bundling via incoming
554 551
555 552 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
556 553 comparing with .
557 554 searching for changes
558 555 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
559 556 5ece8e77363e2b5269e27c66828b72da29e4341a
560 557
561 558 == bundling
562 559
563 560 $ hg bundle bundle.hg part --debug
564 561 query 1; heads
565 562 searching for changes
566 563 all remote heads known locally
567 564 2 changesets found
568 565 list of changesets:
569 566 d2ae7f538514cd87c17547b0de4cea71fe1af9fb
570 567 5ece8e77363e2b5269e27c66828b72da29e4341a
571 568 bundling: 1/2 changesets (50.00%)
572 569 bundling: 2/2 changesets (100.00%)
573 570 bundling: 1/2 manifests (50.00%)
574 571 bundling: 2/2 manifests (100.00%)
575 572 bundling: b 1/2 files (50.00%)
576 573 bundling: b1 2/2 files (100.00%)
577 574
@@ -1,461 +1,460 b''
1 1
2 2 $ "$TESTDIR/hghave" cvs || exit 80
3 3 $ cvscall()
4 4 > {
5 5 > cvs -f "$@"
6 6 > }
7 7 $ hgcat()
8 8 > {
9 9 > hg --cwd src-hg cat -r tip "$1"
10 10 > }
11 11 $ echo "[extensions]" >> $HGRCPATH
12 12 $ echo "convert = " >> $HGRCPATH
13 13 $ echo "graphlog = " >> $HGRCPATH
14 14 $ cat > cvshooks.py <<EOF
15 15 > def cvslog(ui,repo,hooktype,log):
16 16 > print "%s hook: %d entries"%(hooktype,len(log))
17 17 >
18 18 > def cvschangesets(ui,repo,hooktype,changesets):
19 19 > print "%s hook: %d changesets"%(hooktype,len(changesets))
20 20 > EOF
21 21 $ hookpath=`pwd`
22 22 $ echo "[hooks]" >> $HGRCPATH
23 23 $ echo "cvslog=python:$hookpath/cvshooks.py:cvslog" >> $HGRCPATH
24 24 $ echo "cvschangesets=python:$hookpath/cvshooks.py:cvschangesets" >> $HGRCPATH
25 25
26 26 create cvs repository
27 27
28 28 $ mkdir cvsrepo
29 29 $ cd cvsrepo
30 30 $ CVSROOT=`pwd`
31 31 $ export CVSROOT
32 32 $ CVS_OPTIONS=-f
33 33 $ export CVS_OPTIONS
34 34 $ cd ..
35 35 $ cvscall -q -d "$CVSROOT" init
36 36
37 37 create source directory
38 38
39 39 $ mkdir src-temp
40 40 $ cd src-temp
41 41 $ echo a > a
42 42 $ mkdir b
43 43 $ cd b
44 44 $ echo c > c
45 45 $ cd ..
46 46
47 47 import source directory
48 48
49 49 $ cvscall -q import -m import src INITIAL start
50 50 N src/a
51 51 N src/b/c
52 52
53 53 No conflicts created by this import
54 54
55 55 $ cd ..
56 56
57 57 checkout source directory
58 58
59 59 $ cvscall -q checkout src
60 60 U src/a
61 61 U src/b/c
62 62
63 63 commit a new revision changing b/c
64 64
65 65 $ cd src
66 66 $ sleep 1
67 67 $ echo c >> b/c
68 68 $ cvscall -q commit -mci0 . | grep '<--'
69 69 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
70 70 $ cd ..
71 71
72 72 convert fresh repo
73 73
74 74 $ hg convert src src-hg
75 75 initializing destination src-hg repository
76 76 connecting to $TESTTMP/cvsrepo
77 77 scanning source...
78 78 collecting CVS rlog
79 79 5 log entries
80 80 cvslog hook: 5 entries
81 81 creating changesets
82 82 3 changeset entries
83 83 cvschangesets hook: 3 changesets
84 84 sorting...
85 85 converting...
86 86 2 Initial revision
87 87 1 import
88 88 0 ci0
89 89 updating tags
90 90 $ hgcat a
91 91 a
92 92 $ hgcat b/c
93 93 c
94 94 c
95 95
96 96 convert fresh repo with --filemap
97 97
98 98 $ echo include b/c > filemap
99 99 $ hg convert --filemap filemap src src-filemap
100 100 initializing destination src-filemap repository
101 101 connecting to $TESTTMP/cvsrepo
102 102 scanning source...
103 103 collecting CVS rlog
104 104 5 log entries
105 105 cvslog hook: 5 entries
106 106 creating changesets
107 107 3 changeset entries
108 108 cvschangesets hook: 3 changesets
109 109 sorting...
110 110 converting...
111 111 2 Initial revision
112 112 1 import
113 113 filtering out empty revision
114 114 repository tip rolled back to revision 0 (undo commit)
115 working directory now based on revision -1
116 115 0 ci0
117 116 updating tags
118 117 $ hgcat b/c
119 118 c
120 119 c
121 120 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
122 121 2 update tags files: .hgtags
123 122 1 ci0 files: b/c
124 123 0 Initial revision files: b/c
125 124
126 125 convert full repository (issue1649)
127 126
128 127 $ cvscall -q -d "$CVSROOT" checkout -d srcfull "." | grep -v CVSROOT
129 128 U srcfull/src/a
130 129 U srcfull/src/b/c
131 130 $ ls srcfull
132 131 CVS
133 132 CVSROOT
134 133 src
135 134 $ hg convert srcfull srcfull-hg \
136 135 > | grep -v 'log entries' | grep -v 'hook:' \
137 136 > | grep -v '^[0-3] .*' # filter instable changeset order
138 137 initializing destination srcfull-hg repository
139 138 connecting to $TESTTMP/cvsrepo
140 139 scanning source...
141 140 collecting CVS rlog
142 141 creating changesets
143 142 4 changeset entries
144 143 sorting...
145 144 converting...
146 145 updating tags
147 146 $ hg cat -r tip srcfull-hg/src/a
148 147 a
149 148 $ hg cat -r tip srcfull-hg/src/b/c
150 149 c
151 150 c
152 151
153 152 commit new file revisions
154 153
155 154 $ cd src
156 155 $ echo a >> a
157 156 $ echo c >> b/c
158 157 $ cvscall -q commit -mci1 . | grep '<--'
159 158 $TESTTMP/cvsrepo/src/a,v <-- a
160 159 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
161 160 $ cd ..
162 161
163 162 convert again
164 163
165 164 $ hg convert src src-hg
166 165 connecting to $TESTTMP/cvsrepo
167 166 scanning source...
168 167 collecting CVS rlog
169 168 7 log entries
170 169 cvslog hook: 7 entries
171 170 creating changesets
172 171 4 changeset entries
173 172 cvschangesets hook: 4 changesets
174 173 sorting...
175 174 converting...
176 175 0 ci1
177 176 $ hgcat a
178 177 a
179 178 a
180 179 $ hgcat b/c
181 180 c
182 181 c
183 182 c
184 183
185 184 convert again with --filemap
186 185
187 186 $ hg convert --filemap filemap src src-filemap
188 187 connecting to $TESTTMP/cvsrepo
189 188 scanning source...
190 189 collecting CVS rlog
191 190 7 log entries
192 191 cvslog hook: 7 entries
193 192 creating changesets
194 193 4 changeset entries
195 194 cvschangesets hook: 4 changesets
196 195 sorting...
197 196 converting...
198 197 0 ci1
199 198 $ hgcat b/c
200 199 c
201 200 c
202 201 c
203 202 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
204 203 3 ci1 files: b/c
205 204 2 update tags files: .hgtags
206 205 1 ci0 files: b/c
207 206 0 Initial revision files: b/c
208 207
209 208 commit branch
210 209
211 210 $ cd src
212 211 $ cvs -q update -r1.1 b/c
213 212 U b/c
214 213 $ cvs -q tag -b branch
215 214 T a
216 215 T b/c
217 216 $ cvs -q update -r branch > /dev/null
218 217 $ echo d >> b/c
219 218 $ cvs -q commit -mci2 . | grep '<--'
220 219 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
221 220 $ cd ..
222 221
223 222 convert again
224 223
225 224 $ hg convert src src-hg
226 225 connecting to $TESTTMP/cvsrepo
227 226 scanning source...
228 227 collecting CVS rlog
229 228 8 log entries
230 229 cvslog hook: 8 entries
231 230 creating changesets
232 231 5 changeset entries
233 232 cvschangesets hook: 5 changesets
234 233 sorting...
235 234 converting...
236 235 0 ci2
237 236 $ hgcat b/c
238 237 c
239 238 d
240 239
241 240 convert again with --filemap
242 241
243 242 $ hg convert --filemap filemap src src-filemap
244 243 connecting to $TESTTMP/cvsrepo
245 244 scanning source...
246 245 collecting CVS rlog
247 246 8 log entries
248 247 cvslog hook: 8 entries
249 248 creating changesets
250 249 5 changeset entries
251 250 cvschangesets hook: 5 changesets
252 251 sorting...
253 252 converting...
254 253 0 ci2
255 254 $ hgcat b/c
256 255 c
257 256 d
258 257 $ hg -R src-filemap log --template '{rev} {desc} files: {files}\n'
259 258 4 ci2 files: b/c
260 259 3 ci1 files: b/c
261 260 2 update tags files: .hgtags
262 261 1 ci0 files: b/c
263 262 0 Initial revision files: b/c
264 263
265 264 commit a new revision with funny log message
266 265
267 266 $ cd src
268 267 $ sleep 1
269 268 $ echo e >> a
270 269 $ cvscall -q commit -m'funny
271 270 > ----------------------------
272 271 > log message' . | grep '<--' |\
273 272 > sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g'
274 273 checking in src/a,v
275 274
276 275 commit new file revisions with some fuzz
277 276
278 277 $ sleep 1
279 278 $ echo f >> a
280 279 $ cvscall -q commit -mfuzzy . | grep '<--'
281 280 $TESTTMP/cvsrepo/src/a,v <-- a
282 281 $ sleep 4 # the two changes will be split if fuzz < 4
283 282 $ echo g >> b/c
284 283 $ cvscall -q commit -mfuzzy . | grep '<--'
285 284 $TESTTMP/cvsrepo/src/b/c,v <-- *c (glob)
286 285 $ cd ..
287 286
288 287 convert again
289 288
290 289 $ hg convert --config convert.cvsps.fuzz=2 src src-hg
291 290 connecting to $TESTTMP/cvsrepo
292 291 scanning source...
293 292 collecting CVS rlog
294 293 11 log entries
295 294 cvslog hook: 11 entries
296 295 creating changesets
297 296 8 changeset entries
298 297 cvschangesets hook: 8 changesets
299 298 sorting...
300 299 converting...
301 300 2 funny
302 301 1 fuzzy
303 302 0 fuzzy
304 303 $ hg -R src-hg glog --template '{rev} ({branches}) {desc} files: {files}\n'
305 304 o 8 (branch) fuzzy files: b/c
306 305 |
307 306 o 7 (branch) fuzzy files: a
308 307 |
309 308 o 6 (branch) funny
310 309 | ----------------------------
311 310 | log message files: a
312 311 o 5 (branch) ci2 files: b/c
313 312
314 313 o 4 () ci1 files: a b/c
315 314 |
316 315 o 3 () update tags files: .hgtags
317 316 |
318 317 o 2 () ci0 files: b/c
319 318 |
320 319 | o 1 (INITIAL) import files:
321 320 |/
322 321 o 0 () Initial revision files: a b/c
323 322
324 323
325 324 testing debugcvsps
326 325
327 326 $ cd src
328 327 $ hg debugcvsps --fuzz=2
329 328 collecting CVS rlog
330 329 11 log entries
331 330 cvslog hook: 11 entries
332 331 creating changesets
333 332 10 changeset entries
334 333 cvschangesets hook: 10 changesets
335 334 ---------------------
336 335 PatchSet 1
337 336 Date: * (glob)
338 337 Author: * (glob)
339 338 Branch: HEAD
340 339 Tag: (none)
341 340 Branchpoints: INITIAL
342 341 Log:
343 342 Initial revision
344 343
345 344 Members:
346 345 a:INITIAL->1.1
347 346
348 347 ---------------------
349 348 PatchSet 2
350 349 Date: * (glob)
351 350 Author: * (glob)
352 351 Branch: HEAD
353 352 Tag: (none)
354 353 Branchpoints: INITIAL, branch
355 354 Log:
356 355 Initial revision
357 356
358 357 Members:
359 358 b/c:INITIAL->1.1
360 359
361 360 ---------------------
362 361 PatchSet 3
363 362 Date: * (glob)
364 363 Author: * (glob)
365 364 Branch: INITIAL
366 365 Tag: start
367 366 Log:
368 367 import
369 368
370 369 Members:
371 370 a:1.1->1.1.1.1
372 371 b/c:1.1->1.1.1.1
373 372
374 373 ---------------------
375 374 PatchSet 4
376 375 Date: * (glob)
377 376 Author: * (glob)
378 377 Branch: HEAD
379 378 Tag: (none)
380 379 Log:
381 380 ci0
382 381
383 382 Members:
384 383 b/c:1.1->1.2
385 384
386 385 ---------------------
387 386 PatchSet 5
388 387 Date: * (glob)
389 388 Author: * (glob)
390 389 Branch: HEAD
391 390 Tag: (none)
392 391 Branchpoints: branch
393 392 Log:
394 393 ci1
395 394
396 395 Members:
397 396 a:1.1->1.2
398 397
399 398 ---------------------
400 399 PatchSet 6
401 400 Date: * (glob)
402 401 Author: * (glob)
403 402 Branch: HEAD
404 403 Tag: (none)
405 404 Log:
406 405 ci1
407 406
408 407 Members:
409 408 b/c:1.2->1.3
410 409
411 410 ---------------------
412 411 PatchSet 7
413 412 Date: * (glob)
414 413 Author: * (glob)
415 414 Branch: branch
416 415 Tag: (none)
417 416 Log:
418 417 ci2
419 418
420 419 Members:
421 420 b/c:1.1->1.1.2.1
422 421
423 422 ---------------------
424 423 PatchSet 8
425 424 Date: * (glob)
426 425 Author: * (glob)
427 426 Branch: branch
428 427 Tag: (none)
429 428 Log:
430 429 funny
431 430 ----------------------------
432 431 log message
433 432
434 433 Members:
435 434 a:1.2->1.2.2.1
436 435
437 436 ---------------------
438 437 PatchSet 9
439 438 Date: * (glob)
440 439 Author: * (glob)
441 440 Branch: branch
442 441 Tag: (none)
443 442 Log:
444 443 fuzzy
445 444
446 445 Members:
447 446 a:1.2.2.1->1.2.2.2
448 447
449 448 ---------------------
450 449 PatchSet 10
451 450 Date: * (glob)
452 451 Author: * (glob)
453 452 Branch: branch
454 453 Tag: (none)
455 454 Log:
456 455 fuzzy
457 456
458 457 Members:
459 458 b/c:1.1.2.1->1.1.2.2
460 459
461 460
@@ -1,217 +1,216 b''
1 1 Test the EOL hook
2 2
3 3 $ hg init main
4 4 $ cat > main/.hg/hgrc <<EOF
5 5 > [hooks]
6 6 > pretxnchangegroup = python:hgext.eol.hook
7 7 > EOF
8 8 $ hg clone main fork
9 9 updating to branch default
10 10 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 11 $ cd fork
12 12
13 13 Create repo
14 14 $ cat > .hgeol <<EOF
15 15 > [patterns]
16 16 > mixed.txt = BIN
17 17 > crlf.txt = CRLF
18 18 > **.txt = native
19 19 > EOF
20 20 $ hg add .hgeol
21 21 $ hg commit -m 'Commit .hgeol'
22 22
23 23 $ printf "first\nsecond\nthird\n" > a.txt
24 24 $ hg add a.txt
25 25 $ hg commit -m 'LF a.txt'
26 26 $ hg push ../main
27 27 pushing to ../main
28 28 searching for changes
29 29 adding changesets
30 30 adding manifests
31 31 adding file changes
32 32 added 2 changesets with 2 changes to 2 files
33 33
34 34 $ printf "first\r\nsecond\r\nthird\n" > a.txt
35 35 $ hg commit -m 'CRLF a.txt'
36 36 $ hg push ../main
37 37 pushing to ../main
38 38 searching for changes
39 39 adding changesets
40 40 adding manifests
41 41 adding file changes
42 42 added 1 changesets with 1 changes to 1 files
43 43 error: pretxnchangegroup hook failed: end-of-line check failed:
44 44 a.txt in a8ee6548cd86 should not have CRLF line endings
45 45 transaction abort!
46 46 rollback completed
47 47 abort: end-of-line check failed:
48 48 a.txt in a8ee6548cd86 should not have CRLF line endings
49 49 [255]
50 50
51 51 $ printf "first\nsecond\nthird\n" > a.txt
52 52 $ hg commit -m 'LF a.txt (fixed)'
53 53 $ hg push ../main
54 54 pushing to ../main
55 55 searching for changes
56 56 adding changesets
57 57 adding manifests
58 58 adding file changes
59 59 added 2 changesets with 2 changes to 1 files
60 60
61 61 $ printf "first\nsecond\nthird\n" > crlf.txt
62 62 $ hg add crlf.txt
63 63 $ hg commit -m 'LF crlf.txt'
64 64 $ hg push ../main
65 65 pushing to ../main
66 66 searching for changes
67 67 adding changesets
68 68 adding manifests
69 69 adding file changes
70 70 added 1 changesets with 1 changes to 1 files
71 71 error: pretxnchangegroup hook failed: end-of-line check failed:
72 72 crlf.txt in 004ba2132725 should not have LF line endings
73 73 transaction abort!
74 74 rollback completed
75 75 abort: end-of-line check failed:
76 76 crlf.txt in 004ba2132725 should not have LF line endings
77 77 [255]
78 78
79 79 $ printf "first\r\nsecond\r\nthird\r\n" > crlf.txt
80 80 $ hg commit -m 'CRLF crlf.txt (fixed)'
81 81 $ hg push ../main
82 82 pushing to ../main
83 83 searching for changes
84 84 adding changesets
85 85 adding manifests
86 86 adding file changes
87 87 added 2 changesets with 2 changes to 1 files
88 88
89 89 $ printf "first\r\nsecond" > b.txt
90 90 $ hg add b.txt
91 91 $ hg commit -m 'CRLF b.txt'
92 92 $ hg push ../main
93 93 pushing to ../main
94 94 searching for changes
95 95 adding changesets
96 96 adding manifests
97 97 adding file changes
98 98 added 1 changesets with 1 changes to 1 files
99 99 error: pretxnchangegroup hook failed: end-of-line check failed:
100 100 b.txt in fbcf9b1025f5 should not have CRLF line endings
101 101 transaction abort!
102 102 rollback completed
103 103 abort: end-of-line check failed:
104 104 b.txt in fbcf9b1025f5 should not have CRLF line endings
105 105 [255]
106 106
107 107 $ hg up -r -2
108 108 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
109 109 $ printf "some\nother\nfile" > c.txt
110 110 $ hg add c.txt
111 111 $ hg commit -m "LF c.txt, b.txt doesn't exist here"
112 112 created new head
113 113 $ hg push -f ../main
114 114 pushing to ../main
115 115 searching for changes
116 116 adding changesets
117 117 adding manifests
118 118 adding file changes
119 119 added 2 changesets with 2 changes to 2 files (+1 heads)
120 120 error: pretxnchangegroup hook failed: end-of-line check failed:
121 121 b.txt in fbcf9b1025f5 should not have CRLF line endings
122 122 transaction abort!
123 123 rollback completed
124 124 abort: end-of-line check failed:
125 125 b.txt in fbcf9b1025f5 should not have CRLF line endings
126 126 [255]
127 127
128 128 Test checkheadshook alias
129 129
130 130 $ cat > ../main/.hg/hgrc <<EOF
131 131 > [hooks]
132 132 > pretxnchangegroup = python:hgext.eol.checkheadshook
133 133 > EOF
134 134 $ hg push -f ../main
135 135 pushing to ../main
136 136 searching for changes
137 137 adding changesets
138 138 adding manifests
139 139 adding file changes
140 140 added 2 changesets with 2 changes to 2 files (+1 heads)
141 141 error: pretxnchangegroup hook failed: end-of-line check failed:
142 142 b.txt in fbcf9b1025f5 should not have CRLF line endings
143 143 transaction abort!
144 144 rollback completed
145 145 abort: end-of-line check failed:
146 146 b.txt in fbcf9b1025f5 should not have CRLF line endings
147 147 [255]
148 148
149 149 We can fix the head and push again
150 150
151 151 $ hg up 6
152 152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
153 153 $ printf "first\nsecond" > b.txt
154 154 $ hg ci -m "remove CRLF from b.txt"
155 155 $ hg push -f ../main
156 156 pushing to ../main
157 157 searching for changes
158 158 adding changesets
159 159 adding manifests
160 160 adding file changes
161 161 added 3 changesets with 3 changes to 2 files (+1 heads)
162 162 $ hg -R ../main rollback
163 163 repository tip rolled back to revision 5 (undo push)
164 working directory now based on revision -1
165 164
166 165 Test it still fails with checkallhook
167 166
168 167 $ cat > ../main/.hg/hgrc <<EOF
169 168 > [hooks]
170 169 > pretxnchangegroup = python:hgext.eol.checkallhook
171 170 > EOF
172 171 $ hg push -f ../main
173 172 pushing to ../main
174 173 searching for changes
175 174 adding changesets
176 175 adding manifests
177 176 adding file changes
178 177 added 3 changesets with 3 changes to 2 files (+1 heads)
179 178 error: pretxnchangegroup hook failed: end-of-line check failed:
180 179 b.txt in fbcf9b1025f5 should not have CRLF line endings
181 180 transaction abort!
182 181 rollback completed
183 182 abort: end-of-line check failed:
184 183 b.txt in fbcf9b1025f5 should not have CRLF line endings
185 184 [255]
186 185
187 186 But we can push the clean head
188 187
189 188 $ hg push -r7 -f ../main
190 189 pushing to ../main
191 190 searching for changes
192 191 adding changesets
193 192 adding manifests
194 193 adding file changes
195 194 added 1 changesets with 1 changes to 1 files
196 195
197 196 Test multiple files/revisions output
198 197
199 198 $ printf "another\r\nbad\r\none" > d.txt
200 199 $ hg add d.txt
201 200 $ hg ci -m "add d.txt"
202 201 $ hg push -f ../main
203 202 pushing to ../main
204 203 searching for changes
205 204 adding changesets
206 205 adding manifests
207 206 adding file changes
208 207 added 3 changesets with 3 changes to 2 files (+1 heads)
209 208 error: pretxnchangegroup hook failed: end-of-line check failed:
210 209 d.txt in a7040e68714f should not have CRLF line endings
211 210 b.txt in fbcf9b1025f5 should not have CRLF line endings
212 211 transaction abort!
213 212 rollback completed
214 213 abort: end-of-line check failed:
215 214 d.txt in a7040e68714f should not have CRLF line endings
216 215 b.txt in fbcf9b1025f5 should not have CRLF line endings
217 216 [255]
@@ -1,551 +1,550 b''
1 1 commit hooks can see env vars
2 2
3 3 $ hg init a
4 4 $ cd a
5 5 $ echo "[hooks]" > .hg/hgrc
6 6 $ echo 'commit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit' >> .hg/hgrc
7 7 $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
8 8 $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
9 9 $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py pretxncommit' >> .hg/hgrc
10 10 $ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
11 11 $ echo 'pre-identify = python "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
12 12 $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
13 13 $ echo 'post-cat = python "$TESTDIR"/printenv.py post-cat' >> .hg/hgrc
14 14 $ echo a > a
15 15 $ hg add a
16 16 $ hg commit -m a
17 17 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
18 18 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
19 19 0:cb9a9f314b8b
20 20 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
21 21 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22 22
23 23 $ hg clone . ../b
24 24 updating to branch default
25 25 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
26 26 $ cd ../b
27 27
28 28 changegroup hooks can see env vars
29 29
30 30 $ echo '[hooks]' > .hg/hgrc
31 31 $ echo 'prechangegroup = python "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
32 32 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
33 33 $ echo 'incoming = python "$TESTDIR"/printenv.py incoming' >> .hg/hgrc
34 34
35 35 pretxncommit and commit hooks can see both parents of merge
36 36
37 37 $ cd ../a
38 38 $ echo b >> a
39 39 $ hg commit -m a1 -d "1 0"
40 40 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
41 41 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
42 42 1:ab228980c14d
43 43 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 44 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 45 $ hg update -C 0
46 46 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 47 $ echo b > b
48 48 $ hg add b
49 49 $ hg commit -m b -d '1 0'
50 50 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
51 51 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
52 52 2:ee9deb46ab31
53 53 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 54 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 55 created new head
56 56 $ hg merge 1
57 57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 58 (branch merge, don't forget to commit)
59 59 $ hg commit -m merge -d '2 0'
60 60 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
61 61 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
62 62 3:07f3376c1e65
63 63 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 64 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 65
66 66 test generic hooks
67 67
68 68 $ hg id
69 69 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'num': None, 'rev': '', 'tags': None} HG_PATS=[]
70 70 warning: pre-identify hook exited with status 1
71 71 [1]
72 72 $ hg cat b
73 73 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
74 74 b
75 75 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
76 76
77 77 $ cd ../b
78 78 $ hg pull ../a
79 79 pulling from ../a
80 80 searching for changes
81 81 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
82 82 adding changesets
83 83 adding manifests
84 84 adding file changes
85 85 added 3 changesets with 2 changes to 2 files
86 86 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
87 87 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
88 88 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
89 89 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 90 (run 'hg update' to get a working copy)
91 91
92 92 tag hooks can see env vars
93 93
94 94 $ cd ../a
95 95 $ echo 'pretag = python "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
96 96 $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/printenv.py tag' >> .hg/hgrc
97 97 $ hg tag -d '3 0' a
98 98 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
99 99 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
100 100 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
101 101 4:539e4b31b6dc
102 102 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
103 103 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
104 104 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 105 $ hg tag -l la
106 106 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
107 107 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
108 108
109 109 pretag hook can forbid tagging
110 110
111 111 $ echo 'pretag.forbid = python "$TESTDIR"/printenv.py pretag.forbid 1' >> .hg/hgrc
112 112 $ hg tag -d '4 0' fa
113 113 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
114 114 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
115 115 abort: pretag.forbid hook exited with status 1
116 116 [255]
117 117 $ hg tag -l fla
118 118 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
119 119 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
120 120 abort: pretag.forbid hook exited with status 1
121 121 [255]
122 122
123 123 pretxncommit hook can see changeset, can roll back txn, changeset no
124 124 more there after
125 125
126 126 $ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
127 127 $ echo 'pretxncommit.forbid1 = python "$TESTDIR"/printenv.py pretxncommit.forbid 1' >> .hg/hgrc
128 128 $ echo z > z
129 129 $ hg add z
130 130 $ hg -q tip
131 131 4:539e4b31b6dc
132 132 $ hg commit -m 'fail' -d '4 0'
133 133 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
134 134 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
135 135 5:6f611f8018c1
136 136 5:6f611f8018c1
137 137 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
138 138 transaction abort!
139 139 rollback completed
140 140 abort: pretxncommit.forbid1 hook exited with status 1
141 141 [255]
142 142 $ hg -q tip
143 143 4:539e4b31b6dc
144 144
145 145 precommit hook can prevent commit
146 146
147 147 $ echo 'precommit.forbid = python "$TESTDIR"/printenv.py precommit.forbid 1' >> .hg/hgrc
148 148 $ hg commit -m 'fail' -d '4 0'
149 149 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
150 150 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
151 151 abort: precommit.forbid hook exited with status 1
152 152 [255]
153 153 $ hg -q tip
154 154 4:539e4b31b6dc
155 155
156 156 preupdate hook can prevent update
157 157
158 158 $ echo 'preupdate = python "$TESTDIR"/printenv.py preupdate' >> .hg/hgrc
159 159 $ hg update 1
160 160 preupdate hook: HG_PARENT1=ab228980c14d
161 161 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
162 162
163 163 update hook
164 164
165 165 $ echo 'update = python "$TESTDIR"/printenv.py update' >> .hg/hgrc
166 166 $ hg update
167 167 preupdate hook: HG_PARENT1=539e4b31b6dc
168 168 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
169 169 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 170
171 171 pushkey hook
172 172
173 173 $ echo 'pushkey = python "$TESTDIR"/printenv.py pushkey' >> .hg/hgrc
174 174 $ cd ../b
175 175 $ hg bookmark -r null foo
176 176 $ hg push -B foo ../a
177 177 pushing to ../a
178 178 searching for changes
179 179 no changes found
180 180 exporting bookmark foo
181 181 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
182 182 $ cd ../a
183 183
184 184 listkeys hook
185 185
186 186 $ echo 'listkeys = python "$TESTDIR"/printenv.py listkeys' >> .hg/hgrc
187 187 $ hg bookmark -r null bar
188 188 $ cd ../b
189 189 $ hg pull -B bar ../a
190 190 pulling from ../a
191 191 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
192 192 no changes found
193 193 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
194 194 importing bookmark bar
195 195 $ cd ../a
196 196
197 197 test that prepushkey can prevent incoming keys
198 198
199 199 $ echo 'prepushkey = python "$TESTDIR"/printenv.py prepushkey.forbid 1' >> .hg/hgrc
200 200 $ cd ../b
201 201 $ hg bookmark -r null baz
202 202 $ hg push -B baz ../a
203 203 pushing to ../a
204 204 searching for changes
205 205 no changes found
206 206 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
207 207 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
208 208 exporting bookmark baz
209 209 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
210 210 abort: prepushkey hook exited with status 1
211 211 [255]
212 212 $ cd ../a
213 213
214 214 test that prelistkeys can prevent listing keys
215 215
216 216 $ echo 'prelistkeys = python "$TESTDIR"/printenv.py prelistkeys.forbid 1' >> .hg/hgrc
217 217 $ hg bookmark -r null quux
218 218 $ cd ../b
219 219 $ hg pull -B quux ../a
220 220 pulling from ../a
221 221 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
222 222 abort: prelistkeys hook exited with status 1
223 223 [255]
224 224 $ cd ../a
225 225
226 226 prechangegroup hook can prevent incoming changes
227 227
228 228 $ cd ../b
229 229 $ hg -q tip
230 230 3:07f3376c1e65
231 231 $ echo '[hooks]' > .hg/hgrc
232 232 $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
233 233 $ hg pull ../a
234 234 pulling from ../a
235 235 searching for changes
236 236 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
237 237 abort: prechangegroup.forbid hook exited with status 1
238 238 [255]
239 239
240 240 pretxnchangegroup hook can see incoming changes, can roll back txn,
241 241 incoming changes no longer there after
242 242
243 243 $ echo '[hooks]' > .hg/hgrc
244 244 $ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
245 245 $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
246 246 $ hg pull ../a
247 247 pulling from ../a
248 248 searching for changes
249 249 adding changesets
250 250 adding manifests
251 251 adding file changes
252 252 added 1 changesets with 1 changes to 1 files
253 253 4:539e4b31b6dc
254 254 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
255 255 transaction abort!
256 256 rollback completed
257 257 abort: pretxnchangegroup.forbid1 hook exited with status 1
258 258 [255]
259 259 $ hg -q tip
260 260 3:07f3376c1e65
261 261
262 262 outgoing hooks can see env vars
263 263
264 264 $ rm .hg/hgrc
265 265 $ echo '[hooks]' > ../a/.hg/hgrc
266 266 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
267 267 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
268 268 $ hg pull ../a
269 269 pulling from ../a
270 270 searching for changes
271 271 preoutgoing hook: HG_SOURCE=pull
272 272 adding changesets
273 273 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
274 274 adding manifests
275 275 adding file changes
276 276 added 1 changesets with 1 changes to 1 files
277 277 (run 'hg update' to get a working copy)
278 278 $ hg rollback
279 279 repository tip rolled back to revision 3 (undo pull)
280 working directory now based on revision 0
281 280
282 281 preoutgoing hook can prevent outgoing changes
283 282
284 283 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
285 284 $ hg pull ../a
286 285 pulling from ../a
287 286 searching for changes
288 287 preoutgoing hook: HG_SOURCE=pull
289 288 preoutgoing.forbid hook: HG_SOURCE=pull
290 289 abort: preoutgoing.forbid hook exited with status 1
291 290 [255]
292 291
293 292 outgoing hooks work for local clones
294 293
295 294 $ cd ..
296 295 $ echo '[hooks]' > a/.hg/hgrc
297 296 $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
298 297 $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
299 298 $ hg clone a c
300 299 preoutgoing hook: HG_SOURCE=clone
301 300 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
302 301 updating to branch default
303 302 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 303 $ rm -rf c
305 304
306 305 preoutgoing hook can prevent outgoing changes for local clones
307 306
308 307 $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
309 308 $ hg clone a zzz
310 309 preoutgoing hook: HG_SOURCE=clone
311 310 preoutgoing.forbid hook: HG_SOURCE=clone
312 311 abort: preoutgoing.forbid hook exited with status 1
313 312 [255]
314 313 $ cd b
315 314
316 315 $ cat > hooktests.py <<EOF
317 316 > from mercurial import util
318 317 >
319 318 > uncallable = 0
320 319 >
321 320 > def printargs(args):
322 321 > args.pop('ui', None)
323 322 > args.pop('repo', None)
324 323 > a = list(args.items())
325 324 > a.sort()
326 325 > print 'hook args:'
327 326 > for k, v in a:
328 327 > print ' ', k, v
329 328 >
330 329 > def passhook(**args):
331 330 > printargs(args)
332 331 >
333 332 > def failhook(**args):
334 333 > printargs(args)
335 334 > return True
336 335 >
337 336 > class LocalException(Exception):
338 337 > pass
339 338 >
340 339 > def raisehook(**args):
341 340 > raise LocalException('exception from hook')
342 341 >
343 342 > def aborthook(**args):
344 343 > raise util.Abort('raise abort from hook')
345 344 >
346 345 > def brokenhook(**args):
347 346 > return 1 + {}
348 347 >
349 348 > def verbosehook(ui, **args):
350 349 > ui.note('verbose output from hook\n')
351 350 >
352 351 > class container:
353 352 > unreachable = 1
354 353 > EOF
355 354
356 355 test python hooks
357 356
358 357 $ PYTHONPATH="`pwd`:$PYTHONPATH"
359 358 $ export PYTHONPATH
360 359
361 360 $ echo '[hooks]' > ../a/.hg/hgrc
362 361 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
363 362 $ hg pull ../a 2>&1 | grep 'raised an exception'
364 363 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
365 364
366 365 $ echo '[hooks]' > ../a/.hg/hgrc
367 366 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
368 367 $ hg pull ../a 2>&1 | grep 'raised an exception'
369 368 error: preoutgoing.raise hook raised an exception: exception from hook
370 369
371 370 $ echo '[hooks]' > ../a/.hg/hgrc
372 371 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
373 372 $ hg pull ../a
374 373 pulling from ../a
375 374 searching for changes
376 375 error: preoutgoing.abort hook failed: raise abort from hook
377 376 abort: raise abort from hook
378 377 [255]
379 378
380 379 $ echo '[hooks]' > ../a/.hg/hgrc
381 380 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
382 381 $ hg pull ../a
383 382 pulling from ../a
384 383 searching for changes
385 384 hook args:
386 385 hooktype preoutgoing
387 386 source pull
388 387 abort: preoutgoing.fail hook failed
389 388 [255]
390 389
391 390 $ echo '[hooks]' > ../a/.hg/hgrc
392 391 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
393 392 $ hg pull ../a
394 393 pulling from ../a
395 394 searching for changes
396 395 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
397 396 [255]
398 397
399 398 $ echo '[hooks]' > ../a/.hg/hgrc
400 399 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
401 400 $ hg pull ../a
402 401 pulling from ../a
403 402 searching for changes
404 403 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
405 404 [255]
406 405
407 406 $ echo '[hooks]' > ../a/.hg/hgrc
408 407 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
409 408 $ hg pull ../a
410 409 pulling from ../a
411 410 searching for changes
412 411 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
413 412 [255]
414 413
415 414 $ echo '[hooks]' > ../a/.hg/hgrc
416 415 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
417 416 $ hg pull ../a
418 417 pulling from ../a
419 418 searching for changes
420 419 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
421 420 [255]
422 421
423 422 $ echo '[hooks]' > ../a/.hg/hgrc
424 423 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
425 424 $ hg pull ../a
426 425 pulling from ../a
427 426 searching for changes
428 427 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
429 428 [255]
430 429
431 430 $ echo '[hooks]' > ../a/.hg/hgrc
432 431 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
433 432 $ hg pull ../a
434 433 pulling from ../a
435 434 searching for changes
436 435 hook args:
437 436 hooktype preoutgoing
438 437 source pull
439 438 adding changesets
440 439 adding manifests
441 440 adding file changes
442 441 added 1 changesets with 1 changes to 1 files
443 442 (run 'hg update' to get a working copy)
444 443
445 444 make sure --traceback works
446 445
447 446 $ echo '[hooks]' > .hg/hgrc
448 447 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
449 448
450 449 $ echo aa > a
451 450 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
452 451 Traceback (most recent call last):
453 452
454 453 $ cd ..
455 454 $ hg init c
456 455 $ cd c
457 456
458 457 $ cat > hookext.py <<EOF
459 458 > def autohook(**args):
460 459 > print "Automatically installed hook"
461 460 >
462 461 > def reposetup(ui, repo):
463 462 > repo.ui.setconfig("hooks", "commit.auto", autohook)
464 463 > EOF
465 464 $ echo '[extensions]' >> .hg/hgrc
466 465 $ echo 'hookext = hookext.py' >> .hg/hgrc
467 466
468 467 $ touch foo
469 468 $ hg add foo
470 469 $ hg ci -d '0 0' -m 'add foo'
471 470 Automatically installed hook
472 471 $ echo >> foo
473 472 $ hg ci --debug -d '0 0' -m 'change foo'
474 473 foo
475 474 calling hook commit.auto: <function autohook at *> (glob)
476 475 Automatically installed hook
477 476 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
478 477
479 478 $ hg showconfig hooks
480 479 hooks.commit.auto=<function autohook at *> (glob)
481 480
482 481 test python hook configured with python:[file]:[hook] syntax
483 482
484 483 $ cd ..
485 484 $ mkdir d
486 485 $ cd d
487 486 $ hg init repo
488 487 $ mkdir hooks
489 488
490 489 $ cd hooks
491 490 $ cat > testhooks.py <<EOF
492 491 > def testhook(**args):
493 492 > print 'hook works'
494 493 > EOF
495 494 $ echo '[hooks]' > ../repo/.hg/hgrc
496 495 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
497 496
498 497 $ cd ../repo
499 498 $ hg commit -d '0 0'
500 499 hook works
501 500 nothing changed
502 501 [1]
503 502
504 503 $ cd ../../b
505 504
506 505 make sure --traceback works on hook import failure
507 506
508 507 $ cat > importfail.py <<EOF
509 508 > import somebogusmodule
510 509 > # dereference something in the module to force demandimport to load it
511 510 > somebogusmodule.whatever
512 511 > EOF
513 512
514 513 $ echo '[hooks]' > .hg/hgrc
515 514 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
516 515
517 516 $ echo a >> a
518 517 $ hg --traceback commit -ma 2>&1 | egrep '^(exception|Traceback|ImportError)'
519 518 exception from first failed import attempt:
520 519 Traceback (most recent call last):
521 520 ImportError: No module named somebogusmodule
522 521 exception from second failed import attempt:
523 522 Traceback (most recent call last):
524 523 ImportError: No module named hgext_importfail
525 524 Traceback (most recent call last):
526 525
527 526 Issue1827: Hooks Update & Commit not completely post operation
528 527
529 528 commit and update hooks should run after command completion
530 529
531 530 $ echo '[hooks]' > .hg/hgrc
532 531 $ echo 'commit = hg id' >> .hg/hgrc
533 532 $ echo 'update = hg id' >> .hg/hgrc
534 533 $ echo bb > a
535 534 $ hg ci -ma
536 535 223eafe2750c tip
537 536 $ hg up 0
538 537 cb9a9f314b8b
539 538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 539
541 540 make sure --verbose (and --quiet/--debug etc.) are propogated to the local ui
542 541 that is passed to pre/post hooks
543 542
544 543 $ echo '[hooks]' > .hg/hgrc
545 544 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
546 545 $ hg id
547 546 cb9a9f314b8b
548 547 $ hg id --verbose
549 548 calling hook pre-identify: hooktests.verbosehook
550 549 verbose output from hook
551 550 cb9a9f314b8b
@@ -1,261 +1,258 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "purge=" >> $HGRCPATH
3 3 $ echo "graphlog=" >> $HGRCPATH
4 4
5 5 $ shortlog() {
6 6 > hg glog --template '{rev}:{node|short} {author} {date|hgdate} - {branch} - {desc|firstline}\n'
7 7 > }
8 8
9 9 Test --bypass with other options
10 10
11 11 $ hg init repo-options
12 12 $ cd repo-options
13 13 $ echo a > a
14 14 $ hg ci -Am adda
15 15 adding a
16 16 $ echo a >> a
17 17 $ hg branch foo
18 18 marked working directory as branch foo
19 19 $ hg ci -Am changea
20 20 $ hg export . > ../test.diff
21 21 $ hg up null
22 22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23 23
24 24 Test importing an existing revision
25 25
26 26 $ hg import --bypass --exact ../test.diff
27 27 applying ../test.diff
28 28 $ shortlog
29 29 o 1:4e322f7ce8e3 test 0 0 - foo - changea
30 30 |
31 31 o 0:07f494440405 test 0 0 - default - adda
32 32
33 33
34 34 Test failure without --exact
35 35
36 36 $ hg import --bypass ../test.diff
37 37 applying ../test.diff
38 38 unable to find 'a' for patching
39 39 abort: patch failed to apply
40 40 [255]
41 41 $ hg st
42 42 $ shortlog
43 43 o 1:4e322f7ce8e3 test 0 0 - foo - changea
44 44 |
45 45 o 0:07f494440405 test 0 0 - default - adda
46 46
47 47
48 48 Test --user, --date and --message
49 49
50 50 $ hg up 0
51 51 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
52 52 $ hg import --bypass --u test2 -d '1 0' -m patch2 ../test.diff
53 53 applying ../test.diff
54 54 $ cat .hg/last-message.txt
55 55 patch2 (no-eol)
56 56 $ shortlog
57 57 o 2:2e127d1da504 test2 1 0 - default - patch2
58 58 |
59 59 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
60 60 |/
61 61 @ 0:07f494440405 test 0 0 - default - adda
62 62
63 63 $ hg rollback
64 64 repository tip rolled back to revision 1 (undo commit)
65 working directory now based on revision 0
66 65
67 66 Test --import-branch
68 67
69 68 $ hg import --bypass --import-branch ../test.diff
70 69 applying ../test.diff
71 70 $ shortlog
72 71 o 1:4e322f7ce8e3 test 0 0 - foo - changea
73 72 |
74 73 @ 0:07f494440405 test 0 0 - default - adda
75 74
76 75 $ hg rollback
77 76 repository tip rolled back to revision 1 (undo commit)
78 working directory now based on revision 0
79 77
80 78 Test --strip
81 79
82 80 $ hg import --bypass --strip 0 - <<EOF
83 81 > # HG changeset patch
84 82 > # User test
85 83 > # Date 0 0
86 84 > # Branch foo
87 85 > # Node ID 4e322f7ce8e3e4203950eac9ece27bf7e45ffa6c
88 86 > # Parent 07f4944404050f47db2e5c5071e0e84e7a27bba9
89 87 > changea
90 88 >
91 89 > diff -r 07f494440405 -r 4e322f7ce8e3 a
92 90 > --- a Thu Jan 01 00:00:00 1970 +0000
93 91 > +++ a Thu Jan 01 00:00:00 1970 +0000
94 92 > @@ -1,1 +1,2 @@
95 93 > a
96 94 > +a
97 95 > EOF
98 96 applying patch from stdin
99 97 $ hg rollback
100 98 repository tip rolled back to revision 1 (undo commit)
101 working directory now based on revision 0
102 99
103 100 Test unsupported combinations
104 101
105 102 $ hg import --bypass --no-commit ../test.diff
106 103 abort: cannot use --no-commit with --bypass
107 104 [255]
108 105 $ hg import --bypass --similarity 50 ../test.diff
109 106 abort: cannot use --similarity with --bypass
110 107 [255]
111 108
112 109 Test commit editor
113 110
114 111 $ hg diff -c 1 > ../test.diff
115 112 $ HGEDITOR=cat hg import --bypass ../test.diff
116 113 applying ../test.diff
117 114
118 115
119 116 HG: Enter commit message. Lines beginning with 'HG:' are removed.
120 117 HG: Leave message empty to abort commit.
121 118 HG: --
122 119 HG: user: test
123 120 HG: branch 'default'
124 121 HG: changed a
125 122 abort: empty commit message
126 123 [255]
127 124
128 125 Test patch.eol is handled
129 126
130 127 $ python -c 'file("a", "wb").write("a\r\n")'
131 128 $ hg ci -m makeacrlf
132 129 $ hg import -m 'should fail because of eol' --bypass ../test.diff
133 130 applying ../test.diff
134 131 patching file a
135 132 Hunk #1 FAILED at 0
136 133 abort: patch failed to apply
137 134 [255]
138 135 $ hg --config patch.eol=auto import -d '0 0' -m 'test patch.eol' --bypass ../test.diff
139 136 applying ../test.diff
140 137 $ shortlog
141 138 o 3:d7805b4d2cb3 test 0 0 - default - test patch.eol
142 139 |
143 140 @ 2:872023de769d test 0 0 - default - makeacrlf
144 141 |
145 142 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
146 143 |/
147 144 o 0:07f494440405 test 0 0 - default - adda
148 145
149 146
150 147 Test applying multiple patches
151 148
152 149 $ hg up -qC 0
153 150 $ echo e > e
154 151 $ hg ci -Am adde
155 152 adding e
156 153 created new head
157 154 $ hg export . > ../patch1.diff
158 155 $ hg up -qC 1
159 156 $ echo f > f
160 157 $ hg ci -Am addf
161 158 adding f
162 159 $ hg export . > ../patch2.diff
163 160 $ cd ..
164 161 $ hg clone -r1 repo-options repo-multi1
165 162 adding changesets
166 163 adding manifests
167 164 adding file changes
168 165 added 2 changesets with 2 changes to 1 files
169 166 updating to branch foo
170 167 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 168 $ cd repo-multi1
172 169 $ hg up 0
173 170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 171 $ hg import --bypass ../patch1.diff ../patch2.diff
175 172 applying ../patch1.diff
176 173 applying ../patch2.diff
177 174 applied 16581080145e
178 175 $ shortlog
179 176 o 3:bc8ca3f8a7c4 test 0 0 - default - addf
180 177 |
181 178 o 2:16581080145e test 0 0 - default - adde
182 179 |
183 180 | o 1:4e322f7ce8e3 test 0 0 - foo - changea
184 181 |/
185 182 @ 0:07f494440405 test 0 0 - default - adda
186 183
187 184
188 185 Test applying multiple patches with --exact
189 186
190 187 $ cd ..
191 188 $ hg clone -r1 repo-options repo-multi2
192 189 adding changesets
193 190 adding manifests
194 191 adding file changes
195 192 added 2 changesets with 2 changes to 1 files
196 193 updating to branch foo
197 194 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 195 $ cd repo-multi2
199 196 $ hg import --bypass --exact ../patch1.diff ../patch2.diff
200 197 applying ../patch1.diff
201 198 applying ../patch2.diff
202 199 applied 16581080145e
203 200 $ shortlog
204 201 o 3:d60cb8989666 test 0 0 - foo - addf
205 202 |
206 203 | o 2:16581080145e test 0 0 - default - adde
207 204 | |
208 205 @ | 1:4e322f7ce8e3 test 0 0 - foo - changea
209 206 |/
210 207 o 0:07f494440405 test 0 0 - default - adda
211 208
212 209
213 210 $ cd ..
214 211
215 212 Test complicated patch with --exact
216 213
217 214 $ hg init repo-exact
218 215 $ cd repo-exact
219 216 $ echo a > a
220 217 $ echo c > c
221 218 $ echo d > d
222 219 $ echo e > e
223 220 $ echo f > f
224 221 $ chmod +x f
225 222 $ ln -s c linkc
226 223 $ hg ci -Am t
227 224 adding a
228 225 adding c
229 226 adding d
230 227 adding e
231 228 adding f
232 229 adding linkc
233 230 $ hg cp a aa1
234 231 $ echo b >> a
235 232 $ echo b > b
236 233 $ hg add b
237 234 $ hg cp a aa2
238 235 $ echo aa >> aa2
239 236 $ chmod +x e
240 237 $ chmod -x f
241 238 $ ln -s a linka
242 239 $ hg rm d
243 240 $ hg rm linkc
244 241 $ hg mv c cc
245 242 $ hg ci -m patch
246 243 $ hg export --git . > ../test.diff
247 244 $ hg up -C null
248 245 0 files updated, 0 files merged, 7 files removed, 0 files unresolved
249 246 $ hg purge
250 247 $ hg st
251 248 $ hg import --bypass --exact ../test.diff
252 249 applying ../test.diff
253 250
254 251 The patch should have matched the exported revision and generated no additional
255 252 data. If not, diff both heads to debug it.
256 253
257 254 $ shortlog
258 255 o 1:2978fd5c8aa4 test 0 0 - default - patch
259 256 |
260 257 o 0:a0e19e636a43 test 0 0 - default - t
261 258
@@ -1,128 +1,126 b''
1 1
2 2 $ cat <<EOF >> $HGRCPATH
3 3 > [extensions]
4 4 > notify=
5 5 >
6 6 > [hooks]
7 7 > changegroup.notify = python:hgext.notify.hook
8 8 >
9 9 > [notify]
10 10 > sources = push
11 11 > diffstat = False
12 12 > maxsubject = 10
13 13 >
14 14 > [usersubs]
15 15 > foo@bar = *
16 16 >
17 17 > [reposubs]
18 18 > * = baz
19 19 > EOF
20 20 $ hg init a
21 21
22 22 clone
23 23
24 24 $ hg --traceback clone a b
25 25 updating to branch default
26 26 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 27 $ echo a > b/a
28 28
29 29 commit
30 30
31 31 $ hg --traceback --cwd b commit -Ama
32 32 adding a
33 33 $ echo a >> b/a
34 34
35 35 commit
36 36
37 37 $ hg --traceback --cwd b commit -Amb
38 38
39 39 push
40 40
41 41 $ hg --traceback --cwd b push ../a 2>&1 |
42 42 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
43 43 pushing to ../a
44 44 searching for changes
45 45 adding changesets
46 46 adding manifests
47 47 adding file changes
48 48 added 2 changesets with 2 changes to 1 files
49 49 Content-Type: text/plain; charset="us-ascii"
50 50 MIME-Version: 1.0
51 51 Content-Transfer-Encoding: 7bit
52 52 Date: * (glob)
53 53 Subject: * (glob)
54 54 From: test
55 55 X-Hg-Notification: changeset cb9a9f314b8b
56 56 Message-Id: <*> (glob)
57 57 To: baz, foo@bar
58 58
59 59 changeset cb9a9f314b8b in $TESTTMP/a
60 60 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
61 61 summary: a
62 62
63 63 changeset ba677d0156c1 in $TESTTMP/a
64 64 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
65 65 summary: b
66 66
67 67 diffs (6 lines):
68 68
69 69 diff -r 000000000000 -r ba677d0156c1 a
70 70 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71 71 +++ b/a Thu Jan 01 00:00:00 1970 +0000
72 72 @@ -0,0 +1,2 @@
73 73 +a
74 74 +a
75 75 $ hg --cwd a rollback
76 76 repository tip rolled back to revision -1 (undo push)
77 working directory now based on revision -1
78 77
79 78 unbundle with unrelated source
80 79
81 80 $ hg --cwd b bundle ../test.hg ../a
82 81 searching for changes
83 82 2 changesets found
84 83 $ hg --cwd a unbundle ../test.hg
85 84 adding changesets
86 85 adding manifests
87 86 adding file changes
88 87 added 2 changesets with 2 changes to 1 files
89 88 (run 'hg update' to get a working copy)
90 89 $ hg --cwd a rollback
91 90 repository tip rolled back to revision -1 (undo unbundle)
92 working directory now based on revision -1
93 91
94 92 unbundle with correct source
95 93
96 94 $ hg --config notify.sources=unbundle --cwd a unbundle ../test.hg 2>&1 |
97 95 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
98 96 adding changesets
99 97 adding manifests
100 98 adding file changes
101 99 added 2 changesets with 2 changes to 1 files
102 100 Content-Type: text/plain; charset="us-ascii"
103 101 MIME-Version: 1.0
104 102 Content-Transfer-Encoding: 7bit
105 103 Date: * (glob)
106 104 Subject: * (glob)
107 105 From: test
108 106 X-Hg-Notification: changeset cb9a9f314b8b
109 107 Message-Id: <*> (glob)
110 108 To: baz, foo@bar
111 109
112 110 changeset cb9a9f314b8b in $TESTTMP/a
113 111 details: $TESTTMP/a?cmd=changeset;node=cb9a9f314b8b
114 112 summary: a
115 113
116 114 changeset ba677d0156c1 in $TESTTMP/a
117 115 details: $TESTTMP/a?cmd=changeset;node=ba677d0156c1
118 116 summary: b
119 117
120 118 diffs (6 lines):
121 119
122 120 diff -r 000000000000 -r ba677d0156c1 a
123 121 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 122 +++ b/a Thu Jan 01 00:00:00 1970 +0000
125 123 @@ -0,0 +1,2 @@
126 124 +a
127 125 +a
128 126 (run 'hg update' to get a working copy)
@@ -1,400 +1,397 b''
1 1
2 2 $ cat <<EOF >> $HGRCPATH
3 3 > [extensions]
4 4 > notify=
5 5 >
6 6 > [hooks]
7 7 > incoming.notify = python:hgext.notify.hook
8 8 >
9 9 > [notify]
10 10 > sources = pull
11 11 > diffstat = False
12 12 >
13 13 > [usersubs]
14 14 > foo@bar = *
15 15 >
16 16 > [reposubs]
17 17 > * = baz
18 18 > EOF
19 19 $ hg help notify
20 20 notify extension - hooks for sending email push notifications
21 21
22 22 This extension let you run hooks sending email notifications when changesets
23 23 are being pushed, from the sending or receiving side.
24 24
25 25 First, enable the extension as explained in "hg help extensions", and register
26 26 the hook you want to run. "incoming" and "outgoing" hooks are run by the
27 27 changesets receiver while the "outgoing" one is for the sender:
28 28
29 29 [hooks]
30 30 # one email for each incoming changeset
31 31 incoming.notify = python:hgext.notify.hook
32 32 # one email for all incoming changesets
33 33 changegroup.notify = python:hgext.notify.hook
34 34
35 35 # one email for all outgoing changesets
36 36 outgoing.notify = python:hgext.notify.hook
37 37
38 38 Now the hooks are running, subscribers must be assigned to repositories. Use
39 39 the "[usersubs]" section to map repositories to a given email or the
40 40 "[reposubs]" section to map emails to a single repository:
41 41
42 42 [usersubs]
43 43 # key is subscriber email, value is a comma-separated list of glob
44 44 # patterns
45 45 user@host = pattern
46 46
47 47 [reposubs]
48 48 # key is glob pattern, value is a comma-separated list of subscriber
49 49 # emails
50 50 pattern = user@host
51 51
52 52 Glob patterns are matched against absolute path to repository root. The
53 53 subscriptions can be defined in their own file and referenced with:
54 54
55 55 [notify]
56 56 config = /path/to/subscriptionsfile
57 57
58 58 Alternatively, they can be added to Mercurial configuration files by setting
59 59 the previous entry to an empty value.
60 60
61 61 At this point, notifications should be generated but will not be sent until
62 62 you set the "notify.test" entry to "False".
63 63
64 64 Notifications content can be tweaked with the following configuration entries:
65 65
66 66 notify.test
67 67 If "True", print messages to stdout instead of sending them. Default: True.
68 68
69 69 notify.sources
70 70 Space separated list of change sources. Notifications are sent only if it
71 71 includes the incoming or outgoing changes source. Incoming sources can be
72 72 "serve" for changes coming from http or ssh, "pull" for pulled changes,
73 73 "unbundle" for changes added by "hg unbundle" or "push" for changes being
74 74 pushed locally. Outgoing sources are the same except for "unbundle" which is
75 75 replaced by "bundle". Default: serve.
76 76
77 77 notify.strip
78 78 Number of leading slashes to strip from url paths. By default, notifications
79 79 references repositories with their absolute path. "notify.strip" let you
80 80 turn them into relative paths. For example, "notify.strip=3" will change
81 81 "/long/path/repository" into "repository". Default: 0.
82 82
83 83 notify.domain
84 84 If subscribers emails or the from email have no domain set, complete them
85 85 with this value.
86 86
87 87 notify.style
88 88 Style file to use when formatting emails.
89 89
90 90 notify.template
91 91 Template to use when formatting emails.
92 92
93 93 notify.incoming
94 94 Template to use when run as incoming hook, override "notify.template".
95 95
96 96 notify.outgoing
97 97 Template to use when run as outgoing hook, override "notify.template".
98 98
99 99 notify.changegroup
100 100 Template to use when running as changegroup hook, override
101 101 "notify.template".
102 102
103 103 notify.maxdiff
104 104 Maximum number of diff lines to include in notification email. Set to 0 to
105 105 disable the diff, -1 to include all of it. Default: 300.
106 106
107 107 notify.maxsubject
108 108 Maximum number of characters in emails subject line. Default: 67.
109 109
110 110 notify.diffstat
111 111 Set to True to include a diffstat before diff content. Default: True.
112 112
113 113 notify.merge
114 114 If True, send notifications for merge changesets. Default: True.
115 115
116 116 If set, the following entries will also be used to customize the
117 117 notifications:
118 118
119 119 email.from
120 120 Email "From" address to use if none can be found in generated email content.
121 121
122 122 web.baseurl
123 123 Root repository browsing URL to combine with repository paths when making
124 124 references. See also "notify.strip".
125 125
126 126 no commands defined
127 127 $ hg init a
128 128 $ echo a > a/a
129 129
130 130 commit
131 131
132 132 $ hg --cwd a commit -Ama -d '0 0'
133 133 adding a
134 134
135 135
136 136 clone
137 137
138 138 $ hg --traceback clone a b
139 139 updating to branch default
140 140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 141 $ echo a >> a/a
142 142
143 143 commit
144 144
145 145 $ hg --traceback --cwd a commit -Amb -d '1 0'
146 146
147 147 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
148 148
149 149 $ cat <<EOF >> $HGRCPATH
150 150 > [notify]
151 151 > maxsubject = 200
152 152 > EOF
153 153
154 154 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
155 155 of the very long subject line
156 156 pull (minimal config)
157 157
158 158 $ hg --traceback --cwd b pull ../a | \
159 159 > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
160 160 pulling from ../a
161 161 searching for changes
162 162 adding changesets
163 163 adding manifests
164 164 adding file changes
165 165 added 1 changesets with 1 changes to 1 files
166 166 Content-Type: text/plain; charset="us-ascii"
167 167 MIME-Version: 1.0
168 168 Content-Transfer-Encoding: 7bit
169 169 Date: * (glob)
170 170 Subject: changeset in $TESTTMP/b: b
171 171 From: test
172 172 X-Hg-Notification: changeset 0647d048b600
173 173 Message-Id: <*> (glob)
174 174 To: baz, foo@bar
175 175
176 176 changeset 0647d048b600 in $TESTTMP/b
177 177 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
178 178 description: b
179 179
180 180 diffs (6 lines):
181 181
182 182 diff -r cb9a9f314b8b -r 0647d048b600 a
183 183 --- a/a Thu Jan 01 00:00:00 1970 +0000
184 184 +++ b/a Thu Jan 01 00:00:01 1970 +0000
185 185 @@ -1,1 +1,2 @@ a
186 186 +a
187 187 (run 'hg update' to get a working copy)
188 188 $ cat <<EOF >> $HGRCPATH
189 189 > [notify]
190 190 > config = `pwd`/.notify.conf
191 191 > domain = test.com
192 192 > strip = 42
193 193 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
194 194 >
195 195 > [web]
196 196 > baseurl = http://test/
197 197 > EOF
198 198
199 199 fail for config file is missing
200 200
201 201 $ hg --cwd b rollback
202 202 repository tip rolled back to revision 0 (undo pull)
203 working directory now based on revision 0
204 203 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
205 204 pull failed
206 205 $ touch ".notify.conf"
207 206
208 207 pull
209 208
210 209 $ hg --cwd b rollback
211 210 repository tip rolled back to revision 0 (undo pull)
212 working directory now based on revision 0
213 211 $ hg --traceback --cwd b pull ../a | \
214 212 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
215 213 pulling from ../a
216 214 searching for changes
217 215 adding changesets
218 216 adding manifests
219 217 adding file changes
220 218 added 1 changesets with 1 changes to 1 files
221 219 Content-Type: text/plain; charset="us-ascii"
222 220 MIME-Version: 1.0
223 221 Content-Transfer-Encoding: 7bit
224 222 X-Test: foo
225 223 Date: * (glob)
226 224 Subject: b
227 225 From: test@test.com
228 226 X-Hg-Notification: changeset 0647d048b600
229 227 Message-Id: <*> (glob)
230 228 To: baz@test.com, foo@bar
231 229
232 230 changeset 0647d048b600 in b
233 231 description: b
234 232 diffs (6 lines):
235 233
236 234 diff -r cb9a9f314b8b -r 0647d048b600 a
237 235 --- a/a Thu Jan 01 00:00:00 1970 +0000
238 236 +++ b/a Thu Jan 01 00:00:01 1970 +0000
239 237 @@ -1,1 +1,2 @@
240 238 a
241 239 +a
242 240 (run 'hg update' to get a working copy)
243 241
244 242 $ cat << EOF >> $HGRCPATH
245 243 > [hooks]
246 244 > incoming.notify = python:hgext.notify.hook
247 245 >
248 246 > [notify]
249 247 > sources = pull
250 248 > diffstat = True
251 249 > EOF
252 250
253 251 pull
254 252
255 253 $ hg --cwd b rollback
256 254 repository tip rolled back to revision 0 (undo pull)
257 working directory now based on revision 0
258 255 $ hg --traceback --cwd b pull ../a | \
259 256 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
260 257 pulling from ../a
261 258 searching for changes
262 259 adding changesets
263 260 adding manifests
264 261 adding file changes
265 262 added 1 changesets with 1 changes to 1 files
266 263 Content-Type: text/plain; charset="us-ascii"
267 264 MIME-Version: 1.0
268 265 Content-Transfer-Encoding: 7bit
269 266 X-Test: foo
270 267 Date: * (glob)
271 268 Subject: b
272 269 From: test@test.com
273 270 X-Hg-Notification: changeset 0647d048b600
274 271 Message-Id: <*> (glob)
275 272 To: baz@test.com, foo@bar
276 273
277 274 changeset 0647d048b600 in b
278 275 description: b
279 276 diffstat:
280 277
281 278 a | 1 +
282 279 1 files changed, 1 insertions(+), 0 deletions(-)
283 280
284 281 diffs (6 lines):
285 282
286 283 diff -r cb9a9f314b8b -r 0647d048b600 a
287 284 --- a/a Thu Jan 01 00:00:00 1970 +0000
288 285 +++ b/a Thu Jan 01 00:00:01 1970 +0000
289 286 @@ -1,1 +1,2 @@
290 287 a
291 288 +a
292 289 (run 'hg update' to get a working copy)
293 290
294 291 test merge
295 292
296 293 $ cd a
297 294 $ hg up -C 0
298 295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 296 $ echo a >> a
300 297 $ hg ci -Am adda2 -d '2 0'
301 298 created new head
302 299 $ hg merge
303 300 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 301 (branch merge, don't forget to commit)
305 302 $ hg ci -m merge -d '3 0'
306 303 $ cd ..
307 304 $ hg --traceback --cwd b pull ../a | \
308 305 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
309 306 pulling from ../a
310 307 searching for changes
311 308 adding changesets
312 309 adding manifests
313 310 adding file changes
314 311 added 2 changesets with 0 changes to 0 files
315 312 Content-Type: text/plain; charset="us-ascii"
316 313 MIME-Version: 1.0
317 314 Content-Transfer-Encoding: 7bit
318 315 X-Test: foo
319 316 Date: * (glob)
320 317 Subject: adda2
321 318 From: test@test.com
322 319 X-Hg-Notification: changeset 0a184ce6067f
323 320 Message-Id: <*> (glob)
324 321 To: baz@test.com, foo@bar
325 322
326 323 changeset 0a184ce6067f in b
327 324 description: adda2
328 325 diffstat:
329 326
330 327 a | 1 +
331 328 1 files changed, 1 insertions(+), 0 deletions(-)
332 329
333 330 diffs (6 lines):
334 331
335 332 diff -r cb9a9f314b8b -r 0a184ce6067f a
336 333 --- a/a Thu Jan 01 00:00:00 1970 +0000
337 334 +++ b/a Thu Jan 01 00:00:02 1970 +0000
338 335 @@ -1,1 +1,2 @@
339 336 a
340 337 +a
341 338 Content-Type: text/plain; charset="us-ascii"
342 339 MIME-Version: 1.0
343 340 Content-Transfer-Encoding: 7bit
344 341 X-Test: foo
345 342 Date: * (glob)
346 343 Subject: merge
347 344 From: test@test.com
348 345 X-Hg-Notification: changeset 6a0cf76b2701
349 346 Message-Id: <*> (glob)
350 347 To: baz@test.com, foo@bar
351 348
352 349 changeset 6a0cf76b2701 in b
353 350 description: merge
354 351 (run 'hg update' to get a working copy)
355 352
356 353 truncate multi-byte subject
357 354
358 355 $ cat <<EOF >> $HGRCPATH
359 356 > [notify]
360 357 > maxsubject = 4
361 358 > EOF
362 359 $ echo a >> a/a
363 360 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
364 361 > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
365 362 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
366 363 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
367 364 pulling from ../a
368 365 searching for changes
369 366 adding changesets
370 367 adding manifests
371 368 adding file changes
372 369 added 1 changesets with 1 changes to 1 files
373 370 Content-Type: text/plain; charset="us-ascii"
374 371 MIME-Version: 1.0
375 372 Content-Transfer-Encoding: 8bit
376 373 X-Test: foo
377 374 Date: * (glob)
378 375 Subject: \xc3\xa0... (esc)
379 376 From: test@test.com
380 377 X-Hg-Notification: changeset 7ea05ad269dc
381 378 Message-Id: <*> (glob)
382 379 To: baz@test.com, foo@bar
383 380
384 381 changeset 7ea05ad269dc in b
385 382 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
386 383 diffstat:
387 384
388 385 a | 1 +
389 386 1 files changed, 1 insertions(+), 0 deletions(-)
390 387
391 388 diffs (7 lines):
392 389
393 390 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
394 391 --- a/a Thu Jan 01 00:00:03 1970 +0000
395 392 +++ b/a Thu Jan 01 00:00:00 1970 +0000
396 393 @@ -1,2 +1,3 @@
397 394 a
398 395 a
399 396 +a
400 397 (run 'hg update' to get a working copy)
@@ -1,121 +1,118 b''
1 1
2 2 $ hg init test
3 3 $ cd test
4 4 $ echo a > a
5 5 $ hg ci -Ama
6 6 adding a
7 7 $ cd ..
8 8 $ hg clone test test2
9 9 updating to branch default
10 10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 11 $ cd test2
12 12 $ echo a >> a
13 13 $ hg ci -mb
14 14 $ req() {
15 15 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
16 16 > cat hg.pid >> $DAEMON_PIDS
17 17 > hg --cwd ../test2 push http://localhost:$HGPORT/
18 18 > "$TESTDIR/killdaemons.py"
19 19 > echo % serve errors
20 20 > cat errors.log
21 21 > }
22 22 $ cd ../test
23 23
24 24 expect ssl error
25 25
26 26 $ req
27 27 pushing to http://localhost:$HGPORT/
28 28 searching for changes
29 29 remote: ssl required
30 30 % serve errors
31 31
32 32 expect authorization error
33 33
34 34 $ echo '[web]' > .hg/hgrc
35 35 $ echo 'push_ssl = false' >> .hg/hgrc
36 36 $ req
37 37 pushing to http://localhost:$HGPORT/
38 38 searching for changes
39 39 abort: authorization failed
40 40 % serve errors
41 41
42 42 expect authorization error: must have authorized user
43 43
44 44 $ echo 'allow_push = unperson' >> .hg/hgrc
45 45 $ req
46 46 pushing to http://localhost:$HGPORT/
47 47 searching for changes
48 48 abort: authorization failed
49 49 % serve errors
50 50
51 51 expect success
52 52
53 53 $ echo 'allow_push = *' >> .hg/hgrc
54 54 $ echo '[hooks]' >> .hg/hgrc
55 55 $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup 0' >> .hg/hgrc
56 56 $ req
57 57 pushing to http://localhost:$HGPORT/
58 58 searching for changes
59 59 remote: adding changesets
60 60 remote: adding manifests
61 61 remote: adding file changes
62 62 remote: added 1 changesets with 1 changes to 1 files
63 63 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
64 64 % serve errors
65 65 $ hg rollback
66 66 repository tip rolled back to revision 0 (undo serve)
67 working directory now based on revision 0
68 67
69 68 expect success, server lacks the httpheader capability
70 69
71 70 $ CAP=httpheader
72 71 $ . "$TESTDIR/notcapable"
73 72 $ req
74 73 pushing to http://localhost:$HGPORT/
75 74 searching for changes
76 75 remote: adding changesets
77 76 remote: adding manifests
78 77 remote: adding file changes
79 78 remote: added 1 changesets with 1 changes to 1 files
80 79 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
81 80 % serve errors
82 81 $ hg rollback
83 82 repository tip rolled back to revision 0 (undo serve)
84 working directory now based on revision 0
85 83
86 84 expect success, server lacks the unbundlehash capability
87 85
88 86 $ CAP=unbundlehash
89 87 $ . "$TESTDIR/notcapable"
90 88 $ req
91 89 pushing to http://localhost:$HGPORT/
92 90 searching for changes
93 91 remote: adding changesets
94 92 remote: adding manifests
95 93 remote: adding file changes
96 94 remote: added 1 changesets with 1 changes to 1 files
97 95 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
98 96 % serve errors
99 97 $ hg rollback
100 98 repository tip rolled back to revision 0 (undo serve)
101 working directory now based on revision 0
102 99
103 100 expect authorization error: all users denied
104 101
105 102 $ echo '[web]' > .hg/hgrc
106 103 $ echo 'push_ssl = false' >> .hg/hgrc
107 104 $ echo 'deny_push = *' >> .hg/hgrc
108 105 $ req
109 106 pushing to http://localhost:$HGPORT/
110 107 searching for changes
111 108 abort: authorization failed
112 109 % serve errors
113 110
114 111 expect authorization error: some users denied, users must be authenticated
115 112
116 113 $ echo 'deny_push = unperson' >> .hg/hgrc
117 114 $ req
118 115 pushing to http://localhost:$HGPORT/
119 116 searching for changes
120 117 abort: authorization failed
121 118 % serve errors
@@ -1,119 +1,148 b''
1 1 setup repo
2 2 $ hg init t
3 3 $ cd t
4 4 $ echo a > a
5 5 $ hg commit -Am'add a'
6 6 adding a
7 7 $ hg verify
8 8 checking changesets
9 9 checking manifests
10 10 crosschecking files in changesets and manifests
11 11 checking files
12 12 1 files, 1 changesets, 1 total revisions
13 13 $ hg parents
14 14 changeset: 0:1f0dee641bb7
15 15 tag: tip
16 16 user: test
17 17 date: Thu Jan 01 00:00:00 1970 +0000
18 18 summary: add a
19 19
20 20
21 21 rollback to null revision
22 22 $ hg status
23 23 $ hg rollback
24 24 repository tip rolled back to revision -1 (undo commit)
25 25 working directory now based on revision -1
26 26 $ hg verify
27 27 checking changesets
28 28 checking manifests
29 29 crosschecking files in changesets and manifests
30 30 checking files
31 31 0 files, 0 changesets, 0 total revisions
32 32 $ hg parents
33 33 $ hg status
34 34 A a
35 35
36 36 Two changesets this time so we rollback to a real changeset
37 37 $ hg commit -m'add a again'
38 38 $ echo a >> a
39 39 $ hg commit -m'modify a'
40 40
41 41 Test issue 902 (current branch is preserved)
42 42 $ hg branch test
43 43 marked working directory as branch test
44 44 $ hg rollback
45 45 repository tip rolled back to revision 0 (undo commit)
46 46 working directory now based on revision 0
47 47 $ hg branch
48 48 default
49 49
50 50 Test issue 1635 (commit message saved)
51 51 $ cat .hg/last-message.txt ; echo
52 52 modify a
53 53
54 54 Test rollback of hg before issue 902 was fixed
55 55
56 56 $ hg commit -m "test3"
57 57 $ hg branch test
58 58 marked working directory as branch test
59 59 $ rm .hg/undo.branch
60 60 $ hg rollback
61 61 repository tip rolled back to revision 0 (undo commit)
62 62 named branch could not be reset: current branch is still 'test'
63 63 working directory now based on revision 0
64 64 $ hg branch
65 65 test
66 66
67 working dir unaffected by rollback: do not restore dirstate et. al.
68 $ hg log --template '{rev} {branch} {desc|firstline}\n'
69 0 default add a again
70 $ hg status
71 M a
72 $ hg bookmark foo
73 $ hg commit -m'modify a again'
74 $ echo b > b
75 $ hg commit -Am'add b'
76 adding b
77 $ hg log --template '{rev} {branch} {desc|firstline}\n'
78 2 test add b
79 1 test modify a again
80 0 default add a again
81 $ hg update default
82 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 $ hg bookmark bar
84 $ cat .hg/undo.branch ; echo
85 test
86 $ hg rollback
87 repository tip rolled back to revision 1 (undo commit)
88 $ hg id -n
89 0
90 $ hg branch
91 default
92 $ cat .hg/bookmarks.current ; echo
93 bar
94 $ hg bookmark --delete foo
95
67 96 rollback by pretxncommit saves commit message (issue 1635)
68 97
69 98 $ echo a >> a
70 99 $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
71 100 transaction abort!
72 101 rollback completed
73 102 abort: pretxncommit hook exited with status * (glob)
74 103 [255]
75 104 $ cat .hg/last-message.txt ; echo
76 105 precious commit message
77 106
78 107 same thing, but run $EDITOR
79 108
80 109 $ cat > editor << '__EOF__'
81 110 > #!/bin/sh
82 111 > echo "another precious commit message" > "$1"
83 112 > __EOF__
84 113 $ chmod +x editor
85 114 $ HGEDITOR="'`pwd`'"/editor hg --config hooks.pretxncommit=false commit 2>&1
86 115 transaction abort!
87 116 rollback completed
88 117 note: commit message saved in .hg/last-message.txt
89 118 abort: pretxncommit hook exited with status * (glob)
90 119 [255]
91 120 $ cat .hg/last-message.txt
92 121 another precious commit message
93 122
94 123 test rollback on served repository
95 124
96 125 $ hg commit -m "precious commit message"
97 126 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
98 127 $ cat hg.pid >> $DAEMON_PIDS
99 128 $ cd ..
100 129 $ hg clone http://localhost:$HGPORT u
101 130 requesting all changes
102 131 adding changesets
103 132 adding manifests
104 133 adding file changes
105 added 2 changesets with 2 changes to 1 files
134 added 3 changesets with 2 changes to 1 files (+1 heads)
106 135 updating to branch default
107 136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 137 $ cd u
109 138 $ hg id default
110 8902593132ae
139 068774709090
111 140
112 141 now rollback and observe that 'hg serve' reloads the repository and
113 142 presents the correct tip changeset:
114 143
115 144 $ hg -R ../t rollback
116 repository tip rolled back to revision 0 (undo commit)
145 repository tip rolled back to revision 1 (undo commit)
117 146 working directory now based on revision 0
118 147 $ hg id default
119 23b0221f3370
148 791dd2169706
@@ -1,208 +1,203 b''
1 1 Test basic functionality of url#rev syntax
2 2
3 3 $ hg init repo
4 4 $ cd repo
5 5 $ echo a > a
6 6 $ hg ci -qAm 'add a'
7 7 $ hg branch foo
8 8 marked working directory as branch foo
9 9 $ echo >> a
10 10 $ hg ci -m 'change a'
11 11 $ cd ..
12 12
13 13 $ hg clone 'repo#foo' clone
14 14 adding changesets
15 15 adding manifests
16 16 adding file changes
17 17 added 2 changesets with 2 changes to 1 files
18 18 updating to branch foo
19 19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 20
21 21 $ hg --cwd clone heads
22 22 changeset: 1:cd2a86ecc814
23 23 branch: foo
24 24 tag: tip
25 25 user: test
26 26 date: Thu Jan 01 00:00:00 1970 +0000
27 27 summary: change a
28 28
29 29 changeset: 0:1f0dee641bb7
30 30 user: test
31 31 date: Thu Jan 01 00:00:00 1970 +0000
32 32 summary: add a
33 33
34 34 $ hg --cwd clone parents
35 35 changeset: 1:cd2a86ecc814
36 36 branch: foo
37 37 tag: tip
38 38 user: test
39 39 date: Thu Jan 01 00:00:00 1970 +0000
40 40 summary: change a
41 41
42 42 $ cat clone/.hg/hgrc
43 43 [paths]
44 44 default = $TESTTMP/repo#foo
45 45
46 46 Changing original repo:
47 47
48 48 $ cd repo
49 49
50 50 $ echo >> a
51 51 $ hg ci -m 'new head of branch foo'
52 52
53 53 $ hg up -qC default
54 54 $ echo bar > bar
55 55 $ hg ci -qAm 'add bar'
56 56
57 57 $ hg log
58 58 changeset: 3:4cd725637392
59 59 tag: tip
60 60 parent: 0:1f0dee641bb7
61 61 user: test
62 62 date: Thu Jan 01 00:00:00 1970 +0000
63 63 summary: add bar
64 64
65 65 changeset: 2:faba9097cad4
66 66 branch: foo
67 67 user: test
68 68 date: Thu Jan 01 00:00:00 1970 +0000
69 69 summary: new head of branch foo
70 70
71 71 changeset: 1:cd2a86ecc814
72 72 branch: foo
73 73 user: test
74 74 date: Thu Jan 01 00:00:00 1970 +0000
75 75 summary: change a
76 76
77 77 changeset: 0:1f0dee641bb7
78 78 user: test
79 79 date: Thu Jan 01 00:00:00 1970 +0000
80 80 summary: add a
81 81
82 82 $ hg -q outgoing '../clone#foo'
83 83 2:faba9097cad4
84 84
85 85 $ hg -q push '../clone#foo'
86 86
87 87 $ hg --cwd ../clone heads
88 88 changeset: 2:faba9097cad4
89 89 branch: foo
90 90 tag: tip
91 91 user: test
92 92 date: Thu Jan 01 00:00:00 1970 +0000
93 93 summary: new head of branch foo
94 94
95 95 changeset: 0:1f0dee641bb7
96 96 user: test
97 97 date: Thu Jan 01 00:00:00 1970 +0000
98 98 summary: add a
99 99
100 100 $ cd ..
101 101
102 102 $ cd clone
103 103 $ hg rollback
104 104 repository tip rolled back to revision 1 (undo push)
105 working directory now based on revision 1
106 105
107 106 $ hg -q incoming
108 107 2:faba9097cad4
109 108
110 109 $ hg -q pull
111 110
112 111 $ hg heads
113 112 changeset: 2:faba9097cad4
114 113 branch: foo
115 114 tag: tip
116 115 user: test
117 116 date: Thu Jan 01 00:00:00 1970 +0000
118 117 summary: new head of branch foo
119 118
120 119 changeset: 0:1f0dee641bb7
121 120 user: test
122 121 date: Thu Jan 01 00:00:00 1970 +0000
123 122 summary: add a
124 123
125 124 Pull should not have updated:
126 125
127 126 $ hg parents -q
128 127 1:cd2a86ecc814
129 128
130 129 Going back to the default branch:
131 130
132 131 $ hg up -C 0
133 132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 133
135 134 $ hg parents
136 135 changeset: 0:1f0dee641bb7
137 136 user: test
138 137 date: Thu Jan 01 00:00:00 1970 +0000
139 138 summary: add a
140 139
141 140 No new revs, no update:
142 141
143 142 $ hg pull -qu
144 143
145 144 $ hg parents -q
146 145 0:1f0dee641bb7
147 146
148 147 $ hg rollback
149 148 repository tip rolled back to revision 1 (undo pull)
150 working directory now based on revision 1
151
152 $ hg up -C 0
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 149
155 150 $ hg parents -q
156 151 0:1f0dee641bb7
157 152
158 153 Pull -u takes us back to branch foo:
159 154
160 155 $ hg pull -qu
161 156
162 157 $ hg parents
163 158 changeset: 2:faba9097cad4
164 159 branch: foo
165 160 tag: tip
166 161 user: test
167 162 date: Thu Jan 01 00:00:00 1970 +0000
168 163 summary: new head of branch foo
169 164
170 165 $ hg rollback
171 166 repository tip rolled back to revision 1 (undo pull)
172 167 working directory now based on revision 0
173 168
174 169 $ hg up -C 0
175 170 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 171
177 172 $ hg parents -q
178 173 0:1f0dee641bb7
179 174
180 175 $ hg heads -q
181 176 1:cd2a86ecc814
182 177 0:1f0dee641bb7
183 178
184 179 $ hg pull -qur default default
185 180
186 181 $ hg parents
187 182 changeset: 3:4cd725637392
188 183 tag: tip
189 184 parent: 0:1f0dee641bb7
190 185 user: test
191 186 date: Thu Jan 01 00:00:00 1970 +0000
192 187 summary: add bar
193 188
194 189 $ hg heads
195 190 changeset: 3:4cd725637392
196 191 tag: tip
197 192 parent: 0:1f0dee641bb7
198 193 user: test
199 194 date: Thu Jan 01 00:00:00 1970 +0000
200 195 summary: add bar
201 196
202 197 changeset: 2:faba9097cad4
203 198 branch: foo
204 199 user: test
205 200 date: Thu Jan 01 00:00:00 1970 +0000
206 201 summary: new head of branch foo
207 202
208 203
General Comments 0
You need to be logged in to leave comments. Login now