Show More
@@ -361,7 +361,7 b' class rebaseruntime(object):' | |||
|
361 | 361 | self.ui.status(_('reopening closed branch head %s\n') % dest) |
|
362 | 362 | |
|
363 | 363 | def _performrebase(self, tr): |
|
364 |
repo, ui |
|
|
364 | repo, ui = self.repo, self.ui | |
|
365 | 365 | if self.keepbranchesf: |
|
366 | 366 | # insert _savebranch at the start of extrafns so if |
|
367 | 367 | # there's a user-provided extrafn it can clobber branch if |
@@ -384,10 +384,17 b' class rebaseruntime(object):' | |||
|
384 | 384 | # if we fail before the transaction closes. |
|
385 | 385 | self.storestatus() |
|
386 | 386 | |
|
387 | sortedrevs = repo.revs('sort(%ld, -topo)', self.state) | |
|
388 | 387 | cands = [k for k, v in self.state.iteritems() if v == revtodo] |
|
389 | 388 | total = len(cands) |
|
390 | 389 | pos = 0 |
|
390 | for subset in sortsource(self.destmap): | |
|
391 | pos = self._performrebasesubset(tr, subset, pos, total) | |
|
392 | ui.progress(_('rebasing'), None) | |
|
393 | ui.note(_('rebase merging completed\n')) | |
|
394 | ||
|
395 | def _performrebasesubset(self, tr, subset, pos, total): | |
|
396 | repo, ui, opts = self.repo, self.ui, self.opts | |
|
397 | sortedrevs = repo.revs('sort(%ld, -topo)', subset) | |
|
391 | 398 | for rev in sortedrevs: |
|
392 | 399 | dest = self.destmap[rev] |
|
393 | 400 | ctx = repo[rev] |
@@ -449,9 +456,7 b' class rebaseruntime(object):' | |||
|
449 | 456 | else: |
|
450 | 457 | ui.status(_('already rebased %s as %s\n') % |
|
451 | 458 | (desc, repo[self.state[rev]])) |
|
452 | ||
|
453 | ui.progress(_('rebasing'), None) | |
|
454 | ui.note(_('rebase merging completed\n')) | |
|
459 | return pos | |
|
455 | 460 | |
|
456 | 461 | def _finishrebase(self): |
|
457 | 462 | repo, ui, opts = self.repo, self.ui, self.opts |
@@ -969,6 +974,18 b' def adjustdest(repo, rev, destmap, state' | |||
|
969 | 974 | | B | ... |
|
970 | 975 | |/ |/ |
|
971 | 976 | A A |
|
977 | ||
|
978 | Besides, adjust dest according to existing rebase information. For example, | |
|
979 | ||
|
980 | B C D B needs to be rebased on top of C, C needs to be rebased on top | |
|
981 | \|/ of D. We will rebase C first. | |
|
982 | A | |
|
983 | ||
|
984 | C' After rebasing C, when considering B's destination, use C' | |
|
985 | | instead of the original C. | |
|
986 | B D | |
|
987 | \ / | |
|
988 | A | |
|
972 | 989 | """ |
|
973 | 990 | # pick already rebased revs with same dest from state as interesting source |
|
974 | 991 | dest = destmap[rev] |
@@ -981,6 +998,12 b' def adjustdest(repo, rev, destmap, state' | |||
|
981 | 998 | candidate = repo.revs('max(%ld and (::%d))', source, prev).first() |
|
982 | 999 | if candidate is not None: |
|
983 | 1000 | adjusted = state[candidate] |
|
1001 | if adjusted == dest and dest in state: | |
|
1002 | adjusted = state[dest] | |
|
1003 | if adjusted == revtodo: | |
|
1004 | # sortsource should produce an order that makes this impossible | |
|
1005 | raise error.ProgrammingError( | |
|
1006 | 'rev %d should be rebased already at this time' % dest) | |
|
984 | 1007 | result.append(adjusted) |
|
985 | 1008 | return result |
|
986 | 1009 | |
@@ -1128,6 +1151,12 b' def defineparents(repo, rev, destmap, st' | |||
|
1128 | 1151 | 'moving at least one of its parents') |
|
1129 | 1152 | % (rev, repo[rev])) |
|
1130 | 1153 | |
|
1154 | # Source should not be ancestor of dest. The check here guarantees it's | |
|
1155 | # impossible. With multi-dest, the initial check does not cover complex | |
|
1156 | # cases since we don't have abstractions to dry-run rebase cheaply. | |
|
1157 | if any(p != nullrev and isancestor(rev, p) for p in newps): | |
|
1158 | raise error.Abort(_('source is ancestor of destination')) | |
|
1159 | ||
|
1131 | 1160 | # "rebasenode" updates to new p1, use the corresponding merge base. |
|
1132 | 1161 | if bases[0] != nullrev: |
|
1133 | 1162 | base = bases[0] |
@@ -1354,6 +1383,31 b' def abort(repo, originalwd, destmap, sta' | |||
|
1354 | 1383 | repo.ui.warn(_('rebase aborted\n')) |
|
1355 | 1384 | return 0 |
|
1356 | 1385 | |
|
1386 | def sortsource(destmap): | |
|
1387 | """yield source revisions in an order that we only rebase things once | |
|
1388 | ||
|
1389 | If source and destination overlaps, we should filter out revisions | |
|
1390 | depending on other revisions which hasn't been rebased yet. | |
|
1391 | ||
|
1392 | Yield a sorted list of revisions each time. | |
|
1393 | ||
|
1394 | For example, when rebasing A to B, B to C. This function yields [B], then | |
|
1395 | [A], indicating B needs to be rebased first. | |
|
1396 | ||
|
1397 | Raise if there is a cycle so the rebase is impossible. | |
|
1398 | """ | |
|
1399 | srcset = set(destmap) | |
|
1400 | while srcset: | |
|
1401 | srclist = sorted(srcset) | |
|
1402 | result = [] | |
|
1403 | for r in srclist: | |
|
1404 | if destmap[r] not in srcset: | |
|
1405 | result.append(r) | |
|
1406 | if not result: | |
|
1407 | raise error.Abort(_('source and destination form a cycle')) | |
|
1408 | srcset -= set(result) | |
|
1409 | yield result | |
|
1410 | ||
|
1357 | 1411 | def buildstate(repo, destmap, collapse, obsoletenotrebased): |
|
1358 | 1412 | '''Define which revisions are going to be rebased and where |
|
1359 | 1413 | |
@@ -1372,12 +1426,21 b' def buildstate(repo, destmap, collapse, ' | |||
|
1372 | 1426 | if set(destmap.values()) & mqapplied: |
|
1373 | 1427 | raise error.Abort(_('cannot rebase onto an applied mq patch')) |
|
1374 | 1428 | |
|
1375 | roots = list(repo.set('roots(%ld)', rebaseset)) | |
|
1429 | # Get "cycle" error early by exhausting the generator. | |
|
1430 | sortedsrc = list(sortsource(destmap)) # a list of sorted revs | |
|
1431 | if not sortedsrc: | |
|
1432 | raise error.Abort(_('no matching revisions')) | |
|
1433 | ||
|
1434 | # Only check the first batch of revisions to rebase not depending on other | |
|
1435 | # rebaseset. This means "source is ancestor of destination" for the second | |
|
1436 | # (and following) batches of revisions are not checked here. We rely on | |
|
1437 | # "defineparents" to do that check. | |
|
1438 | roots = list(repo.set('roots(%ld)', sortedsrc[0])) | |
|
1376 | 1439 | if not roots: |
|
1377 | 1440 | raise error.Abort(_('no matching revisions')) |
|
1378 | 1441 | roots.sort() |
|
1379 | 1442 | state = dict.fromkeys(rebaseset, revtodo) |
|
1380 |
emptyrebase = |
|
|
1443 | emptyrebase = (len(sortedsrc) == 1) | |
|
1381 | 1444 | for root in roots: |
|
1382 | 1445 | dest = repo[destmap[root.rev()]] |
|
1383 | 1446 | commonbase = root.ancestor(dest) |
@@ -204,7 +204,7 b' Destination is an ancestor of source:' | |||
|
204 | 204 | > | |
|
205 | 205 | > Z |
|
206 | 206 | > EOS |
|
207 |
abort: source |
|
|
207 | abort: source and destination form a cycle | |
|
208 | 208 | [255] |
|
209 | 209 | |
|
210 | 210 | Switch roots: |
@@ -291,22 +291,163 b' Move to a previous parent:' | |||
|
291 | 291 | |/ |
|
292 | 292 | o 0: A |
|
293 | 293 | |
|
294 |
Source overlaps with destination |
|
|
294 | Source overlaps with destination: | |
|
295 | 295 | |
|
296 | 296 | $ rebasewithdag -s 'B+C+D' -d 'map(SRC, "B:C,C:D")' <<'EOS' |
|
297 | 297 | > B C D |
|
298 | 298 | > \|/ |
|
299 | 299 | > A |
|
300 | 300 | > EOS |
|
301 | rebasing 2:dc0947a82db8 "C" (C) | |
|
301 | 302 | rebasing 1:112478962961 "B" (B) |
|
302 | rebasing 2:dc0947a82db8 "C" (C) | |
|
303 | o 5: C | |
|
303 | o 5: B | |
|
304 | | | |
|
305 | o 4: C | |
|
306 | | | |
|
307 | o 3: D | |
|
308 | | | |
|
309 | o 0: A | |
|
310 | ||
|
311 | Detect cycles early: | |
|
312 | ||
|
313 | $ rebasewithdag -r 'all()-Z' -d 'map(SRC, "A:B,B:C,C:D,D:B")' <<'EOS' | |
|
314 | > A B C | |
|
315 | > \|/ | |
|
316 | > | D | |
|
317 | > |/ | |
|
318 | > Z | |
|
319 | > EOS | |
|
320 | abort: source and destination form a cycle | |
|
321 | [255] | |
|
322 | ||
|
323 | Detect source is ancestor of dest in runtime: | |
|
324 | ||
|
325 | $ rebasewithdag -r 'C+B' -d 'map(SRC, "C:B,B:D")' -q <<'EOS' | |
|
326 | > D | |
|
327 | > | | |
|
328 | > B C | |
|
329 | > \| | |
|
330 | > A | |
|
331 | > EOS | |
|
332 | abort: source is ancestor of destination | |
|
333 | [255] | |
|
334 | ||
|
335 | "Already rebased" fast path still works: | |
|
336 | ||
|
337 | $ rebasewithdag -r 'all()' -d 'SRC^' <<'EOS' | |
|
338 | > E F | |
|
339 | > /| | | |
|
340 | > B C D | |
|
341 | > \|/ | |
|
342 | > A | |
|
343 | > EOS | |
|
344 | already rebased 1:112478962961 "B" (B) | |
|
345 | already rebased 2:dc0947a82db8 "C" (C) | |
|
346 | already rebased 3:b18e25de2cf5 "D" (D) | |
|
347 | already rebased 4:312782b8f06e "E" (E) | |
|
348 | already rebased 5:ad6717a6a58e "F" (F tip) | |
|
349 | o 5: F | |
|
304 | 350 | | |
|
305 | 351 | o 3: D |
|
306 | 352 | | |
|
307 |
| o 4: |
|
|
353 | | o 4: E | |
|
354 | | |\ | |
|
355 | +---o 2: C | |
|
308 | 356 | | | |
|
309 |
| |
|
|
357 | | o 1: B | |
|
310 | 358 | |/ |
|
311 | 359 | o 0: A |
|
312 | 360 | |
|
361 | Massively rewrite the DAG: | |
|
362 | ||
|
363 | $ rebasewithdag -r 'all()' -d 'map(SRC, "A:I,I:null,H:A,B:J,J:C,C:H,D:E,F:G,G:K,K:D,E:B")' <<'EOS' | |
|
364 | > D G K | |
|
365 | > | | | | |
|
366 | > C F J | |
|
367 | > | | | | |
|
368 | > B E I | |
|
369 | > \| | | |
|
370 | > A H | |
|
371 | > EOS | |
|
372 | rebasing 4:701514e1408d "I" (I) | |
|
373 | rebasing 0:426bada5c675 "A" (A) | |
|
374 | rebasing 1:e7050b6e5048 "H" (H) | |
|
375 | rebasing 5:26805aba1e60 "C" (C) | |
|
376 | rebasing 7:cf89f86b485b "J" (J) | |
|
377 | rebasing 2:112478962961 "B" (B) | |
|
378 | rebasing 3:7fb047a69f22 "E" (E) | |
|
379 | rebasing 8:f585351a92f8 "D" (D) | |
|
380 | rebasing 10:ae41898d7875 "K" (K tip) | |
|
381 | rebasing 9:711f53bbef0b "G" (G) | |
|
382 | rebasing 6:64a8289d2492 "F" (F) | |
|
383 | o 21: F | |
|
384 | | | |
|
385 | o 20: G | |
|
386 | | | |
|
387 | o 19: K | |
|
388 | | | |
|
389 | o 18: D | |
|
390 | | | |
|
391 | o 17: E | |
|
392 | | | |
|
393 | o 16: B | |
|
394 | | | |
|
395 | o 15: J | |
|
396 | | | |
|
397 | o 14: C | |
|
398 | | | |
|
399 | o 13: H | |
|
400 | | | |
|
401 | o 12: A | |
|
402 | | | |
|
403 | o 11: I | |
|
404 | ||
|
405 | Resolve instability: | |
|
406 | ||
|
407 | $ rebasewithdag <<'EOF' -r 'orphan()-obsolete()' -d 'max((successors(max(roots(ALLSRC) & ::SRC)^)-obsolete())::)' | |
|
408 | > F2 | |
|
409 | > | | |
|
410 | > J E E2 | |
|
411 | > | |/ | |
|
412 | > I2 I | E3 | |
|
413 | > \| |/ | |
|
414 | > H | G | |
|
415 | > | | | | |
|
416 | > B2 D F | |
|
417 | > | |/ # rebase: B -> B2 | |
|
418 | > N C # amend: E -> E2 | |
|
419 | > | | # amend: E2 -> E3 | |
|
420 | > M B # rebase: F -> F2 | |
|
421 | > \| # amend: I -> I2 | |
|
422 | > A | |
|
423 | > EOF | |
|
424 | rebasing 16:5c432343bf59 "J" (J tip) | |
|
425 | rebasing 3:26805aba1e60 "C" (C) | |
|
426 | rebasing 6:f585351a92f8 "D" (D) | |
|
427 | rebasing 10:ffebc37c5d0b "E3" (E3) | |
|
428 | rebasing 13:fb184bcfeee8 "F2" (F2) | |
|
429 | rebasing 11:dc838ab4c0da "G" (G) | |
|
430 | o 22: G | |
|
431 | | | |
|
432 | o 21: F2 | |
|
433 | | | |
|
434 | o 20: E3 | |
|
435 | | | |
|
436 | o 19: D | |
|
437 | | | |
|
438 | o 18: C | |
|
439 | | | |
|
440 | o 17: J | |
|
441 | | | |
|
442 | o 15: I2 | |
|
443 | | | |
|
444 | o 12: H | |
|
445 | | | |
|
446 | o 5: B2 | |
|
447 | | | |
|
448 | o 4: N | |
|
449 | | | |
|
450 | o 2: M | |
|
451 | | | |
|
452 | o 0: A | |
|
453 |
@@ -245,7 +245,7 b' Rebasing descendant onto ancestor across' | |||
|
245 | 245 | @ 0: 'A' |
|
246 | 246 | |
|
247 | 247 | $ hg rebase -s 5 -d 6 |
|
248 |
abort: source |
|
|
248 | abort: source and destination form a cycle | |
|
249 | 249 | [255] |
|
250 | 250 | |
|
251 | 251 | $ hg rebase -s 6 -d 5 |
@@ -264,7 +264,7 b' G onto F - rebase onto an ancestor:' | |||
|
264 | 264 | F onto G - rebase onto a descendant: |
|
265 | 265 | |
|
266 | 266 | $ hg rebase -s 5 -d 6 |
|
267 |
abort: source |
|
|
267 | abort: source and destination form a cycle | |
|
268 | 268 | [255] |
|
269 | 269 | |
|
270 | 270 | G onto B - merge revision with both parents not in ancestors of target: |
General Comments 0
You need to be logged in to leave comments.
Login now