##// END OF EJS Templates
rebase: change internal format to support destination map...
Jun Wu -
r34006:af609bb3 default
parent child Browse files
Show More
@@ -0,0 +1,76 b''
1 Test rebase --continue with rebasestate written by legacy client
2
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
5 > rebase=
6 > drawdag=$TESTDIR/drawdag.py
7 > EOF
8
9 $ hg init
10 $ hg debugdrawdag <<'EOF'
11 > D H
12 > | |
13 > C G
14 > | |
15 > B F
16 > | |
17 > Z A E
18 > \|/
19 > R
20 > EOF
21
22 rebasestate generated by a legacy client running "hg rebase -r B+D+E+G+H -d Z"
23
24 $ touch .hg/last-message.txt
25 $ cat > .hg/rebasestate <<EOF
26 > 0000000000000000000000000000000000000000
27 > f424eb6a8c01c4a0c0fba9f863f79b3eb5b4b69f
28 > 0000000000000000000000000000000000000000
29 > 0
30 > 0
31 > 0
32 >
33 > 21a6c45028857f500f56ae84fbf40689c429305b:-2
34 > de008c61a447fcfd93f808ef527d933a84048ce7:0000000000000000000000000000000000000000
35 > c1e6b162678d07d0b204e5c8267d51b4e03b633c:0000000000000000000000000000000000000000
36 > aeba276fcb7df8e10153a07ee728d5540693f5aa:-3
37 > bd5548558fcf354d37613005737a143871bf3723:-3
38 > d2fa1c02b2401b0e32867f26cce50818a4bd796a:0000000000000000000000000000000000000000
39 > 6f7a236de6852570cd54649ab62b1012bb78abc8:0000000000000000000000000000000000000000
40 > 6582e6951a9c48c236f746f186378e36f59f4928:0000000000000000000000000000000000000000
41 > EOF
42
43 $ hg rebase --continue
44 rebasing 4:c1e6b162678d "B" (B)
45 rebasing 8:6f7a236de685 "D" (D)
46 rebasing 2:de008c61a447 "E" (E)
47 rebasing 7:d2fa1c02b240 "G" (G)
48 rebasing 9:6582e6951a9c "H" (H tip)
49 warning: orphaned descendants detected, not stripping c1e6b162678d, de008c61a447
50 saved backup bundle to $TESTTMP/.hg/strip-backup/6f7a236de685-9880a3dc-rebase.hg (glob)
51
52 $ hg log -G -T '{rev}:{node|short} {desc}\n'
53 o 11:721b8da0a708 H
54 |
55 o 10:9d65695ec3c2 G
56 |
57 o 9:21c8397a5d68 E
58 |
59 | o 8:fc52970345e8 D
60 | |
61 | o 7:eac96551b107 B
62 |/
63 | o 6:bd5548558fcf C
64 | |
65 | | o 5:aeba276fcb7d F
66 | | |
67 | o | 4:c1e6b162678d B
68 | | |
69 o | | 3:f424eb6a8c01 Z
70 | | |
71 +---o 2:de008c61a447 E
72 | |
73 | o 1:21a6c4502885 A
74 |/
75 o 0:b41ce7760717 R
76
@@ -21,7 +21,6 b' import os'
21 21
22 22 from mercurial.i18n import _
23 23 from mercurial.node import (
24 hex,
25 24 nullid,
26 25 nullrev,
27 26 short,
@@ -60,6 +59,7 b' templateopts = cmdutil.templateopts'
60 59
61 60 # Indicates that a revision needs to be rebased
62 61 revtodo = -1
62 revtodostr = '-1'
63 63
64 64 # legacy revstates no longer needed in current code
65 65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
@@ -146,7 +146,7 b' class rebaseruntime(object):'
146 146 # dict will be what contains most of the rebase progress state.
147 147 self.state = {}
148 148 self.activebookmark = None
149 self.dest = None
149 self.destmap = {}
150 150 self.skipped = set()
151 151
152 152 self.collapsef = opts.get('collapse', False)
@@ -177,34 +177,34 b' class rebaseruntime(object):'
177 177 def _writestatus(self, f):
178 178 repo = self.repo.unfiltered()
179 179 f.write(repo[self.originalwd].hex() + '\n')
180 f.write(repo[self.dest].hex() + '\n')
180 # was "dest". we now write dest per src root below.
181 f.write('\n')
181 182 f.write(repo[self.external].hex() + '\n')
182 183 f.write('%d\n' % int(self.collapsef))
183 184 f.write('%d\n' % int(self.keepf))
184 185 f.write('%d\n' % int(self.keepbranchesf))
185 186 f.write('%s\n' % (self.activebookmark or ''))
187 destmap = self.destmap
186 188 for d, v in self.state.iteritems():
187 189 oldrev = repo[d].hex()
188 190 if v >= 0:
189 191 newrev = repo[v].hex()
190 elif v == revtodo:
191 # To maintain format compatibility, we have to use nullid.
192 # Please do remove this special case when upgrading the format.
193 newrev = hex(nullid)
194 192 else:
195 193 newrev = v
196 f.write("%s:%s\n" % (oldrev, newrev))
194 destnode = repo[destmap[d]].hex()
195 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
197 196 repo.ui.debug('rebase status stored\n')
198 197
199 198 def restorestatus(self):
200 199 """Restore a previously stored status"""
201 200 repo = self.repo
202 201 keepbranches = None
203 dest = None
202 legacydest = None
204 203 collapse = False
205 204 external = nullrev
206 205 activebookmark = None
207 206 state = {}
207 destmap = {}
208 208
209 209 try:
210 210 f = repo.vfs("rebasestate")
@@ -212,7 +212,10 b' class rebaseruntime(object):'
212 212 if i == 0:
213 213 originalwd = repo[l].rev()
214 214 elif i == 1:
215 dest = repo[l].rev()
215 # this line should be empty in newer version. but legacy
216 # clients may still use it
217 if l:
218 legacydest = repo[l].rev()
216 219 elif i == 2:
217 220 external = repo[l].rev()
218 221 elif i == 3:
@@ -227,10 +230,17 b' class rebaseruntime(object):'
227 230 # oldrev:newrev lines
228 231 activebookmark = l
229 232 else:
230 oldrev, newrev = l.split(':')
233 args = l.split(':')
234 oldrev = args[0]
235 newrev = args[1]
231 236 if newrev in legacystates:
232 237 continue
233 elif newrev == nullid:
238 if len(args) > 2:
239 destnode = args[2]
240 else:
241 destnode = legacydest
242 destmap[repo[oldrev].rev()] = repo[destnode].rev()
243 if newrev in (nullid, revtodostr):
234 244 state[repo[oldrev].rev()] = revtodo
235 245 # Legacy compat special case
236 246 else:
@@ -247,7 +257,7 b' class rebaseruntime(object):'
247 257 skipped = set()
248 258 # recompute the set of skipped revs
249 259 if not collapse:
250 seen = {dest}
260 seen = set(destmap.values())
251 261 for old, new in sorted(state.items()):
252 262 if new != revtodo and new in seen:
253 263 skipped.add(old)
@@ -258,7 +268,7 b' class rebaseruntime(object):'
258 268 _setrebasesetvisibility(repo, set(state.keys()) | {originalwd})
259 269
260 270 self.originalwd = originalwd
261 self.dest = dest
271 self.destmap = destmap
262 272 self.state = state
263 273 self.skipped = skipped
264 274 self.collapsef = collapse
@@ -267,12 +277,11 b' class rebaseruntime(object):'
267 277 self.external = external
268 278 self.activebookmark = activebookmark
269 279
270 def _handleskippingobsolete(self, rebaserevs, obsoleterevs, dest):
280 def _handleskippingobsolete(self, obsoleterevs, destmap):
271 281 """Compute structures necessary for skipping obsolete revisions
272 282
273 rebaserevs: iterable of all revisions that are to be rebased
274 283 obsoleterevs: iterable of all obsolete revisions in rebaseset
275 dest: a destination revision for the rebase operation
284 destmap: {srcrev: destrev} destination revisions
276 285 """
277 286 self.obsoletenotrebased = {}
278 287 if not self.ui.configbool('experimental', 'rebaseskipobsolete',
@@ -280,7 +289,7 b' class rebaseruntime(object):'
280 289 return
281 290 obsoleteset = set(obsoleterevs)
282 291 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
283 obsoleteset, dest)
292 obsoleteset, destmap)
284 293 skippedset = set(self.obsoletenotrebased)
285 294 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
286 295
@@ -300,13 +309,14 b' class rebaseruntime(object):'
300 309 hint = _('use "hg rebase --abort" to clear broken state')
301 310 raise error.Abort(msg, hint=hint)
302 311 if isabort:
303 return abort(self.repo, self.originalwd, self.dest,
312 return abort(self.repo, self.originalwd, self.destmap,
304 313 self.state, activebookmark=self.activebookmark)
305 314
306 def _preparenewrebase(self, dest, rebaseset):
307 if dest is None:
315 def _preparenewrebase(self, destmap):
316 if not destmap:
308 317 return _nothingtorebase()
309 318
319 rebaseset = destmap.keys()
310 320 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
311 321 if (not (self.keepf or allowunstable)
312 322 and self.repo.revs('first(children(%ld) - %ld)',
@@ -316,10 +326,10 b' class rebaseruntime(object):'
316 326 " unrebased descendants"),
317 327 hint=_('use --keep to keep original changesets'))
318 328
319 obsrevs = _filterobsoleterevs(self.repo, set(rebaseset))
320 self._handleskippingobsolete(rebaseset, obsrevs, dest.rev())
329 obsrevs = _filterobsoleterevs(self.repo, rebaseset)
330 self._handleskippingobsolete(obsrevs, destmap)
321 331
322 result = buildstate(self.repo, dest, rebaseset, self.collapsef,
332 result = buildstate(self.repo, destmap, self.collapsef,
323 333 self.obsoletenotrebased)
324 334
325 335 if not result:
@@ -333,14 +343,21 b' class rebaseruntime(object):'
333 343 % root,
334 344 hint=_("see 'hg help phases' for details"))
335 345
336 (self.originalwd, self.dest, self.state) = result
346 (self.originalwd, self.destmap, self.state) = result
337 347 if self.collapsef:
338 destancestors = self.repo.changelog.ancestors([self.dest],
348 dests = set(self.destmap.values())
349 if len(dests) != 1:
350 raise error.Abort(
351 _('--collapse does not work with multiple destinations'))
352 destrev = next(iter(dests))
353 destancestors = self.repo.changelog.ancestors([destrev],
339 354 inclusive=True)
340 355 self.external = externalparent(self.repo, self.state, destancestors)
341 356
342 if dest.closesbranch() and not self.keepbranchesf:
343 self.ui.status(_('reopening closed branch head %s\n') % dest)
357 for destrev in sorted(set(destmap.values())):
358 dest = self.repo[destrev]
359 if dest.closesbranch() and not self.keepbranchesf:
360 self.ui.status(_('reopening closed branch head %s\n') % dest)
344 361
345 362 def _performrebase(self, tr):
346 363 repo, ui, opts = self.repo, self.ui, self.opts
@@ -371,6 +388,7 b' class rebaseruntime(object):'
371 388 total = len(cands)
372 389 pos = 0
373 390 for rev in sortedrevs:
391 dest = self.destmap[rev]
374 392 ctx = repo[rev]
375 393 desc = _ctxdesc(ctx)
376 394 if self.state[rev] == rev:
@@ -380,7 +398,8 b' class rebaseruntime(object):'
380 398 ui.status(_('rebasing %s\n') % desc)
381 399 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
382 400 _('changesets'), total)
383 p1, p2, base = defineparents(repo, rev, self.dest, self.state)
401 p1, p2, base = defineparents(repo, rev, self.destmap,
402 self.state)
384 403 self.storestatus(tr=tr)
385 404 storecollapsemsg(repo, self.collapsemsg)
386 405 if len(repo[None].parents()) == 2:
@@ -390,7 +409,7 b' class rebaseruntime(object):'
390 409 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
391 410 'rebase')
392 411 stats = rebasenode(repo, rev, p1, base, self.state,
393 self.collapsef, self.dest)
412 self.collapsef, dest)
394 413 if stats and stats[3] > 0:
395 414 raise error.InterventionRequired(
396 415 _('unresolved conflicts (see hg '
@@ -436,8 +455,8 b' class rebaseruntime(object):'
436 455 def _finishrebase(self):
437 456 repo, ui, opts = self.repo, self.ui, self.opts
438 457 if self.collapsef and not self.keepopen:
439 p1, p2, _base = defineparents(repo, min(self.state),
440 self.dest, self.state)
458 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
459 self.state)
441 460 editopt = opts.get('edit')
442 461 editform = 'rebase.collapse'
443 462 if self.collapsemsg:
@@ -483,7 +502,7 b' class rebaseruntime(object):'
483 502 collapsedas = None
484 503 if self.collapsef:
485 504 collapsedas = newnode
486 clearrebased(ui, repo, self.dest, self.state, self.skipped,
505 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
487 506 collapsedas)
488 507
489 508 clearstatus(repo)
@@ -675,9 +694,9 b' def rebase(ui, repo, **opts):'
675 694 if retcode is not None:
676 695 return retcode
677 696 else:
678 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
679 destspace=destspace)
680 retcode = rbsrt._preparenewrebase(dest, rebaseset)
697 destmap = _definedestmap(ui, repo, destf, srcf, basef, revf,
698 destspace=destspace)
699 retcode = rbsrt._preparenewrebase(destmap)
681 700 if retcode is not None:
682 701 return retcode
683 702
@@ -695,10 +714,9 b' def rebase(ui, repo, **opts):'
695 714
696 715 rbsrt._finishrebase()
697 716
698 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=None,
699 destspace=None):
700 """use revisions argument to define destination and rebase set
701 """
717 def _definedestmap(ui, repo, destf=None, srcf=None, basef=None, revf=None,
718 destspace=None):
719 """use revisions argument to define destmap {srcrev: destrev}"""
702 720 if revf is None:
703 721 revf = []
704 722
@@ -725,12 +743,12 b' def _definesets(ui, repo, destf=None, sr'
725 743 rebaseset = scmutil.revrange(repo, revf)
726 744 if not rebaseset:
727 745 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
728 return None, None
746 return None
729 747 elif srcf:
730 748 src = scmutil.revrange(repo, [srcf])
731 749 if not src:
732 750 ui.status(_('empty "source" revision set - nothing to rebase\n'))
733 return None, None
751 return None
734 752 rebaseset = repo.revs('(%ld)::', src)
735 753 assert rebaseset
736 754 else:
@@ -738,7 +756,7 b' def _definesets(ui, repo, destf=None, sr'
738 756 if not base:
739 757 ui.status(_('empty "base" revision set - '
740 758 "can't compute rebase set\n"))
741 return None, None
759 return None
742 760 if not destf:
743 761 dest = repo[_destrebase(repo, base, destspace=destspace)]
744 762 destf = str(dest)
@@ -782,13 +800,17 b' def _definesets(ui, repo, destf=None, sr'
782 800 else: # can it happen?
783 801 ui.status(_('nothing to rebase from %s to %s\n') %
784 802 ('+'.join(str(repo[r]) for r in base), dest))
785 return None, None
803 return None
786 804
787 805 if not destf:
788 806 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
789 807 destf = str(dest)
790 808
791 return dest, rebaseset
809 # assign dest to each rev in rebaseset
810 destrev = dest.rev()
811 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
812
813 return destmap
792 814
793 815 def externalparent(repo, state, destancestors):
794 816 """Return the revision that should be used as the second parent
@@ -874,7 +896,7 b' def rebasenode(repo, rev, p1, base, stat'
874 896 copies.duplicatecopies(repo, rev, p1rev, skiprev=dest)
875 897 return stats
876 898
877 def adjustdest(repo, rev, dest, state):
899 def adjustdest(repo, rev, destmap, state):
878 900 """adjust rebase destination given the current rebase state
879 901
880 902 rev is what is being rebased. Return a list of two revs, which are the
@@ -914,8 +936,9 b' def adjustdest(repo, rev, dest, state):'
914 936 |/ |/
915 937 A A
916 938 """
917 # pick already rebased revs from state
918 source = [s for s, d in state.items() if d > 0]
939 # pick already rebased revs with same dest from state as interesting source
940 dest = destmap[rev]
941 source = [s for s, d in state.items() if d > 0 and destmap[s] == dest]
919 942
920 943 result = []
921 944 for prev in repo.changelog.parentrevs(rev):
@@ -957,7 +980,7 b' def successorrevs(repo, rev):'
957 980 if s in nodemap:
958 981 yield nodemap[s]
959 982
960 def defineparents(repo, rev, dest, state):
983 def defineparents(repo, rev, destmap, state):
961 984 """Return new parents and optionally a merge base for rev being rebased
962 985
963 986 The destination specified by "dest" cannot always be used directly because
@@ -981,9 +1004,10 b' def defineparents(repo, rev, dest, state'
981 1004 return False
982 1005 return cl.isancestor(cl.node(a), cl.node(b))
983 1006
1007 dest = destmap[rev]
984 1008 oldps = repo.changelog.parentrevs(rev) # old parents
985 1009 newps = [nullrev, nullrev] # new parents
986 dests = adjustdest(repo, rev, dest, state) # adjusted destinations
1010 dests = adjustdest(repo, rev, destmap, state) # adjusted destinations
987 1011 bases = list(oldps) # merge base candidates, initially just old parents
988 1012
989 1013 if all(r == nullrev for r in oldps[1:]):
@@ -1238,7 +1262,7 b' def needupdate(repo, state):'
1238 1262
1239 1263 return False
1240 1264
1241 def abort(repo, originalwd, dest, state, activebookmark=None):
1265 def abort(repo, originalwd, destmap, state, activebookmark=None):
1242 1266 '''Restore the repository to its original state. Additional args:
1243 1267
1244 1268 activebookmark: the name of the bookmark that should be active after the
@@ -1248,7 +1272,7 b' def abort(repo, originalwd, dest, state,'
1248 1272 # If the first commits in the rebased set get skipped during the rebase,
1249 1273 # their values within the state mapping will be the dest rev id. The
1250 1274 # dstates list must must not contain the dest rev (issue4896)
1251 dstates = [s for s in state.values() if s >= 0 and s != dest]
1275 dstates = [s for r, s in state.items() if s >= 0 and s != destmap[r]]
1252 1276 immutable = [d for d in dstates if not repo[d].mutable()]
1253 1277 cleanup = True
1254 1278 if immutable:
@@ -1267,13 +1291,14 b' def abort(repo, originalwd, dest, state,'
1267 1291
1268 1292 if cleanup:
1269 1293 shouldupdate = False
1270 rebased = filter(lambda x: x >= 0 and x != dest, state.values())
1294 rebased = [s for r, s in state.items()
1295 if s >= 0 and s != destmap[r]]
1271 1296 if rebased:
1272 1297 strippoints = [
1273 1298 c.node() for c in repo.set('roots(%ld)', rebased)]
1274 1299
1275 1300 updateifonnodes = set(rebased)
1276 updateifonnodes.add(dest)
1301 updateifonnodes.update(destmap.values())
1277 1302 updateifonnodes.add(originalwd)
1278 1303 shouldupdate = repo['.'].rev() in updateifonnodes
1279 1304
@@ -1295,22 +1320,23 b' def abort(repo, originalwd, dest, state,'
1295 1320 repo.ui.warn(_('rebase aborted\n'))
1296 1321 return 0
1297 1322
1298 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1323 def buildstate(repo, destmap, collapse, obsoletenotrebased):
1299 1324 '''Define which revisions are going to be rebased and where
1300 1325
1301 1326 repo: repo
1302 dest: context
1303 rebaseset: set of rev
1327 destmap: {srcrev: destrev}
1304 1328 '''
1329 rebaseset = destmap.keys()
1305 1330 originalwd = repo['.'].rev()
1306 1331 _setrebasesetvisibility(repo, set(rebaseset) | {originalwd})
1307 1332
1308 1333 # This check isn't strictly necessary, since mq detects commits over an
1309 1334 # applied patch. But it prevents messing up the working directory when
1310 1335 # a partially completed rebase is blocked by mq.
1311 if 'qtip' in repo.tags() and (dest.node() in
1312 [s.node for s in repo.mq.applied]):
1313 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1336 if 'qtip' in repo.tags():
1337 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1338 if set(destmap.values()) & mqapplied:
1339 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1314 1340
1315 1341 roots = list(repo.set('roots(%ld)', rebaseset))
1316 1342 if not roots:
@@ -1319,6 +1345,7 b' def buildstate(repo, dest, rebaseset, co'
1319 1345 state = dict.fromkeys(rebaseset, revtodo)
1320 1346 emptyrebase = True
1321 1347 for root in roots:
1348 dest = repo[destmap[root.rev()]]
1322 1349 commonbase = root.ancestor(dest)
1323 1350 if commonbase == root:
1324 1351 raise error.Abort(_('source is ancestor of destination'))
@@ -1352,6 +1379,7 b' def buildstate(repo, dest, rebaseset, co'
1352 1379 if succ is None:
1353 1380 msg = _('note: not rebasing %s, it has no successor\n') % desc
1354 1381 del state[r]
1382 del destmap[r]
1355 1383 else:
1356 1384 destctx = unfi[succ]
1357 1385 destdesc = '%d:%s "%s"' % (destctx.rev(), destctx,
@@ -1359,10 +1387,11 b' def buildstate(repo, dest, rebaseset, co'
1359 1387 msg = (_('note: not rebasing %s, already in destination as %s\n')
1360 1388 % (desc, destdesc))
1361 1389 del state[r]
1390 del destmap[r]
1362 1391 repo.ui.status(msg)
1363 return originalwd, dest.rev(), state
1392 return originalwd, destmap, state
1364 1393
1365 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None):
1394 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None):
1366 1395 """dispose of rebased revision at the end of the rebase
1367 1396
1368 1397 If `collapsedas` is not None, the rebase was a collapse whose result if the
@@ -1371,7 +1400,7 b' def clearrebased(ui, repo, dest, state, '
1371 1400 # Move bookmark of skipped nodes to destination. This cannot be handled
1372 1401 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1373 1402 # and move bookmark backwards.
1374 bmchanges = [(name, tonode(max(adjustdest(repo, rev, dest, state))))
1403 bmchanges = [(name, tonode(max(adjustdest(repo, rev, destmap, state))))
1375 1404 for rev in skipped
1376 1405 for name in repo.nodebookmarks(tonode(rev))]
1377 1406 if bmchanges:
@@ -1477,7 +1506,7 b' def _filterobsoleterevs(repo, revs):'
1477 1506 """returns a set of the obsolete revisions in revs"""
1478 1507 return set(r for r in revs if repo[r].obsolete())
1479 1508
1480 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1509 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1481 1510 """return a mapping obsolete => successor for all obsolete nodes to be
1482 1511 rebased that have a successors in the destination
1483 1512
@@ -1486,9 +1515,9 b' def _computeobsoletenotrebased(repo, reb'
1486 1515
1487 1516 cl = repo.unfiltered().changelog
1488 1517 nodemap = cl.nodemap
1489 destnode = cl.node(dest)
1490 1518 for srcrev in rebaseobsrevs:
1491 1519 srcnode = cl.node(srcrev)
1520 destnode = cl.node(destmap[srcrev])
1492 1521 # XXX: more advanced APIs are required to handle split correctly
1493 1522 successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1494 1523 if len(successors) == 1:
General Comments 0
You need to be logged in to leave comments. Login now