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