##// END OF EJS Templates
bundle: add config option to include phases...
Martin von Zweigbergk -
r33031:e8c8d81e default
parent child Browse files
Show More
@@ -0,0 +1,259 b''
1 $ cat >> $HGRCPATH <<EOF
2 > [experimental]
3 > bundle-phases=yes
4 > [extensions]
5 > strip=
6 > drawdag=$TESTDIR/drawdag.py
7 > EOF
8
9 Set up repo with linear history
10 $ hg init linear
11 $ cd linear
12 $ hg debugdrawdag <<'EOF'
13 > E
14 > |
15 > D
16 > |
17 > C
18 > |
19 > B
20 > |
21 > A
22 > EOF
23 $ hg phase --public A
24 $ hg phase --force --secret D
25 $ hg log -G -T '{desc} {phase}\n'
26 o E secret
27 |
28 o D secret
29 |
30 o C draft
31 |
32 o B draft
33 |
34 o A public
35
36 Phases are restored when unbundling
37 $ hg bundle --base B -r E bundle
38 3 changesets found
39 $ hg debugbundle bundle
40 Stream params: sortdict([('Compression', 'BZ')])
41 changegroup -- "sortdict([('version', '02'), ('nbchanges', '3')])"
42 26805aba1e600a82e93661149f2313866a221a7b
43 f585351a92f85104bff7c284233c338b10eb1df7
44 9bc730a19041f9ec7cb33c626e811aa233efb18c
45 phase-heads -- 'sortdict()'
46 26805aba1e600a82e93661149f2313866a221a7b draft
47 $ hg strip --no-backup C
48 $ hg unbundle -q bundle
49 $ rm bundle
50 $ hg log -G -T '{desc} {phase}\n'
51 o E secret
52 |
53 o D secret
54 |
55 o C draft
56 |
57 o B draft
58 |
59 o A public
60
61 Root revision's phase is preserved
62 $ hg bundle -a bundle
63 5 changesets found
64 $ hg strip --no-backup A
65 $ hg unbundle -q bundle
66 $ rm bundle
67 $ hg log -G -T '{desc} {phase}\n'
68 o E secret
69 |
70 o D secret
71 |
72 o C draft
73 |
74 o B draft
75 |
76 o A public
77
78 Completely public history can be restored
79 $ hg phase --public E
80 $ hg bundle -a bundle
81 5 changesets found
82 $ hg strip --no-backup A
83 $ hg unbundle -q bundle
84 $ rm bundle
85 $ hg log -G -T '{desc} {phase}\n'
86 o E public
87 |
88 o D public
89 |
90 o C public
91 |
92 o B public
93 |
94 o A public
95
96 Direct transition from public to secret can be restored
97 $ hg phase --secret --force D
98 $ hg bundle -a bundle
99 5 changesets found
100 $ hg strip --no-backup A
101 $ hg unbundle -q bundle
102 $ rm bundle
103 $ hg log -G -T '{desc} {phase}\n'
104 o E secret
105 |
106 o D secret
107 |
108 o C public
109 |
110 o B public
111 |
112 o A public
113
114 Revisions within bundle preserve their phase even if parent changes its phase
115 $ hg phase --draft --force B
116 $ hg bundle --base B -r E bundle
117 3 changesets found
118 $ hg strip --no-backup C
119 $ hg phase --public B
120 $ hg unbundle -q bundle
121 $ rm bundle
122 $ hg log -G -T '{desc} {phase}\n'
123 o E secret
124 |
125 o D secret
126 |
127 o C draft
128 |
129 o B public
130 |
131 o A public
132
133 Phase of ancestors of stripped node get advanced to accommodate child
134 $ hg bundle --base B -r E bundle
135 3 changesets found
136 $ hg strip --no-backup C
137 $ hg phase --force --secret B
138 $ hg unbundle -q bundle
139 $ rm bundle
140 $ hg log -G -T '{desc} {phase}\n'
141 o E secret
142 |
143 o D secret
144 |
145 o C draft
146 |
147 o B draft
148 |
149 o A public
150
151 Unbundling advances phases of changesets even if they were already in the repo.
152 To test that, create a bundle of everything in draft phase and then unbundle
153 to see that secret becomes draft, but public remains public.
154 $ hg phase --draft --force A
155 $ hg phase --draft E
156 $ hg bundle -a bundle
157 5 changesets found
158 $ hg phase --public A
159 $ hg phase --secret --force E
160 $ hg unbundle -q bundle
161 $ rm bundle
162 $ hg log -G -T '{desc} {phase}\n'
163 o E draft
164 |
165 o D draft
166 |
167 o C draft
168 |
169 o B draft
170 |
171 o A public
172
173 $ cd ..
174
175 Set up repo with non-linear history
176 $ hg init non-linear
177 $ cd non-linear
178 $ hg debugdrawdag <<'EOF'
179 > D E
180 > |\|
181 > B C
182 > |/
183 > A
184 > EOF
185 $ hg phase --public C
186 $ hg phase --force --secret B
187 $ hg log -G -T '{node|short} {desc} {phase}\n'
188 o 03ca77807e91 E draft
189 |
190 | o 215e7b0814e1 D secret
191 |/|
192 o | dc0947a82db8 C public
193 | |
194 | o 112478962961 B secret
195 |/
196 o 426bada5c675 A public
197
198
199 Restore bundle of entire repo
200 $ hg bundle -a bundle
201 5 changesets found
202 $ hg debugbundle bundle
203 Stream params: sortdict([('Compression', 'BZ')])
204 changegroup -- "sortdict([('version', '02'), ('nbchanges', '5')])"
205 426bada5c67598ca65036d57d9e4b64b0c1ce7a0
206 112478962961147124edd43549aedd1a335e44bf
207 dc0947a82db884575bb76ea10ac97b08536bfa03
208 215e7b0814e1cac8e2614e7284f2a5dc266b4323
209 03ca77807e919db8807c3749086dc36fb478cac0
210 phase-heads -- 'sortdict()'
211 dc0947a82db884575bb76ea10ac97b08536bfa03 public
212 03ca77807e919db8807c3749086dc36fb478cac0 draft
213 $ hg strip --no-backup A
214 $ hg unbundle -q bundle
215 $ rm bundle
216 $ hg log -G -T '{node|short} {desc} {phase}\n'
217 o 03ca77807e91 E draft
218 |
219 | o 215e7b0814e1 D secret
220 |/|
221 o | dc0947a82db8 C public
222 | |
223 | o 112478962961 B secret
224 |/
225 o 426bada5c675 A public
226
227
228 $ hg bundle --base 'A + C' -r D bundle
229 2 changesets found
230 $ hg debugbundle bundle
231 Stream params: sortdict([('Compression', 'BZ')])
232 changegroup -- "sortdict([('version', '02'), ('nbchanges', '2')])"
233 112478962961147124edd43549aedd1a335e44bf
234 215e7b0814e1cac8e2614e7284f2a5dc266b4323
235 phase-heads -- 'sortdict()'
236 $ rm bundle
237
238 $ hg bundle --base A -r D bundle
239 3 changesets found
240 $ hg debugbundle bundle
241 Stream params: sortdict([('Compression', 'BZ')])
242 changegroup -- "sortdict([('version', '02'), ('nbchanges', '3')])"
243 112478962961147124edd43549aedd1a335e44bf
244 dc0947a82db884575bb76ea10ac97b08536bfa03
245 215e7b0814e1cac8e2614e7284f2a5dc266b4323
246 phase-heads -- 'sortdict()'
247 dc0947a82db884575bb76ea10ac97b08536bfa03 public
248 $ rm bundle
249
250 $ hg bundle --base 'B + C' -r 'D + E' bundle
251 2 changesets found
252 $ hg debugbundle bundle
253 Stream params: sortdict([('Compression', 'BZ')])
254 changegroup -- "sortdict([('version', '02'), ('nbchanges', '2')])"
255 215e7b0814e1cac8e2614e7284f2a5dc266b4323
256 03ca77807e919db8807c3749086dc36fb478cac0
257 phase-heads -- 'sortdict()'
258 03ca77807e919db8807c3749086dc36fb478cac0 draft
259 $ rm bundle
@@ -158,6 +158,7 b' from . import ('
158 changegroup,
158 changegroup,
159 error,
159 error,
160 obsolete,
160 obsolete,
161 phases,
161 pushkey,
162 pushkey,
162 pycompat,
163 pycompat,
163 tags,
164 tags,
@@ -178,6 +179,8 b' urlreq = util.urlreq'
178 _fpayloadsize = '>i'
179 _fpayloadsize = '>i'
179 _fpartparamcount = '>BB'
180 _fpartparamcount = '>BB'
180
181
182 _fphasesentry = '>i20s'
183
181 preferedchunksize = 4096
184 preferedchunksize = 4096
182
185
183 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
186 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
@@ -1387,6 +1390,14 b' def _addpartsfromopts(ui, repo, bundler,'
1387 obsmarkers = repo.obsstore.relevantmarkers(outgoing.missing)
1390 obsmarkers = repo.obsstore.relevantmarkers(outgoing.missing)
1388 buildobsmarkerspart(bundler, obsmarkers)
1391 buildobsmarkerspart(bundler, obsmarkers)
1389
1392
1393 if opts.get('phases', False):
1394 headsbyphase = phases.subsetphaseheads(repo, outgoing.missing)
1395 phasedata = []
1396 for phase in phases.allphases:
1397 for head in headsbyphase[phase]:
1398 phasedata.append(_pack(_fphasesentry, phase, head))
1399 bundler.newpart('phase-heads', data=''.join(phasedata))
1400
1390 def addparttagsfnodescache(repo, bundler, outgoing):
1401 def addparttagsfnodescache(repo, bundler, outgoing):
1391 # we include the tags fnode cache for the bundle changeset
1402 # we include the tags fnode cache for the bundle changeset
1392 # (as an optional parts)
1403 # (as an optional parts)
@@ -1721,6 +1732,29 b' def handlepushkey(op, inpart):'
1721 kwargs[key] = inpart.params[key]
1732 kwargs[key] = inpart.params[key]
1722 raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
1733 raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
1723
1734
1735 def _readphaseheads(inpart):
1736 headsbyphase = [[] for i in phases.allphases]
1737 entrysize = struct.calcsize(_fphasesentry)
1738 while True:
1739 entry = inpart.read(entrysize)
1740 if len(entry) < entrysize:
1741 if entry:
1742 raise error.Abort(_('bad phase-heads bundle part'))
1743 break
1744 phase, node = struct.unpack(_fphasesentry, entry)
1745 headsbyphase[phase].append(node)
1746 return headsbyphase
1747
1748 @parthandler('phase-heads')
1749 def handlephases(op, inpart):
1750 """apply phases from bundle part to repo"""
1751 headsbyphase = _readphaseheads(inpart)
1752 addednodes = []
1753 for entry in op.records['changegroup']:
1754 addednodes.extend(entry['addednodes'])
1755 phases.updatephases(op.repo.unfiltered(), op.gettransaction(), headsbyphase,
1756 addednodes)
1757
1724 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1758 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1725 def handlepushkeyreply(op, inpart):
1759 def handlepushkeyreply(op, inpart):
1726 """retrieve the result of a pushkey request"""
1760 """retrieve the result of a pushkey request"""
@@ -1230,6 +1230,8 b' def bundle(ui, repo, fname, dest=None, *'
1230 contentopts = {'cg.version': cgversion}
1230 contentopts = {'cg.version': cgversion}
1231 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1231 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False):
1232 contentopts['obsolescence'] = True
1232 contentopts['obsolescence'] = True
1233 if repo.ui.configbool('experimental', 'bundle-phases', False):
1234 contentopts['phases'] = True
1233 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1235 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1234 contentopts, compression=bcompression,
1236 contentopts, compression=bcompression,
1235 compopts=compopts)
1237 compopts=compopts)
@@ -311,6 +311,15 b' def _debugobsmarkers(ui, part, indent=0,'
311 cmdutil.showmarker(fm, m)
311 cmdutil.showmarker(fm, m)
312 fm.end()
312 fm.end()
313
313
314 def _debugphaseheads(ui, data, indent=0):
315 """display version and markers contained in 'data'"""
316 indent_string = ' ' * indent
317 headsbyphase = bundle2._readphaseheads(data)
318 for phase in phases.allphases:
319 for head in headsbyphase[phase]:
320 ui.write(indent_string)
321 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
322
314 def _debugbundle2(ui, gen, all=None, **opts):
323 def _debugbundle2(ui, gen, all=None, **opts):
315 """lists the contents of a bundle2"""
324 """lists the contents of a bundle2"""
316 if not isinstance(gen, bundle2.unbundle20):
325 if not isinstance(gen, bundle2.unbundle20):
@@ -327,6 +336,8 b' def _debugbundle2(ui, gen, all=None, **o'
327 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
336 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
328 if part.type == 'obsmarkers':
337 if part.type == 'obsmarkers':
329 _debugobsmarkers(ui, part, indent=4, **opts)
338 _debugobsmarkers(ui, part, indent=4, **opts)
339 if part.type == 'phase-heads':
340 _debugphaseheads(ui, part, indent=4)
330
341
331 @command('debugbundle',
342 @command('debugbundle',
332 [('a', 'all', None, _('show all details')),
343 [('a', 'all', None, _('show all details')),
@@ -430,6 +430,32 b' def pushphase(repo, nhex, oldphasestr, n'
430 else:
430 else:
431 return False
431 return False
432
432
433 def subsetphaseheads(repo, subset):
434 """Finds the phase heads for a subset of a history
435
436 Returns a list indexed by phase number where each item is a list of phase
437 head nodes.
438 """
439 cl = repo.changelog
440
441 headsbyphase = [[] for i in allphases]
442 # No need to keep track of secret phase; any heads in the subset that
443 # are not mentioned are implicitly secret.
444 for phase in allphases[:-1]:
445 revset = "heads(%%ln & %s())" % phasenames[phase]
446 headsbyphase[phase] = [cl.node(r) for r in repo.revs(revset, subset)]
447 return headsbyphase
448
449 def updatephases(repo, tr, headsbyphase, addednodes):
450 """Updates the repo with the given phase heads"""
451 # First make all the added revisions secret because changegroup.apply()
452 # currently sets the phase to draft.
453 retractboundary(repo, tr, secret, addednodes)
454
455 # Now advance phase boundaries of all but secret phase
456 for phase in allphases[:-1]:
457 advanceboundary(repo, tr, phase, headsbyphase[phase])
458
433 def analyzeremotephases(repo, subset, roots):
459 def analyzeremotephases(repo, subset, roots):
434 """Compute phases heads and root in a subset of node from root dict
460 """Compute phases heads and root in a subset of node from root dict
435
461
General Comments 0
You need to be logged in to leave comments. Login now