##// END OF EJS Templates
rebase: move bookmarks with --keep (issue5682)...
Jun Wu -
r34364:2f427b57 4.3.3 stable
parent child Browse files
Show More
@@ -508,12 +508,12 b' class rebaseruntime(object):'
508 ui.note(_("update back to initial working directory parent\n"))
508 ui.note(_("update back to initial working directory parent\n"))
509 hg.updaterepo(repo, newwd, False)
509 hg.updaterepo(repo, newwd, False)
510
510
511 collapsedas = None
511 if not self.keepf:
512 if not self.keepf:
512 collapsedas = None
513 if self.collapsef:
513 if self.collapsef:
514 collapsedas = newnode
514 collapsedas = newnode
515 clearrebased(ui, repo, self.dest, self.state, self.skipped,
515 clearrebased(ui, repo, self.dest, self.state, self.skipped,
516 collapsedas)
516 collapsedas, self.keepf)
517
517
518 clearstatus(repo)
518 clearstatus(repo)
519 clearcollapsemsg(repo)
519 clearcollapsemsg(repo)
@@ -1354,32 +1354,30 b' def buildstate(repo, dest, rebaseset, co'
1354 state[r] = revprecursor
1354 state[r] = revprecursor
1355 return originalwd, dest.rev(), state
1355 return originalwd, dest.rev(), state
1356
1356
1357 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None):
1357 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None, keepf=False):
1358 """dispose of rebased revision at the end of the rebase
1358 """dispose of rebased revision at the end of the rebase
1359
1359
1360 If `collapsedas` is not None, the rebase was a collapse whose result if the
1360 If `collapsedas` is not None, the rebase was a collapse whose result if the
1361 `collapsedas` node."""
1361 `collapsedas` node.
1362
1363 If `keepf` is not True, the rebase has --keep set and no nodes should be
1364 removed (but bookmarks still need to be moved).
1365 """
1362 tonode = repo.changelog.node
1366 tonode = repo.changelog.node
1363 # Move bookmark of skipped nodes to destination. This cannot be handled
1367 replacements = {}
1364 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1368 moves = {}
1365 # and move bookmark backwards.
1366 bmchanges = [(name, tonode(max(adjustdest(repo, rev, dest, state))))
1367 for rev in skipped
1368 for name in repo.nodebookmarks(tonode(rev))]
1369 if bmchanges:
1370 with repo.transaction('rebase') as tr:
1371 repo._bookmarks.applychanges(repo, tr, bmchanges)
1372 mapping = {}
1373 for rev, newrev in sorted(state.items()):
1369 for rev, newrev in sorted(state.items()):
1374 if newrev >= 0 and newrev != rev:
1370 if newrev >= 0 and newrev != rev:
1375 if rev in skipped:
1371 oldnode = tonode(rev)
1376 succs = ()
1372 newnode = collapsedas or tonode(newrev)
1377 elif collapsedas is not None:
1373 moves[oldnode] = newnode
1378 succs = (collapsedas,)
1374 if not keepf:
1379 else:
1375 if rev in skipped:
1380 succs = (tonode(newrev),)
1376 succs = ()
1381 mapping[tonode(rev)] = succs
1377 else:
1382 scmutil.cleanupnodes(repo, mapping, 'rebase')
1378 succs = (newnode,)
1379 replacements[oldnode] = succs
1380 scmutil.cleanupnodes(repo, replacements, 'rebase', moves)
1383
1381
1384 def pullrebase(orig, ui, repo, *args, **opts):
1382 def pullrebase(orig, ui, repo, *args, **opts):
1385 'Call rebase after pull if the latter has been invoked with --rebase'
1383 'Call rebase after pull if the latter has been invoked with --rebase'
@@ -576,23 +576,34 b' class _containsnode(object):'
576 def __contains__(self, node):
576 def __contains__(self, node):
577 return self._revcontains(self._torev(node))
577 return self._revcontains(self._torev(node))
578
578
579 def cleanupnodes(repo, replacements, operation):
579 def cleanupnodes(repo, replacements, operation, moves=None):
580 """do common cleanups when old nodes are replaced by new nodes
580 """do common cleanups when old nodes are replaced by new nodes
581
581
582 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
582 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
583 (we might also want to move working directory parent in the future)
583 (we might also want to move working directory parent in the future)
584
584
585 By default, bookmark moves are calculated automatically from 'replacements',
586 but 'moves' can be used to override that. Also, 'moves' may include
587 additional bookmark moves that should not have associated obsmarkers.
588
585 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
589 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
586 have replacements. operation is a string, like "rebase".
590 have replacements. operation is a string, like "rebase".
587 """
591 """
592 if not replacements and not moves:
593 return
594
595 # translate mapping's other forms
588 if not util.safehasattr(replacements, 'items'):
596 if not util.safehasattr(replacements, 'items'):
589 replacements = {n: () for n in replacements}
597 replacements = {n: () for n in replacements}
590
598
591 # Calculate bookmark movements
599 # Calculate bookmark movements
592 moves = {}
600 if moves is None:
601 moves = {}
593 # Unfiltered repo is needed since nodes in replacements might be hidden.
602 # Unfiltered repo is needed since nodes in replacements might be hidden.
594 unfi = repo.unfiltered()
603 unfi = repo.unfiltered()
595 for oldnode, newnodes in replacements.items():
604 for oldnode, newnodes in replacements.items():
605 if oldnode in moves:
606 continue
596 if len(newnodes) > 1:
607 if len(newnodes) > 1:
597 # usually a split, take the one with biggest rev number
608 # usually a split, take the one with biggest rev number
598 newnode = next(unfi.set('max(%ln)', newnodes)).node()
609 newnode = next(unfi.set('max(%ln)', newnodes)).node()
@@ -646,10 +657,13 b' def cleanupnodes(repo, replacements, ope'
646 rels = [(unfi[n], tuple(unfi[m] for m in s))
657 rels = [(unfi[n], tuple(unfi[m] for m in s))
647 for n, s in sorted(replacements.items(), key=sortfunc)
658 for n, s in sorted(replacements.items(), key=sortfunc)
648 if s or not isobs(n)]
659 if s or not isobs(n)]
649 obsolete.createmarkers(repo, rels, operation=operation)
660 if rels:
661 obsolete.createmarkers(repo, rels, operation=operation)
650 else:
662 else:
651 from . import repair # avoid import cycle
663 from . import repair # avoid import cycle
652 repair.delayedstrip(repo.ui, repo, list(replacements), operation)
664 tostrip = list(replacements)
665 if tostrip:
666 repair.delayedstrip(repo.ui, repo, tostrip, operation)
653
667
654 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None):
668 def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None):
655 if opts is None:
669 if opts is None:
@@ -1,6 +1,7 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 > drawdag=$TESTDIR/drawdag.py
4 >
5 >
5 > [phases]
6 > [phases]
6 > publish=False
7 > publish=False
@@ -210,3 +211,35 b' as --rev arguments (issue3950)'
210 rebasing 6:f677a2907404 "bisect2"
211 rebasing 6:f677a2907404 "bisect2"
211 rebasing 7:325c16001345 "bisect3" (tip bisect)
212 rebasing 7:325c16001345 "bisect3" (tip bisect)
212 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/345c90f326a4-b4840586-rebase.hg (glob)
213 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/345c90f326a4-b4840586-rebase.hg (glob)
214
215 Bookmark and working parent get moved even if --keep is set (issue5682)
216
217 $ hg init $TESTTMP/book-keep
218 $ cd $TESTTMP/book-keep
219 $ hg debugdrawdag <<'EOS'
220 > B C
221 > |/
222 > A
223 > EOS
224 $ eval `hg tags -T 'hg bookmark -ir {node} {tag};\n' | grep -v tip`
225 $ rm .hg/localtags
226 $ hg up -q B
227 $ hg tglog
228 o 2: 'C' bookmarks: C
229 |
230 | @ 1: 'B' bookmarks: B
231 |/
232 o 0: 'A' bookmarks: A
233
234 $ hg rebase -r B -d C --keep
235 rebasing 1:112478962961 "B" (B)
236 $ hg tglog
237 @ 3: 'B' bookmarks: B
238 |
239 o 2: 'C' bookmarks: C
240 |
241 | o 1: 'B' bookmarks:
242 |/
243 o 0: 'A' bookmarks: A
244
245
@@ -47,7 +47,7 b''
47 |/
47 |/
48 o 0 A
48 o 0 A
49
49
50 With --keep, bookmark should not move
50 With --keep, bookmark should move
51
51
52 $ hg rebase -r 3+4 -d E --keep
52 $ hg rebase -r 3+4 -d E --keep
53 rebasing 3:e7b3f00ed42e "D" (BOOK-D)
53 rebasing 3:e7b3f00ed42e "D" (BOOK-D)
@@ -55,15 +55,15 b' With --keep, bookmark should not move'
55 rebasing 4:69a34c08022a "E" (BOOK-E)
55 rebasing 4:69a34c08022a "E" (BOOK-E)
56 note: rebase of 4:69a34c08022a created no changes to commit
56 note: rebase of 4:69a34c08022a created no changes to commit
57 $ hg log -G -T '{rev} {desc} {bookmarks}'
57 $ hg log -G -T '{rev} {desc} {bookmarks}'
58 o 7 E
58 o 7 E BOOK-D BOOK-E
59 |
59 |
60 o 6 D
60 o 6 D
61 |
61 |
62 | o 5 F BOOK-F
62 | o 5 F BOOK-F
63 | |
63 | |
64 | o 4 E BOOK-E
64 | o 4 E
65 | |
65 | |
66 | o 3 D BOOK-D
66 | o 3 D
67 | |
67 | |
68 | o 2 C BOOK-C
68 | o 2 C BOOK-C
69 | |
69 | |
@@ -71,6 +71,11 b' With --keep, bookmark should not move'
71 |/
71 |/
72 o 0 A
72 o 0 A
73
73
74 Move D and E back for the next test
75
76 $ hg bookmark BOOK-D -fqir 3
77 $ hg bookmark BOOK-E -fqir 4
78
74 Bookmark is usually an indication of a head. For changes that are introduced by
79 Bookmark is usually an indication of a head. For changes that are introduced by
75 an ancestor of bookmark B, after moving B to B-NEW, the changes are ideally
80 an ancestor of bookmark B, after moving B to B-NEW, the changes are ideally
76 still introduced by an ancestor of changeset on B-NEW. In the below case,
81 still introduced by an ancestor of changeset on B-NEW. In the below case,
General Comments 0
You need to be logged in to leave comments. Login now