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 | 158 | changegroup, |
|
159 | 159 | error, |
|
160 | 160 | obsolete, |
|
161 | phases, | |
|
161 | 162 | pushkey, |
|
162 | 163 | pycompat, |
|
163 | 164 | tags, |
@@ -178,6 +179,8 b' urlreq = util.urlreq' | |||
|
178 | 179 | _fpayloadsize = '>i' |
|
179 | 180 | _fpartparamcount = '>BB' |
|
180 | 181 | |
|
182 | _fphasesentry = '>i20s' | |
|
183 | ||
|
181 | 184 | preferedchunksize = 4096 |
|
182 | 185 | |
|
183 | 186 | _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]') |
@@ -1387,6 +1390,14 b' def _addpartsfromopts(ui, repo, bundler,' | |||
|
1387 | 1390 | obsmarkers = repo.obsstore.relevantmarkers(outgoing.missing) |
|
1388 | 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 | 1401 | def addparttagsfnodescache(repo, bundler, outgoing): |
|
1391 | 1402 | # we include the tags fnode cache for the bundle changeset |
|
1392 | 1403 | # (as an optional parts) |
@@ -1721,6 +1732,29 b' def handlepushkey(op, inpart):' | |||
|
1721 | 1732 | kwargs[key] = inpart.params[key] |
|
1722 | 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 | 1758 | @parthandler('reply:pushkey', ('return', 'in-reply-to')) |
|
1725 | 1759 | def handlepushkeyreply(op, inpart): |
|
1726 | 1760 | """retrieve the result of a pushkey request""" |
@@ -1230,6 +1230,8 b' def bundle(ui, repo, fname, dest=None, *' | |||
|
1230 | 1230 | contentopts = {'cg.version': cgversion} |
|
1231 | 1231 | if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker', False): |
|
1232 | 1232 | contentopts['obsolescence'] = True |
|
1233 | if repo.ui.configbool('experimental', 'bundle-phases', False): | |
|
1234 | contentopts['phases'] = True | |
|
1233 | 1235 | bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing, |
|
1234 | 1236 | contentopts, compression=bcompression, |
|
1235 | 1237 | compopts=compopts) |
@@ -311,6 +311,15 b' def _debugobsmarkers(ui, part, indent=0,' | |||
|
311 | 311 | cmdutil.showmarker(fm, m) |
|
312 | 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 | 323 | def _debugbundle2(ui, gen, all=None, **opts): |
|
315 | 324 | """lists the contents of a bundle2""" |
|
316 | 325 | if not isinstance(gen, bundle2.unbundle20): |
@@ -327,6 +336,8 b' def _debugbundle2(ui, gen, all=None, **o' | |||
|
327 | 336 | _debugchangegroup(ui, cg, all=all, indent=4, **opts) |
|
328 | 337 | if part.type == 'obsmarkers': |
|
329 | 338 | _debugobsmarkers(ui, part, indent=4, **opts) |
|
339 | if part.type == 'phase-heads': | |
|
340 | _debugphaseheads(ui, part, indent=4) | |
|
330 | 341 | |
|
331 | 342 | @command('debugbundle', |
|
332 | 343 | [('a', 'all', None, _('show all details')), |
@@ -430,6 +430,32 b' def pushphase(repo, nhex, oldphasestr, n' | |||
|
430 | 430 | else: |
|
431 | 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 | 459 | def analyzeremotephases(repo, subset, roots): |
|
434 | 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