##// END OF EJS Templates
phases: pass phase names to hooks instead of internal values
Kevin Bullock -
r34877:eb1b964b default
parent child Browse files
Show More
@@ -1,666 +1,666 b''
1 1 """ Mercurial phases support code
2 2
3 3 ---
4 4
5 5 Copyright 2011 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 6 Logilab SA <contact@logilab.fr>
7 7 Augie Fackler <durin42@gmail.com>
8 8
9 9 This software may be used and distributed according to the terms
10 10 of the GNU General Public License version 2 or any later version.
11 11
12 12 ---
13 13
14 14 This module implements most phase logic in mercurial.
15 15
16 16
17 17 Basic Concept
18 18 =============
19 19
20 20 A 'changeset phase' is an indicator that tells us how a changeset is
21 21 manipulated and communicated. The details of each phase is described
22 22 below, here we describe the properties they have in common.
23 23
24 24 Like bookmarks, phases are not stored in history and thus are not
25 25 permanent and leave no audit trail.
26 26
27 27 First, no changeset can be in two phases at once. Phases are ordered,
28 28 so they can be considered from lowest to highest. The default, lowest
29 29 phase is 'public' - this is the normal phase of existing changesets. A
30 30 child changeset can not be in a lower phase than its parents.
31 31
32 32 These phases share a hierarchy of traits:
33 33
34 34 immutable shared
35 35 public: X X
36 36 draft: X
37 37 secret:
38 38
39 39 Local commits are draft by default.
40 40
41 41 Phase Movement and Exchange
42 42 ===========================
43 43
44 44 Phase data is exchanged by pushkey on pull and push. Some servers have
45 45 a publish option set, we call such a server a "publishing server".
46 46 Pushing a draft changeset to a publishing server changes the phase to
47 47 public.
48 48
49 49 A small list of fact/rules define the exchange of phase:
50 50
51 51 * old client never changes server states
52 52 * pull never changes server states
53 53 * publish and old server changesets are seen as public by client
54 54 * any secret changeset seen in another repository is lowered to at
55 55 least draft
56 56
57 57 Here is the final table summing up the 49 possible use cases of phase
58 58 exchange:
59 59
60 60 server
61 61 old publish non-publish
62 62 N X N D P N D P
63 63 old client
64 64 pull
65 65 N - X/X - X/D X/P - X/D X/P
66 66 X - X/X - X/D X/P - X/D X/P
67 67 push
68 68 X X/X X/X X/P X/P X/P X/D X/D X/P
69 69 new client
70 70 pull
71 71 N - P/X - P/D P/P - D/D P/P
72 72 D - P/X - P/D P/P - D/D P/P
73 73 P - P/X - P/D P/P - P/D P/P
74 74 push
75 75 D P/X P/X P/P P/P P/P D/D D/D P/P
76 76 P P/X P/X P/P P/P P/P P/P P/P P/P
77 77
78 78 Legend:
79 79
80 80 A/B = final state on client / state on server
81 81
82 82 * N = new/not present,
83 83 * P = public,
84 84 * D = draft,
85 85 * X = not tracked (i.e., the old client or server has no internal
86 86 way of recording the phase.)
87 87
88 88 passive = only pushes
89 89
90 90
91 91 A cell here can be read like this:
92 92
93 93 "When a new client pushes a draft changeset (D) to a publishing
94 94 server where it's not present (N), it's marked public on both
95 95 sides (P/P)."
96 96
97 97 Note: old client behave as a publishing server with draft only content
98 98 - other people see it as public
99 99 - content is pushed as draft
100 100
101 101 """
102 102
103 103 from __future__ import absolute_import
104 104
105 105 import errno
106 106 import struct
107 107
108 108 from .i18n import _
109 109 from .node import (
110 110 bin,
111 111 hex,
112 112 nullid,
113 113 nullrev,
114 114 short,
115 115 )
116 116 from . import (
117 117 error,
118 118 smartset,
119 119 txnutil,
120 120 util,
121 121 )
122 122
123 123 _fphasesentry = struct.Struct('>i20s')
124 124
125 125 allphases = public, draft, secret = range(3)
126 126 trackedphases = allphases[1:]
127 127 phasenames = ['public', 'draft', 'secret']
128 128
129 129 def _readroots(repo, phasedefaults=None):
130 130 """Read phase roots from disk
131 131
132 132 phasedefaults is a list of fn(repo, roots) callable, which are
133 133 executed if the phase roots file does not exist. When phases are
134 134 being initialized on an existing repository, this could be used to
135 135 set selected changesets phase to something else than public.
136 136
137 137 Return (roots, dirty) where dirty is true if roots differ from
138 138 what is being stored.
139 139 """
140 140 repo = repo.unfiltered()
141 141 dirty = False
142 142 roots = [set() for i in allphases]
143 143 try:
144 144 f, pending = txnutil.trypending(repo.root, repo.svfs, 'phaseroots')
145 145 try:
146 146 for line in f:
147 147 phase, nh = line.split()
148 148 roots[int(phase)].add(bin(nh))
149 149 finally:
150 150 f.close()
151 151 except IOError as inst:
152 152 if inst.errno != errno.ENOENT:
153 153 raise
154 154 if phasedefaults:
155 155 for f in phasedefaults:
156 156 roots = f(repo, roots)
157 157 dirty = True
158 158 return roots, dirty
159 159
160 160 def binaryencode(phasemapping):
161 161 """encode a 'phase -> nodes' mapping into a binary stream
162 162
163 163 Since phases are integer the mapping is actually a python list:
164 164 [[PUBLIC_HEADS], [DRAFTS_HEADS], [SECRET_HEADS]]
165 165 """
166 166 binarydata = []
167 167 for phase, nodes in enumerate(phasemapping):
168 168 for head in nodes:
169 169 binarydata.append(_fphasesentry.pack(phase, head))
170 170 return ''.join(binarydata)
171 171
172 172 def binarydecode(stream):
173 173 """decode a binary stream into a 'phase -> nodes' mapping
174 174
175 175 Since phases are integer the mapping is actually a python list."""
176 176 headsbyphase = [[] for i in allphases]
177 177 entrysize = _fphasesentry.size
178 178 while True:
179 179 entry = stream.read(entrysize)
180 180 if len(entry) < entrysize:
181 181 if entry:
182 182 raise error.Abort(_('bad phase-heads stream'))
183 183 break
184 184 phase, node = _fphasesentry.unpack(entry)
185 185 headsbyphase[phase].append(node)
186 186 return headsbyphase
187 187
188 188 def _trackphasechange(data, rev, old, new):
189 189 """add a phase move the <data> dictionnary
190 190
191 191 If data is None, nothing happens.
192 192 """
193 193 if data is None:
194 194 return
195 195 existing = data.get(rev)
196 196 if existing is not None:
197 197 old = existing[0]
198 198 data[rev] = (old, new)
199 199
200 200 class phasecache(object):
201 201 def __init__(self, repo, phasedefaults, _load=True):
202 202 if _load:
203 203 # Cheap trick to allow shallow-copy without copy module
204 204 self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
205 205 self._phaserevs = None
206 206 self._phasesets = None
207 207 self.filterunknown(repo)
208 208 self.opener = repo.svfs
209 209
210 210 def getrevset(self, repo, phases):
211 211 """return a smartset for the given phases"""
212 212 self.loadphaserevs(repo) # ensure phase's sets are loaded
213 213
214 214 if self._phasesets and all(self._phasesets[p] is not None
215 215 for p in phases):
216 216 # fast path - use _phasesets
217 217 revs = self._phasesets[phases[0]]
218 218 if len(phases) > 1:
219 219 revs = revs.copy() # only copy when needed
220 220 for p in phases[1:]:
221 221 revs.update(self._phasesets[p])
222 222 if repo.changelog.filteredrevs:
223 223 revs = revs - repo.changelog.filteredrevs
224 224 return smartset.baseset(revs)
225 225 else:
226 226 # slow path - enumerate all revisions
227 227 phase = self.phase
228 228 revs = (r for r in repo if phase(repo, r) in phases)
229 229 return smartset.generatorset(revs, iterasc=True)
230 230
231 231 def copy(self):
232 232 # Shallow copy meant to ensure isolation in
233 233 # advance/retractboundary(), nothing more.
234 234 ph = self.__class__(None, None, _load=False)
235 235 ph.phaseroots = self.phaseroots[:]
236 236 ph.dirty = self.dirty
237 237 ph.opener = self.opener
238 238 ph._phaserevs = self._phaserevs
239 239 ph._phasesets = self._phasesets
240 240 return ph
241 241
242 242 def replace(self, phcache):
243 243 """replace all values in 'self' with content of phcache"""
244 244 for a in ('phaseroots', 'dirty', 'opener', '_phaserevs', '_phasesets'):
245 245 setattr(self, a, getattr(phcache, a))
246 246
247 247 def _getphaserevsnative(self, repo):
248 248 repo = repo.unfiltered()
249 249 nativeroots = []
250 250 for phase in trackedphases:
251 251 nativeroots.append(map(repo.changelog.rev, self.phaseroots[phase]))
252 252 return repo.changelog.computephases(nativeroots)
253 253
254 254 def _computephaserevspure(self, repo):
255 255 repo = repo.unfiltered()
256 256 revs = [public] * len(repo.changelog)
257 257 self._phaserevs = revs
258 258 self._populatephaseroots(repo)
259 259 for phase in trackedphases:
260 260 roots = list(map(repo.changelog.rev, self.phaseroots[phase]))
261 261 if roots:
262 262 for rev in roots:
263 263 revs[rev] = phase
264 264 for rev in repo.changelog.descendants(roots):
265 265 revs[rev] = phase
266 266
267 267 def loadphaserevs(self, repo):
268 268 """ensure phase information is loaded in the object"""
269 269 if self._phaserevs is None:
270 270 try:
271 271 res = self._getphaserevsnative(repo)
272 272 self._phaserevs, self._phasesets = res
273 273 except AttributeError:
274 274 self._computephaserevspure(repo)
275 275
276 276 def invalidate(self):
277 277 self._phaserevs = None
278 278 self._phasesets = None
279 279
280 280 def _populatephaseroots(self, repo):
281 281 """Fills the _phaserevs cache with phases for the roots.
282 282 """
283 283 cl = repo.changelog
284 284 phaserevs = self._phaserevs
285 285 for phase in trackedphases:
286 286 roots = map(cl.rev, self.phaseroots[phase])
287 287 for root in roots:
288 288 phaserevs[root] = phase
289 289
290 290 def phase(self, repo, rev):
291 291 # We need a repo argument here to be able to build _phaserevs
292 292 # if necessary. The repository instance is not stored in
293 293 # phasecache to avoid reference cycles. The changelog instance
294 294 # is not stored because it is a filecache() property and can
295 295 # be replaced without us being notified.
296 296 if rev == nullrev:
297 297 return public
298 298 if rev < nullrev:
299 299 raise ValueError(_('cannot lookup negative revision'))
300 300 if self._phaserevs is None or rev >= len(self._phaserevs):
301 301 self.invalidate()
302 302 self.loadphaserevs(repo)
303 303 return self._phaserevs[rev]
304 304
305 305 def write(self):
306 306 if not self.dirty:
307 307 return
308 308 f = self.opener('phaseroots', 'w', atomictemp=True, checkambig=True)
309 309 try:
310 310 self._write(f)
311 311 finally:
312 312 f.close()
313 313
314 314 def _write(self, fp):
315 315 for phase, roots in enumerate(self.phaseroots):
316 316 for h in roots:
317 317 fp.write('%i %s\n' % (phase, hex(h)))
318 318 self.dirty = False
319 319
320 320 def _updateroots(self, phase, newroots, tr):
321 321 self.phaseroots[phase] = newroots
322 322 self.invalidate()
323 323 self.dirty = True
324 324
325 325 tr.addfilegenerator('phase', ('phaseroots',), self._write)
326 326 tr.hookargs['phases_moved'] = '1'
327 327
328 328 def registernew(self, repo, tr, targetphase, nodes):
329 329 repo = repo.unfiltered()
330 330 self._retractboundary(repo, tr, targetphase, nodes)
331 331 if tr is not None and 'phases' in tr.changes:
332 332 phasetracking = tr.changes['phases']
333 333 torev = repo.changelog.rev
334 334 phase = self.phase
335 335 for n in nodes:
336 336 rev = torev(n)
337 337 revphase = phase(repo, rev)
338 338 _trackphasechange(phasetracking, rev, None, revphase)
339 339 repo.invalidatevolatilesets()
340 340
341 341 def advanceboundary(self, repo, tr, targetphase, nodes):
342 342 """Set all 'nodes' to phase 'targetphase'
343 343
344 344 Nodes with a phase lower than 'targetphase' are not affected.
345 345 """
346 346 # Be careful to preserve shallow-copied values: do not update
347 347 # phaseroots values, replace them.
348 348 if tr is None:
349 349 phasetracking = None
350 350 else:
351 351 phasetracking = tr.changes.get('phases')
352 352
353 353 repo = repo.unfiltered()
354 354
355 355 delroots = [] # set of root deleted by this path
356 356 for phase in xrange(targetphase + 1, len(allphases)):
357 357 # filter nodes that are not in a compatible phase already
358 358 nodes = [n for n in nodes
359 359 if self.phase(repo, repo[n].rev()) >= phase]
360 360 if not nodes:
361 361 break # no roots to move anymore
362 362
363 363 olds = self.phaseroots[phase]
364 364
365 365 affected = repo.revs('%ln::%ln', olds, nodes)
366 366 for r in affected:
367 367 _trackphasechange(phasetracking, r, self.phase(repo, r),
368 368 targetphase)
369 369
370 370 roots = set(ctx.node() for ctx in repo.set(
371 371 'roots((%ln::) - %ld)', olds, affected))
372 372 if olds != roots:
373 373 self._updateroots(phase, roots, tr)
374 374 # some roots may need to be declared for lower phases
375 375 delroots.extend(olds - roots)
376 376 # declare deleted root in the target phase
377 377 if targetphase != 0:
378 378 self._retractboundary(repo, tr, targetphase, delroots)
379 379 repo.invalidatevolatilesets()
380 380
381 381 def retractboundary(self, repo, tr, targetphase, nodes):
382 382 oldroots = self.phaseroots[:targetphase + 1]
383 383 if tr is None:
384 384 phasetracking = None
385 385 else:
386 386 phasetracking = tr.changes.get('phases')
387 387 repo = repo.unfiltered()
388 388 if (self._retractboundary(repo, tr, targetphase, nodes)
389 389 and phasetracking is not None):
390 390
391 391 # find the affected revisions
392 392 new = self.phaseroots[targetphase]
393 393 old = oldroots[targetphase]
394 394 affected = set(repo.revs('(%ln::) - (%ln::)', new, old))
395 395
396 396 # find the phase of the affected revision
397 397 for phase in xrange(targetphase, -1, -1):
398 398 if phase:
399 399 roots = oldroots[phase]
400 400 revs = set(repo.revs('%ln::%ld', roots, affected))
401 401 affected -= revs
402 402 else: # public phase
403 403 revs = affected
404 404 for r in revs:
405 405 _trackphasechange(phasetracking, r, phase, targetphase)
406 406 repo.invalidatevolatilesets()
407 407
408 408 def _retractboundary(self, repo, tr, targetphase, nodes):
409 409 # Be careful to preserve shallow-copied values: do not update
410 410 # phaseroots values, replace them.
411 411
412 412 repo = repo.unfiltered()
413 413 currentroots = self.phaseroots[targetphase]
414 414 finalroots = oldroots = set(currentroots)
415 415 newroots = [n for n in nodes
416 416 if self.phase(repo, repo[n].rev()) < targetphase]
417 417 if newroots:
418 418
419 419 if nullid in newroots:
420 420 raise error.Abort(_('cannot change null revision phase'))
421 421 currentroots = currentroots.copy()
422 422 currentroots.update(newroots)
423 423
424 424 # Only compute new roots for revs above the roots that are being
425 425 # retracted.
426 426 minnewroot = min(repo[n].rev() for n in newroots)
427 427 aboveroots = [n for n in currentroots
428 428 if repo[n].rev() >= minnewroot]
429 429 updatedroots = repo.set('roots(%ln::)', aboveroots)
430 430
431 431 finalroots = set(n for n in currentroots if repo[n].rev() <
432 432 minnewroot)
433 433 finalroots.update(ctx.node() for ctx in updatedroots)
434 434 if finalroots != oldroots:
435 435 self._updateroots(targetphase, finalroots, tr)
436 436 return True
437 437 return False
438 438
439 439 def filterunknown(self, repo):
440 440 """remove unknown nodes from the phase boundary
441 441
442 442 Nothing is lost as unknown nodes only hold data for their descendants.
443 443 """
444 444 filtered = False
445 445 nodemap = repo.changelog.nodemap # to filter unknown nodes
446 446 for phase, nodes in enumerate(self.phaseroots):
447 447 missing = sorted(node for node in nodes if node not in nodemap)
448 448 if missing:
449 449 for mnode in missing:
450 450 repo.ui.debug(
451 451 'removing unknown node %s from %i-phase boundary\n'
452 452 % (short(mnode), phase))
453 453 nodes.symmetric_difference_update(missing)
454 454 filtered = True
455 455 if filtered:
456 456 self.dirty = True
457 457 # filterunknown is called by repo.destroyed, we may have no changes in
458 458 # root but phaserevs contents is certainly invalid (or at least we
459 459 # have not proper way to check that). related to issue 3858.
460 460 #
461 461 # The other caller is __init__ that have no _phaserevs initialized
462 462 # anyway. If this change we should consider adding a dedicated
463 463 # "destroyed" function to phasecache or a proper cache key mechanism
464 464 # (see branchmap one)
465 465 self.invalidate()
466 466
467 467 def advanceboundary(repo, tr, targetphase, nodes):
468 468 """Add nodes to a phase changing other nodes phases if necessary.
469 469
470 470 This function move boundary *forward* this means that all nodes
471 471 are set in the target phase or kept in a *lower* phase.
472 472
473 473 Simplify boundary to contains phase roots only."""
474 474 phcache = repo._phasecache.copy()
475 475 phcache.advanceboundary(repo, tr, targetphase, nodes)
476 476 repo._phasecache.replace(phcache)
477 477
478 478 def retractboundary(repo, tr, targetphase, nodes):
479 479 """Set nodes back to a phase changing other nodes phases if
480 480 necessary.
481 481
482 482 This function move boundary *backward* this means that all nodes
483 483 are set in the target phase or kept in a *higher* phase.
484 484
485 485 Simplify boundary to contains phase roots only."""
486 486 phcache = repo._phasecache.copy()
487 487 phcache.retractboundary(repo, tr, targetphase, nodes)
488 488 repo._phasecache.replace(phcache)
489 489
490 490 def registernew(repo, tr, targetphase, nodes):
491 491 """register a new revision and its phase
492 492
493 493 Code adding revisions to the repository should use this function to
494 494 set new changeset in their target phase (or higher).
495 495 """
496 496 phcache = repo._phasecache.copy()
497 497 phcache.registernew(repo, tr, targetphase, nodes)
498 498 repo._phasecache.replace(phcache)
499 499
500 500 def listphases(repo):
501 501 """List phases root for serialization over pushkey"""
502 502 # Use ordered dictionary so behavior is deterministic.
503 503 keys = util.sortdict()
504 504 value = '%i' % draft
505 505 cl = repo.unfiltered().changelog
506 506 for root in repo._phasecache.phaseroots[draft]:
507 507 if repo._phasecache.phase(repo, cl.rev(root)) <= draft:
508 508 keys[hex(root)] = value
509 509
510 510 if repo.publishing():
511 511 # Add an extra data to let remote know we are a publishing
512 512 # repo. Publishing repo can't just pretend they are old repo.
513 513 # When pushing to a publishing repo, the client still need to
514 514 # push phase boundary
515 515 #
516 516 # Push do not only push changeset. It also push phase data.
517 517 # New phase data may apply to common changeset which won't be
518 518 # push (as they are common). Here is a very simple example:
519 519 #
520 520 # 1) repo A push changeset X as draft to repo B
521 521 # 2) repo B make changeset X public
522 522 # 3) repo B push to repo A. X is not pushed but the data that
523 523 # X as now public should
524 524 #
525 525 # The server can't handle it on it's own as it has no idea of
526 526 # client phase data.
527 527 keys['publishing'] = 'True'
528 528 return keys
529 529
530 530 def pushphase(repo, nhex, oldphasestr, newphasestr):
531 531 """List phases root for serialization over pushkey"""
532 532 repo = repo.unfiltered()
533 533 with repo.lock():
534 534 currentphase = repo[nhex].phase()
535 535 newphase = abs(int(newphasestr)) # let's avoid negative index surprise
536 536 oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise
537 537 if currentphase == oldphase and newphase < oldphase:
538 538 with repo.transaction('pushkey-phase') as tr:
539 539 advanceboundary(repo, tr, newphase, [bin(nhex)])
540 540 return True
541 541 elif currentphase == newphase:
542 542 # raced, but got correct result
543 543 return True
544 544 else:
545 545 return False
546 546
547 547 def subsetphaseheads(repo, subset):
548 548 """Finds the phase heads for a subset of a history
549 549
550 550 Returns a list indexed by phase number where each item is a list of phase
551 551 head nodes.
552 552 """
553 553 cl = repo.changelog
554 554
555 555 headsbyphase = [[] for i in allphases]
556 556 # No need to keep track of secret phase; any heads in the subset that
557 557 # are not mentioned are implicitly secret.
558 558 for phase in allphases[:-1]:
559 559 revset = "heads(%%ln & %s())" % phasenames[phase]
560 560 headsbyphase[phase] = [cl.node(r) for r in repo.revs(revset, subset)]
561 561 return headsbyphase
562 562
563 563 def updatephases(repo, trgetter, headsbyphase):
564 564 """Updates the repo with the given phase heads"""
565 565 # Now advance phase boundaries of all but secret phase
566 566 #
567 567 # run the update (and fetch transaction) only if there are actually things
568 568 # to update. This avoid creating empty transaction during no-op operation.
569 569
570 570 for phase in allphases[:-1]:
571 571 revset = '%%ln - %s()' % phasenames[phase]
572 572 heads = [c.node() for c in repo.set(revset, headsbyphase[phase])]
573 573 if heads:
574 574 advanceboundary(repo, trgetter(), phase, heads)
575 575
576 576 def analyzeremotephases(repo, subset, roots):
577 577 """Compute phases heads and root in a subset of node from root dict
578 578
579 579 * subset is heads of the subset
580 580 * roots is {<nodeid> => phase} mapping. key and value are string.
581 581
582 582 Accept unknown element input
583 583 """
584 584 repo = repo.unfiltered()
585 585 # build list from dictionary
586 586 draftroots = []
587 587 nodemap = repo.changelog.nodemap # to filter unknown nodes
588 588 for nhex, phase in roots.iteritems():
589 589 if nhex == 'publishing': # ignore data related to publish option
590 590 continue
591 591 node = bin(nhex)
592 592 phase = int(phase)
593 593 if phase == public:
594 594 if node != nullid:
595 595 repo.ui.warn(_('ignoring inconsistent public root'
596 596 ' from remote: %s\n') % nhex)
597 597 elif phase == draft:
598 598 if node in nodemap:
599 599 draftroots.append(node)
600 600 else:
601 601 repo.ui.warn(_('ignoring unexpected root from remote: %i %s\n')
602 602 % (phase, nhex))
603 603 # compute heads
604 604 publicheads = newheads(repo, subset, draftroots)
605 605 return publicheads, draftroots
606 606
607 607 class remotephasessummary(object):
608 608 """summarize phase information on the remote side
609 609
610 610 :publishing: True is the remote is publishing
611 611 :publicheads: list of remote public phase heads (nodes)
612 612 :draftheads: list of remote draft phase heads (nodes)
613 613 :draftroots: list of remote draft phase root (nodes)
614 614 """
615 615
616 616 def __init__(self, repo, remotesubset, remoteroots):
617 617 unfi = repo.unfiltered()
618 618 self._allremoteroots = remoteroots
619 619
620 620 self.publishing = remoteroots.get('publishing', False)
621 621
622 622 ana = analyzeremotephases(repo, remotesubset, remoteroots)
623 623 self.publicheads, self.draftroots = ana
624 624 # Get the list of all "heads" revs draft on remote
625 625 dheads = unfi.set('heads(%ln::%ln)', self.draftroots, remotesubset)
626 626 self.draftheads = [c.node() for c in dheads]
627 627
628 628 def newheads(repo, heads, roots):
629 629 """compute new head of a subset minus another
630 630
631 631 * `heads`: define the first subset
632 632 * `roots`: define the second we subtract from the first"""
633 633 repo = repo.unfiltered()
634 634 revset = repo.set('heads((%ln + parents(%ln)) - (%ln::%ln))',
635 635 heads, roots, roots, heads)
636 636 return [c.node() for c in revset]
637 637
638 638
639 639 def newcommitphase(ui):
640 640 """helper to get the target phase of new commit
641 641
642 642 Handle all possible values for the phases.new-commit options.
643 643
644 644 """
645 645 v = ui.config('phases', 'new-commit')
646 646 try:
647 647 return phasenames.index(v)
648 648 except ValueError:
649 649 try:
650 650 return int(v)
651 651 except ValueError:
652 652 msg = _("phases.new-commit: not a valid phase name ('%s')")
653 653 raise error.ConfigError(msg % v)
654 654
655 655 def hassecret(repo):
656 656 """utility function that check if a repo have any secret changeset."""
657 657 return bool(repo._phasecache.phaseroots[2])
658 658
659 659 def preparehookargs(node, old, new):
660 660 if old is None:
661 661 old = ''
662 662 else:
663 old = '%s' % old
663 old = phasenames[old]
664 664 return {'node': node,
665 665 'oldphase': old,
666 'phase': '%s' % new}
666 'phase': phasenames[new]}
@@ -1,825 +1,825 b''
1 1
2 2 $ cat >> $HGRCPATH << EOF
3 3 > [extensions]
4 4 > phasereport=$TESTDIR/testlib/ext-phase-report.py
5 5 > [hooks]
6 6 > txnclose-phase.test = echo "test-hook-close-phase: \$HG_NODE: \$HG_OLDPHASE -> \$HG_PHASE"
7 7 > EOF
8 8
9 9 $ hglog() { hg log --template "{rev} {phaseidx} {desc}\n" $*; }
10 10 $ mkcommit() {
11 11 > echo "$1" > "$1"
12 12 > hg add "$1"
13 13 > message="$1"
14 14 > shift
15 15 > hg ci -m "$message" $*
16 16 > }
17 17
18 18 $ hg init initialrepo
19 19 $ cd initialrepo
20 20
21 21 Cannot change null revision phase
22 22
23 23 $ hg phase --force --secret null
24 24 abort: cannot change null revision phase
25 25 [255]
26 26 $ hg phase null
27 27 -1: public
28 28
29 29 $ mkcommit A
30 30 test-debug-phase: new rev 0: x -> 1
31 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> 1
31 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> draft
32 32
33 33 New commit are draft by default
34 34
35 35 $ hglog
36 36 0 1 A
37 37
38 38 Following commit are draft too
39 39
40 40 $ mkcommit B
41 41 test-debug-phase: new rev 1: x -> 1
42 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> 1
42 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> draft
43 43
44 44 $ hglog
45 45 1 1 B
46 46 0 1 A
47 47
48 48 Draft commit are properly created over public one:
49 49
50 50 $ hg phase --public .
51 51 test-debug-phase: move rev 0: 1 -> 0
52 52 test-debug-phase: move rev 1: 1 -> 0
53 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: 1 -> 0
54 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: 1 -> 0
53 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: draft -> public
54 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: draft -> public
55 55 $ hg phase
56 56 1: public
57 57 $ hglog
58 58 1 0 B
59 59 0 0 A
60 60
61 61 $ mkcommit C
62 62 test-debug-phase: new rev 2: x -> 1
63 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> 1
63 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> draft
64 64 $ mkcommit D
65 65 test-debug-phase: new rev 3: x -> 1
66 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> 1
66 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> draft
67 67
68 68 $ hglog
69 69 3 1 D
70 70 2 1 C
71 71 1 0 B
72 72 0 0 A
73 73
74 74 Test creating changeset as secret
75 75
76 76 $ mkcommit E --config phases.new-commit='secret'
77 77 test-debug-phase: new rev 4: x -> 2
78 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: -> 2
78 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: -> secret
79 79 $ hglog
80 80 4 2 E
81 81 3 1 D
82 82 2 1 C
83 83 1 0 B
84 84 0 0 A
85 85
86 86 Test the secret property is inherited
87 87
88 88 $ mkcommit H
89 89 test-debug-phase: new rev 5: x -> 2
90 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: -> 2
90 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: -> secret
91 91 $ hglog
92 92 5 2 H
93 93 4 2 E
94 94 3 1 D
95 95 2 1 C
96 96 1 0 B
97 97 0 0 A
98 98
99 99 Even on merge
100 100
101 101 $ hg up -q 1
102 102 $ mkcommit "B'"
103 103 test-debug-phase: new rev 6: x -> 1
104 104 created new head
105 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> 1
105 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> draft
106 106 $ hglog
107 107 6 1 B'
108 108 5 2 H
109 109 4 2 E
110 110 3 1 D
111 111 2 1 C
112 112 1 0 B
113 113 0 0 A
114 114 $ hg merge 4 # E
115 115 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 116 (branch merge, don't forget to commit)
117 117 $ hg phase
118 118 6: draft
119 119 4: secret
120 120 $ hg ci -m "merge B' and E"
121 121 test-debug-phase: new rev 7: x -> 2
122 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: -> 2
122 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: -> secret
123 123
124 124 $ hglog
125 125 7 2 merge B' and E
126 126 6 1 B'
127 127 5 2 H
128 128 4 2 E
129 129 3 1 D
130 130 2 1 C
131 131 1 0 B
132 132 0 0 A
133 133
134 134 Test secret changeset are not pushed
135 135
136 136 $ hg init ../push-dest
137 137 $ cat > ../push-dest/.hg/hgrc << EOF
138 138 > [phases]
139 139 > publish=False
140 140 > EOF
141 141 $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
142 142 comparing with ../push-dest
143 143 searching for changes
144 144 0 public A
145 145 1 public B
146 146 2 draft C
147 147 3 draft D
148 148 6 draft B'
149 149 $ hg outgoing -r 'branch(default)' ../push-dest --template='{rev} {phase} {desc|firstline}\n'
150 150 comparing with ../push-dest
151 151 searching for changes
152 152 0 public A
153 153 1 public B
154 154 2 draft C
155 155 3 draft D
156 156 6 draft B'
157 157
158 158 $ hg push ../push-dest -f # force because we push multiple heads
159 159 pushing to ../push-dest
160 160 searching for changes
161 161 adding changesets
162 162 adding manifests
163 163 adding file changes
164 164 added 5 changesets with 5 changes to 5 files (+1 heads)
165 165 test-debug-phase: new rev 0: x -> 0
166 166 test-debug-phase: new rev 1: x -> 0
167 167 test-debug-phase: new rev 2: x -> 1
168 168 test-debug-phase: new rev 3: x -> 1
169 169 test-debug-phase: new rev 4: x -> 1
170 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> 0
171 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> 0
172 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> 1
173 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> 1
174 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> 1
170 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> public
171 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> public
172 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> draft
173 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> draft
174 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> draft
175 175 $ hglog
176 176 7 2 merge B' and E
177 177 6 1 B'
178 178 5 2 H
179 179 4 2 E
180 180 3 1 D
181 181 2 1 C
182 182 1 0 B
183 183 0 0 A
184 184 $ cd ../push-dest
185 185 $ hglog
186 186 4 1 B'
187 187 3 1 D
188 188 2 1 C
189 189 1 0 B
190 190 0 0 A
191 191
192 192 (Issue3303)
193 193 Check that remote secret changeset are ignore when checking creation of remote heads
194 194
195 195 We add a secret head into the push destination. This secret head shadows a
196 196 visible shared between the initial repo and the push destination.
197 197
198 198 $ hg up -q 4 # B'
199 199 $ mkcommit Z --config phases.new-commit=secret
200 200 test-debug-phase: new rev 5: x -> 2
201 test-hook-close-phase: 2713879da13d6eea1ff22b442a5a87cb31a7ce6a: -> 2
201 test-hook-close-phase: 2713879da13d6eea1ff22b442a5a87cb31a7ce6a: -> secret
202 202 $ hg phase .
203 203 5: secret
204 204
205 205 We now try to push a new public changeset that descend from the common public
206 206 head shadowed by the remote secret head.
207 207
208 208 $ cd ../initialrepo
209 209 $ hg up -q 6 #B'
210 210 $ mkcommit I
211 211 test-debug-phase: new rev 8: x -> 1
212 212 created new head
213 test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061: -> 1
213 test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061: -> draft
214 214 $ hg push ../push-dest
215 215 pushing to ../push-dest
216 216 searching for changes
217 217 adding changesets
218 218 adding manifests
219 219 adding file changes
220 220 added 1 changesets with 1 changes to 1 files (+1 heads)
221 221 test-debug-phase: new rev 6: x -> 1
222 test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061: -> 1
222 test-hook-close-phase: 6d6770faffce199f1fddd1cf87f6f026138cf061: -> draft
223 223
224 224 :note: The "(+1 heads)" is wrong as we do not had any visible head
225 225
226 226 check that branch cache with "served" filter are properly computed and stored
227 227
228 228 $ ls ../push-dest/.hg/cache/branch2*
229 229 ../push-dest/.hg/cache/branch2-base
230 230 ../push-dest/.hg/cache/branch2-served
231 231 $ cat ../push-dest/.hg/cache/branch2-served
232 232 6d6770faffce199f1fddd1cf87f6f026138cf061 6 465891ffab3c47a3c23792f7dc84156e19a90722
233 233 b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e o default
234 234 6d6770faffce199f1fddd1cf87f6f026138cf061 o default
235 235 $ hg heads -R ../push-dest --template '{rev}:{node} {phase}\n' #update visible cache too
236 236 6:6d6770faffce199f1fddd1cf87f6f026138cf061 draft
237 237 5:2713879da13d6eea1ff22b442a5a87cb31a7ce6a secret
238 238 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e draft
239 239 $ ls ../push-dest/.hg/cache/branch2*
240 240 ../push-dest/.hg/cache/branch2-base
241 241 ../push-dest/.hg/cache/branch2-served
242 242 ../push-dest/.hg/cache/branch2-visible
243 243 $ cat ../push-dest/.hg/cache/branch2-served
244 244 6d6770faffce199f1fddd1cf87f6f026138cf061 6 465891ffab3c47a3c23792f7dc84156e19a90722
245 245 b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e o default
246 246 6d6770faffce199f1fddd1cf87f6f026138cf061 o default
247 247 $ cat ../push-dest/.hg/cache/branch2-visible
248 248 6d6770faffce199f1fddd1cf87f6f026138cf061 6
249 249 b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e o default
250 250 2713879da13d6eea1ff22b442a5a87cb31a7ce6a o default
251 251 6d6770faffce199f1fddd1cf87f6f026138cf061 o default
252 252
253 253
254 254 Restore condition prior extra insertion.
255 255 $ hg -q --config extensions.mq= strip .
256 256 $ hg up -q 7
257 257 $ cd ..
258 258
259 259 Test secret changeset are not pull
260 260
261 261 $ hg init pull-dest
262 262 $ cd pull-dest
263 263 $ hg pull ../initialrepo
264 264 pulling from ../initialrepo
265 265 requesting all changes
266 266 adding changesets
267 267 adding manifests
268 268 adding file changes
269 269 added 5 changesets with 5 changes to 5 files (+1 heads)
270 270 new changesets 4a2df7238c3b:cf9fe039dfd6
271 271 test-debug-phase: new rev 0: x -> 0
272 272 test-debug-phase: new rev 1: x -> 0
273 273 test-debug-phase: new rev 2: x -> 0
274 274 test-debug-phase: new rev 3: x -> 0
275 275 test-debug-phase: new rev 4: x -> 0
276 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> 0
277 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> 0
278 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> 0
279 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> 0
280 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> 0
276 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> public
277 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> public
278 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> public
279 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> public
280 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> public
281 281 (run 'hg heads' to see heads, 'hg merge' to merge)
282 282 $ hglog
283 283 4 0 B'
284 284 3 0 D
285 285 2 0 C
286 286 1 0 B
287 287 0 0 A
288 288 $ cd ..
289 289
290 290 But secret can still be bundled explicitly
291 291
292 292 $ cd initialrepo
293 293 $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
294 294 4 changesets found
295 295 $ cd ..
296 296
297 297 Test secret changeset are not cloned
298 298 (during local clone)
299 299
300 300 $ hg clone -qU initialrepo clone-dest
301 301 test-debug-phase: new rev 0: x -> 0
302 302 test-debug-phase: new rev 1: x -> 0
303 303 test-debug-phase: new rev 2: x -> 0
304 304 test-debug-phase: new rev 3: x -> 0
305 305 test-debug-phase: new rev 4: x -> 0
306 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> 0
307 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> 0
308 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> 0
309 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> 0
310 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> 0
306 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> public
307 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> public
308 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> public
309 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> public
310 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> public
311 311 $ hglog -R clone-dest
312 312 4 0 B'
313 313 3 0 D
314 314 2 0 C
315 315 1 0 B
316 316 0 0 A
317 317
318 318 Test summary
319 319
320 320 $ hg summary -R clone-dest --verbose
321 321 parent: -1:000000000000 (no revision checked out)
322 322 branch: default
323 323 commit: (clean)
324 324 update: 5 new changesets (update)
325 325 $ hg summary -R initialrepo
326 326 parent: 7:17a481b3bccb tip
327 327 merge B' and E
328 328 branch: default
329 329 commit: (clean) (secret)
330 330 update: 1 new changesets, 2 branch heads (merge)
331 331 phases: 3 draft, 3 secret
332 332 $ hg summary -R initialrepo --quiet
333 333 parent: 7:17a481b3bccb tip
334 334 update: 1 new changesets, 2 branch heads (merge)
335 335
336 336 Test revset
337 337
338 338 $ cd initialrepo
339 339 $ hglog -r 'public()'
340 340 0 0 A
341 341 1 0 B
342 342 $ hglog -r 'draft()'
343 343 2 1 C
344 344 3 1 D
345 345 6 1 B'
346 346 $ hglog -r 'secret()'
347 347 4 2 E
348 348 5 2 H
349 349 7 2 merge B' and E
350 350
351 351 test that phase are displayed in log at debug level
352 352
353 353 $ hg log --debug
354 354 changeset: 7:17a481b3bccb796c0521ae97903d81c52bfee4af
355 355 tag: tip
356 356 phase: secret
357 357 parent: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
358 358 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
359 359 manifest: 7:5e724ffacba267b2ab726c91fc8b650710deaaa8
360 360 user: test
361 361 date: Thu Jan 01 00:00:00 1970 +0000
362 362 files+: C D E
363 363 extra: branch=default
364 364 description:
365 365 merge B' and E
366 366
367 367
368 368 changeset: 6:cf9fe039dfd67e829edf6522a45de057b5c86519
369 369 phase: draft
370 370 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
371 371 parent: -1:0000000000000000000000000000000000000000
372 372 manifest: 6:ab8bfef2392903058bf4ebb9e7746e8d7026b27a
373 373 user: test
374 374 date: Thu Jan 01 00:00:00 1970 +0000
375 375 files+: B'
376 376 extra: branch=default
377 377 description:
378 378 B'
379 379
380 380
381 381 changeset: 5:a030c6be5127abc010fcbff1851536552e6951a8
382 382 phase: secret
383 383 parent: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
384 384 parent: -1:0000000000000000000000000000000000000000
385 385 manifest: 5:5c710aa854874fe3d5fa7192e77bdb314cc08b5a
386 386 user: test
387 387 date: Thu Jan 01 00:00:00 1970 +0000
388 388 files+: H
389 389 extra: branch=default
390 390 description:
391 391 H
392 392
393 393
394 394 changeset: 4:a603bfb5a83e312131cebcd05353c217d4d21dde
395 395 phase: secret
396 396 parent: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
397 397 parent: -1:0000000000000000000000000000000000000000
398 398 manifest: 4:7173fd1c27119750b959e3a0f47ed78abe75d6dc
399 399 user: test
400 400 date: Thu Jan 01 00:00:00 1970 +0000
401 401 files+: E
402 402 extra: branch=default
403 403 description:
404 404 E
405 405
406 406
407 407 changeset: 3:b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
408 408 phase: draft
409 409 parent: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
410 410 parent: -1:0000000000000000000000000000000000000000
411 411 manifest: 3:6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c
412 412 user: test
413 413 date: Thu Jan 01 00:00:00 1970 +0000
414 414 files+: D
415 415 extra: branch=default
416 416 description:
417 417 D
418 418
419 419
420 420 changeset: 2:f838bfaca5c7226600ebcfd84f3c3c13a28d3757
421 421 phase: draft
422 422 parent: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
423 423 parent: -1:0000000000000000000000000000000000000000
424 424 manifest: 2:66a5a01817fdf5239c273802b5b7618d051c89e4
425 425 user: test
426 426 date: Thu Jan 01 00:00:00 1970 +0000
427 427 files+: C
428 428 extra: branch=default
429 429 description:
430 430 C
431 431
432 432
433 433 changeset: 1:27547f69f25460a52fff66ad004e58da7ad3fb56
434 434 phase: public
435 435 parent: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
436 436 parent: -1:0000000000000000000000000000000000000000
437 437 manifest: 1:cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd
438 438 user: test
439 439 date: Thu Jan 01 00:00:00 1970 +0000
440 440 files+: B
441 441 extra: branch=default
442 442 description:
443 443 B
444 444
445 445
446 446 changeset: 0:4a2df7238c3b48766b5e22fafbb8a2f506ec8256
447 447 phase: public
448 448 parent: -1:0000000000000000000000000000000000000000
449 449 parent: -1:0000000000000000000000000000000000000000
450 450 manifest: 0:007d8c9d88841325f5c6b06371b35b4e8a2b1a83
451 451 user: test
452 452 date: Thu Jan 01 00:00:00 1970 +0000
453 453 files+: A
454 454 extra: branch=default
455 455 description:
456 456 A
457 457
458 458
459 459
460 460
461 461 (Issue3707)
462 462 test invalid phase name
463 463
464 464 $ mkcommit I --config phases.new-commit='babar'
465 465 transaction abort!
466 466 rollback completed
467 467 abort: phases.new-commit: not a valid phase name ('babar')
468 468 [255]
469 469 Test phase command
470 470 ===================
471 471
472 472 initial picture
473 473
474 474 $ hg log -G --template "{rev} {phase} {desc}\n"
475 475 @ 7 secret merge B' and E
476 476 |\
477 477 | o 6 draft B'
478 478 | |
479 479 +---o 5 secret H
480 480 | |
481 481 o | 4 secret E
482 482 | |
483 483 o | 3 draft D
484 484 | |
485 485 o | 2 draft C
486 486 |/
487 487 o 1 public B
488 488 |
489 489 o 0 public A
490 490
491 491
492 492 display changesets phase
493 493
494 494 (mixing -r and plain rev specification)
495 495
496 496 $ hg phase 1::4 -r 7
497 497 1: public
498 498 2: draft
499 499 3: draft
500 500 4: secret
501 501 7: secret
502 502
503 503
504 504 move changeset forward
505 505
506 506 (with -r option)
507 507
508 508 $ hg phase --public -r 2
509 509 test-debug-phase: move rev 2: 1 -> 0
510 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: 1 -> 0
510 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: draft -> public
511 511 $ hg log -G --template "{rev} {phase} {desc}\n"
512 512 @ 7 secret merge B' and E
513 513 |\
514 514 | o 6 draft B'
515 515 | |
516 516 +---o 5 secret H
517 517 | |
518 518 o | 4 secret E
519 519 | |
520 520 o | 3 draft D
521 521 | |
522 522 o | 2 public C
523 523 |/
524 524 o 1 public B
525 525 |
526 526 o 0 public A
527 527
528 528
529 529 move changeset backward
530 530
531 531 (without -r option)
532 532
533 533 $ hg phase --draft --force 2
534 534 test-debug-phase: move rev 2: 0 -> 1
535 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: 0 -> 1
535 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: public -> draft
536 536 $ hg log -G --template "{rev} {phase} {desc}\n"
537 537 @ 7 secret merge B' and E
538 538 |\
539 539 | o 6 draft B'
540 540 | |
541 541 +---o 5 secret H
542 542 | |
543 543 o | 4 secret E
544 544 | |
545 545 o | 3 draft D
546 546 | |
547 547 o | 2 draft C
548 548 |/
549 549 o 1 public B
550 550 |
551 551 o 0 public A
552 552
553 553
554 554 move changeset forward and backward
555 555
556 556 $ hg phase --draft --force 1::4
557 557 test-debug-phase: move rev 1: 0 -> 1
558 558 test-debug-phase: move rev 4: 2 -> 1
559 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: 0 -> 1
560 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 2 -> 1
559 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: public -> draft
560 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: secret -> draft
561 561 $ hg log -G --template "{rev} {phase} {desc}\n"
562 562 @ 7 secret merge B' and E
563 563 |\
564 564 | o 6 draft B'
565 565 | |
566 566 +---o 5 secret H
567 567 | |
568 568 o | 4 draft E
569 569 | |
570 570 o | 3 draft D
571 571 | |
572 572 o | 2 draft C
573 573 |/
574 574 o 1 draft B
575 575 |
576 576 o 0 public A
577 577
578 578 test partial failure
579 579
580 580 $ hg phase --public 7
581 581 test-debug-phase: move rev 1: 1 -> 0
582 582 test-debug-phase: move rev 2: 1 -> 0
583 583 test-debug-phase: move rev 3: 1 -> 0
584 584 test-debug-phase: move rev 4: 1 -> 0
585 585 test-debug-phase: move rev 6: 1 -> 0
586 586 test-debug-phase: move rev 7: 2 -> 0
587 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: 1 -> 0
588 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: 1 -> 0
589 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: 1 -> 0
590 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 1 -> 0
591 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: 1 -> 0
592 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: 2 -> 0
587 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: draft -> public
588 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: draft -> public
589 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: draft -> public
590 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: draft -> public
591 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: draft -> public
592 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: secret -> public
593 593 $ hg phase --draft '5 or 7'
594 594 test-debug-phase: move rev 5: 2 -> 1
595 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: 2 -> 1
595 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: secret -> draft
596 596 cannot move 1 changesets to a higher phase, use --force
597 597 phase changed for 1 changesets
598 598 [1]
599 599 $ hg log -G --template "{rev} {phase} {desc}\n"
600 600 @ 7 public merge B' and E
601 601 |\
602 602 | o 6 public B'
603 603 | |
604 604 +---o 5 draft H
605 605 | |
606 606 o | 4 public E
607 607 | |
608 608 o | 3 public D
609 609 | |
610 610 o | 2 public C
611 611 |/
612 612 o 1 public B
613 613 |
614 614 o 0 public A
615 615
616 616
617 617 test complete failure
618 618
619 619 $ hg phase --draft 7
620 620 cannot move 1 changesets to a higher phase, use --force
621 621 no phases changed
622 622 [1]
623 623
624 624 $ cd ..
625 625
626 626 test hidden changeset are not cloned as public (issue3935)
627 627
628 628 $ cd initialrepo
629 629
630 630 (enabling evolution)
631 631 $ cat >> $HGRCPATH << EOF
632 632 > [experimental]
633 633 > evolution.createmarkers=True
634 634 > EOF
635 635
636 636 (making a changeset hidden; H in that case)
637 637 $ hg debugobsolete `hg id --debug -r 5`
638 638 obsoleted 1 changesets
639 639
640 640 $ cd ..
641 641 $ hg clone initialrepo clonewithobs
642 642 requesting all changes
643 643 adding changesets
644 644 adding manifests
645 645 adding file changes
646 646 added 7 changesets with 6 changes to 6 files
647 647 new changesets 4a2df7238c3b:17a481b3bccb
648 648 test-debug-phase: new rev 0: x -> 0
649 649 test-debug-phase: new rev 1: x -> 0
650 650 test-debug-phase: new rev 2: x -> 0
651 651 test-debug-phase: new rev 3: x -> 0
652 652 test-debug-phase: new rev 4: x -> 0
653 653 test-debug-phase: new rev 5: x -> 0
654 654 test-debug-phase: new rev 6: x -> 0
655 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> 0
656 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> 0
657 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> 0
658 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> 0
659 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: -> 0
660 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> 0
661 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: -> 0
655 test-hook-close-phase: 4a2df7238c3b48766b5e22fafbb8a2f506ec8256: -> public
656 test-hook-close-phase: 27547f69f25460a52fff66ad004e58da7ad3fb56: -> public
657 test-hook-close-phase: f838bfaca5c7226600ebcfd84f3c3c13a28d3757: -> public
658 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: -> public
659 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: -> public
660 test-hook-close-phase: cf9fe039dfd67e829edf6522a45de057b5c86519: -> public
661 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: -> public
662 662 updating to branch default
663 663 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
664 664 $ cd clonewithobs
665 665 $ hg log -G --template "{rev} {phase} {desc}\n"
666 666 @ 6 public merge B' and E
667 667 |\
668 668 | o 5 public B'
669 669 | |
670 670 o | 4 public E
671 671 | |
672 672 o | 3 public D
673 673 | |
674 674 o | 2 public C
675 675 |/
676 676 o 1 public B
677 677 |
678 678 o 0 public A
679 679
680 680
681 681 test verify repo containing hidden changesets, which should not abort just
682 682 because repo.cancopy() is False
683 683
684 684 $ cd ../initialrepo
685 685 $ hg verify
686 686 checking changesets
687 687 checking manifests
688 688 crosschecking files in changesets and manifests
689 689 checking files
690 690 7 files, 8 changesets, 7 total revisions
691 691
692 692 $ cd ..
693 693
694 694 check whether HG_PENDING makes pending changes only in related
695 695 repositories visible to an external hook.
696 696
697 697 (emulate a transaction running concurrently by copied
698 698 .hg/phaseroots.pending in subsequent test)
699 699
700 700 $ cat > $TESTTMP/savepending.sh <<EOF
701 701 > cp .hg/store/phaseroots.pending .hg/store/phaseroots.pending.saved
702 702 > exit 1 # to avoid changing phase for subsequent tests
703 703 > EOF
704 704 $ cd push-dest
705 705 $ hg phase 6
706 706 6: draft
707 707 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" phase -f -s 6
708 708 transaction abort!
709 709 rollback completed
710 710 abort: pretxnclose hook exited with status 1
711 711 [255]
712 712 $ cp .hg/store/phaseroots.pending.saved .hg/store/phaseroots.pending
713 713
714 714 (check (in)visibility of phaseroot while transaction running in repo)
715 715
716 716 $ cat > $TESTTMP/checkpending.sh <<EOF
717 717 > echo '@initialrepo'
718 718 > hg -R "$TESTTMP/initialrepo" phase 7
719 719 > echo '@push-dest'
720 720 > hg -R "$TESTTMP/push-dest" phase 6
721 721 > exit 1 # to avoid changing phase for subsequent tests
722 722 > EOF
723 723 $ cd ../initialrepo
724 724 $ hg phase 7
725 725 7: public
726 726 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" phase -f -s 7
727 727 @initialrepo
728 728 7: secret
729 729 @push-dest
730 730 6: draft
731 731 transaction abort!
732 732 rollback completed
733 733 abort: pretxnclose hook exited with status 1
734 734 [255]
735 735
736 736 Check that pretxnclose-phase hook can control phase movement
737 737
738 738 $ hg phase --force b3325c91a4d9 --secret
739 739 test-debug-phase: move rev 3: 0 -> 2
740 740 test-debug-phase: move rev 4: 0 -> 2
741 741 test-debug-phase: move rev 5: 1 -> 2
742 742 test-debug-phase: move rev 7: 0 -> 2
743 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: 0 -> 2
744 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 0 -> 2
745 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: 1 -> 2
746 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: 0 -> 2
743 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: public -> secret
744 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: public -> secret
745 test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: draft -> secret
746 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: public -> secret
747 747 $ hg log -G -T phases
748 748 @ changeset: 7:17a481b3bccb
749 749 |\ tag: tip
750 750 | | phase: secret
751 751 | | parent: 6:cf9fe039dfd6
752 752 | | parent: 4:a603bfb5a83e
753 753 | | user: test
754 754 | | date: Thu Jan 01 00:00:00 1970 +0000
755 755 | | summary: merge B' and E
756 756 | |
757 757 | o changeset: 6:cf9fe039dfd6
758 758 | | phase: public
759 759 | | parent: 1:27547f69f254
760 760 | | user: test
761 761 | | date: Thu Jan 01 00:00:00 1970 +0000
762 762 | | summary: B'
763 763 | |
764 764 o | changeset: 4:a603bfb5a83e
765 765 | | phase: secret
766 766 | | user: test
767 767 | | date: Thu Jan 01 00:00:00 1970 +0000
768 768 | | summary: E
769 769 | |
770 770 o | changeset: 3:b3325c91a4d9
771 771 | | phase: secret
772 772 | | user: test
773 773 | | date: Thu Jan 01 00:00:00 1970 +0000
774 774 | | summary: D
775 775 | |
776 776 o | changeset: 2:f838bfaca5c7
777 777 |/ phase: public
778 778 | user: test
779 779 | date: Thu Jan 01 00:00:00 1970 +0000
780 780 | summary: C
781 781 |
782 782 o changeset: 1:27547f69f254
783 783 | phase: public
784 784 | user: test
785 785 | date: Thu Jan 01 00:00:00 1970 +0000
786 786 | summary: B
787 787 |
788 788 o changeset: 0:4a2df7238c3b
789 789 phase: public
790 790 user: test
791 791 date: Thu Jan 01 00:00:00 1970 +0000
792 792 summary: A
793 793
794 794
795 795 Install a hook that prevent b3325c91a4d9 to become public
796 796
797 797 $ cat >> .hg/hgrc << EOF
798 798 > [hooks]
799 > pretxnclose-phase.nopublish_D = (echo \$HG_NODE| grep -v b3325c91a4d9>/dev/null) || [ 0 -lt \$HG_PHASE ]
799 > pretxnclose-phase.nopublish_D = (echo \$HG_NODE| grep -v b3325c91a4d9>/dev/null) || [ 'public' != \$HG_PHASE ]
800 800 > EOF
801 801
802 802 Try various actions. only the draft move should succeed
803 803
804 804 $ hg phase --public b3325c91a4d9
805 805 transaction abort!
806 806 rollback completed
807 807 abort: pretxnclose-phase.nopublish_D hook exited with status 1
808 808 [255]
809 809 $ hg phase --public a603bfb5a83e
810 810 transaction abort!
811 811 rollback completed
812 812 abort: pretxnclose-phase.nopublish_D hook exited with status 1
813 813 [255]
814 814 $ hg phase --draft 17a481b3bccb
815 815 test-debug-phase: move rev 3: 2 -> 1
816 816 test-debug-phase: move rev 4: 2 -> 1
817 817 test-debug-phase: move rev 7: 2 -> 1
818 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: 2 -> 1
819 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 2 -> 1
820 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: 2 -> 1
818 test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: secret -> draft
819 test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: secret -> draft
820 test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: secret -> draft
821 821 $ hg phase --public 17a481b3bccb
822 822 transaction abort!
823 823 rollback completed
824 824 abort: pretxnclose-phase.nopublish_D hook exited with status 1
825 825 [255]
@@ -1,198 +1,198 b''
1 1 #require killdaemons
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo a > a
6 6 $ hg ci -Ama
7 7 adding a
8 8 $ cd ..
9 9 $ hg clone test test2
10 10 updating to branch default
11 11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 12 $ cd test2
13 13 $ echo a >> a
14 14 $ hg ci -mb
15 15 $ req() {
16 16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
17 17 > cat hg.pid >> $DAEMON_PIDS
18 18 > hg --cwd ../test2 push http://localhost:$HGPORT/
19 19 > exitstatus=$?
20 20 > killdaemons.py
21 21 > echo % serve errors
22 22 > cat errors.log
23 23 > return $exitstatus
24 24 > }
25 25 $ cd ../test
26 26
27 27 expect ssl error
28 28
29 29 $ req
30 30 pushing to http://localhost:$HGPORT/
31 31 searching for changes
32 32 abort: HTTP Error 403: ssl required
33 33 % serve errors
34 34 [255]
35 35
36 36 expect authorization error
37 37
38 38 $ echo '[web]' > .hg/hgrc
39 39 $ echo 'push_ssl = false' >> .hg/hgrc
40 40 $ req
41 41 pushing to http://localhost:$HGPORT/
42 42 searching for changes
43 43 abort: authorization failed
44 44 % serve errors
45 45 [255]
46 46
47 47 expect authorization error: must have authorized user
48 48
49 49 $ echo 'allow_push = unperson' >> .hg/hgrc
50 50 $ req
51 51 pushing to http://localhost:$HGPORT/
52 52 searching for changes
53 53 abort: authorization failed
54 54 % serve errors
55 55 [255]
56 56
57 57 expect success
58 58
59 59 $ cat >> .hg/hgrc <<EOF
60 60 > allow_push = *
61 61 > [hooks]
62 62 > changegroup = sh -c "printenv.py changegroup 0"
63 63 > pushkey = sh -c "printenv.py pushkey 0"
64 64 > txnclose-phase.test = echo "phase-move: \$HG_NODE: \$HG_OLDPHASE -> \$HG_PHASE"
65 65 > EOF
66 66 $ req
67 67 pushing to http://localhost:$HGPORT/
68 68 searching for changes
69 69 remote: adding changesets
70 70 remote: adding manifests
71 71 remote: adding file changes
72 72 remote: added 1 changesets with 1 changes to 1 files
73 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
74 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
73 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
74 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
75 75 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
76 76 % serve errors
77 77 $ hg rollback
78 78 repository tip rolled back to revision 0 (undo serve)
79 79
80 80 expect success, server lacks the httpheader capability
81 81
82 82 $ CAP=httpheader
83 83 $ . "$TESTDIR/notcapable"
84 84 $ req
85 85 pushing to http://localhost:$HGPORT/
86 86 searching for changes
87 87 remote: adding changesets
88 88 remote: adding manifests
89 89 remote: adding file changes
90 90 remote: added 1 changesets with 1 changes to 1 files
91 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
92 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
91 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
92 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
93 93 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
94 94 % serve errors
95 95 $ hg rollback
96 96 repository tip rolled back to revision 0 (undo serve)
97 97
98 98 expect success, server lacks the unbundlehash capability
99 99
100 100 $ CAP=unbundlehash
101 101 $ . "$TESTDIR/notcapable"
102 102 $ req
103 103 pushing to http://localhost:$HGPORT/
104 104 searching for changes
105 105 remote: adding changesets
106 106 remote: adding manifests
107 107 remote: adding file changes
108 108 remote: added 1 changesets with 1 changes to 1 files
109 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
110 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
109 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
110 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
111 111 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
112 112 % serve errors
113 113 $ hg rollback
114 114 repository tip rolled back to revision 0 (undo serve)
115 115
116 116 expect push success, phase change failure
117 117
118 118 $ cat > .hg/hgrc <<EOF
119 119 > [web]
120 120 > push_ssl = false
121 121 > allow_push = *
122 122 > [hooks]
123 123 > prepushkey = sh -c "printenv.py prepushkey 1"
124 124 > [devel]
125 125 > legacy.exchange=phases
126 126 > EOF
127 127 $ req
128 128 pushing to http://localhost:$HGPORT/
129 129 searching for changes
130 130 remote: adding changesets
131 131 remote: adding manifests
132 132 remote: adding file changes
133 133 remote: added 1 changesets with 1 changes to 1 files
134 134 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
135 135 remote: pushkey-abort: prepushkey hook exited with status 1
136 136 remote: transaction abort!
137 137 remote: rollback completed
138 138 abort: updating ba677d0156c1 to public failed
139 139 % serve errors
140 140 [255]
141 141
142 142 expect phase change success
143 143
144 144 $ cat >> .hg/hgrc <<EOF
145 145 > prepushkey = sh -c "printenv.py prepushkey 0"
146 146 > [devel]
147 147 > legacy.exchange=
148 148 > EOF
149 149 $ req
150 150 pushing to http://localhost:$HGPORT/
151 151 searching for changes
152 152 remote: adding changesets
153 153 remote: adding manifests
154 154 remote: adding file changes
155 155 remote: added 1 changesets with 1 changes to 1 files
156 156 % serve errors
157 157 $ hg rollback
158 158 repository tip rolled back to revision 0 (undo serve)
159 159
160 160 expect authorization error: all users denied
161 161
162 162 $ echo '[web]' > .hg/hgrc
163 163 $ echo 'push_ssl = false' >> .hg/hgrc
164 164 $ echo 'deny_push = *' >> .hg/hgrc
165 165 $ req
166 166 pushing to http://localhost:$HGPORT/
167 167 searching for changes
168 168 abort: authorization failed
169 169 % serve errors
170 170 [255]
171 171
172 172 expect authorization error: some users denied, users must be authenticated
173 173
174 174 $ echo 'deny_push = unperson' >> .hg/hgrc
175 175 $ req
176 176 pushing to http://localhost:$HGPORT/
177 177 searching for changes
178 178 abort: authorization failed
179 179 % serve errors
180 180 [255]
181 181
182 182 $ cat > .hg/hgrc <<EOF
183 183 > [web]
184 184 > push_ssl = false
185 185 > allow_push = *
186 186 > [experimental]
187 187 > httppostargs=true
188 188 > EOF
189 189 $ req
190 190 pushing to http://localhost:$HGPORT/
191 191 searching for changes
192 192 remote: adding changesets
193 193 remote: adding manifests
194 194 remote: adding file changes
195 195 remote: added 1 changesets with 1 changes to 1 files
196 196 % serve errors
197 197
198 198 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now