Show More
@@ -547,12 +547,12 b' class rebaseruntime(object):' | |||||
547 | ui.note(_("update back to initial working directory parent\n")) |
|
547 | ui.note(_("update back to initial working directory parent\n")) | |
548 | hg.updaterepo(repo, newwd, False) |
|
548 | hg.updaterepo(repo, newwd, False) | |
549 |
|
549 | |||
|
550 | collapsedas = None | |||
550 | if not self.keepf: |
|
551 | if not self.keepf: | |
551 | collapsedas = None |
|
|||
552 | if self.collapsef: |
|
552 | if self.collapsef: | |
553 | collapsedas = newnode |
|
553 | collapsedas = newnode | |
554 |
|
|
554 | clearrebased(ui, repo, self.destmap, self.state, self.skipped, | |
555 |
|
|
555 | collapsedas, self.keepf) | |
556 |
|
556 | |||
557 | clearstatus(repo) |
|
557 | clearstatus(repo) | |
558 | clearcollapsemsg(repo) |
|
558 | clearcollapsemsg(repo) | |
@@ -1516,32 +1516,31 b' def buildstate(repo, destmap, collapse):' | |||||
1516 | state[rev] = rev |
|
1516 | state[rev] = rev | |
1517 | return originalwd, destmap, state |
|
1517 | return originalwd, destmap, state | |
1518 |
|
1518 | |||
1519 |
def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None |
|
1519 | def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None, | |
|
1520 | keepf=False): | |||
1520 | """dispose of rebased revision at the end of the rebase |
|
1521 | """dispose of rebased revision at the end of the rebase | |
1521 |
|
1522 | |||
1522 | If `collapsedas` is not None, the rebase was a collapse whose result if the |
|
1523 | If `collapsedas` is not None, the rebase was a collapse whose result if the | |
1523 |
`collapsedas` node. |
|
1524 | `collapsedas` node. | |
|
1525 | ||||
|
1526 | If `keepf` is not True, the rebase has --keep set and no nodes should be | |||
|
1527 | removed (but bookmarks still need to be moved). | |||
|
1528 | """ | |||
1524 | tonode = repo.changelog.node |
|
1529 | tonode = repo.changelog.node | |
1525 | # Move bookmark of skipped nodes to destination. This cannot be handled |
|
1530 | replacements = {} | |
1526 | # by scmutil.cleanupnodes since it will treat rev as removed (no successor) |
|
1531 | moves = {} | |
1527 | # and move bookmark backwards. |
|
|||
1528 | bmchanges = [(name, tonode(state[rev])) |
|
|||
1529 | for rev in skipped |
|
|||
1530 | for name in repo.nodebookmarks(tonode(rev))] |
|
|||
1531 | if bmchanges: |
|
|||
1532 | with repo.transaction('rebase') as tr: |
|
|||
1533 | repo._bookmarks.applychanges(repo, tr, bmchanges) |
|
|||
1534 | mapping = {} |
|
|||
1535 | for rev, newrev in sorted(state.items()): |
|
1532 | for rev, newrev in sorted(state.items()): | |
1536 | if newrev >= 0 and newrev != rev: |
|
1533 | if newrev >= 0 and newrev != rev: | |
1537 | if rev in skipped: |
|
1534 | oldnode = tonode(rev) | |
1538 | succs = () |
|
1535 | newnode = collapsedas or tonode(newrev) | |
1539 | elif collapsedas is not None: |
|
1536 | moves[oldnode] = newnode | |
1540 | succs = (collapsedas,) |
|
1537 | if not keepf: | |
1541 |
|
|
1538 | if rev in skipped: | |
1542 |
succs = ( |
|
1539 | succs = () | |
1543 | mapping[tonode(rev)] = succs |
|
1540 | else: | |
1544 | scmutil.cleanupnodes(repo, mapping, 'rebase') |
|
1541 | succs = (newnode,) | |
|
1542 | replacements[oldnode] = succs | |||
|
1543 | scmutil.cleanupnodes(repo, replacements, 'rebase', moves) | |||
1545 |
|
1544 | |||
1546 | def pullrebase(orig, ui, repo, *args, **opts): |
|
1545 | def pullrebase(orig, ui, repo, *args, **opts): | |
1547 | 'Call rebase after pull if the latter has been invoked with --rebase' |
|
1546 | 'Call rebase after pull if the latter has been invoked with --rebase' |
@@ -594,41 +594,59 b' class _containsnode(object):' | |||||
594 | def __contains__(self, node): |
|
594 | def __contains__(self, node): | |
595 | return self._revcontains(self._torev(node)) |
|
595 | return self._revcontains(self._torev(node)) | |
596 |
|
596 | |||
597 |
def cleanupnodes(repo, |
|
597 | def cleanupnodes(repo, replacements, operation, moves=None): | |
598 | """do common cleanups when old nodes are replaced by new nodes |
|
598 | """do common cleanups when old nodes are replaced by new nodes | |
599 |
|
599 | |||
600 | That includes writing obsmarkers or stripping nodes, and moving bookmarks. |
|
600 | That includes writing obsmarkers or stripping nodes, and moving bookmarks. | |
601 | (we might also want to move working directory parent in the future) |
|
601 | (we might also want to move working directory parent in the future) | |
602 |
|
602 | |||
603 | mapping is {oldnode: [newnode]} or a iterable of nodes if they do not have |
|
603 | By default, bookmark moves are calculated automatically from 'replacements', | |
604 | replacements. operation is a string, like "rebase". |
|
604 | but 'moves' can be used to override that. Also, 'moves' may include | |
|
605 | additional bookmark moves that should not have associated obsmarkers. | |||
|
606 | ||||
|
607 | replacements is {oldnode: [newnode]} or a iterable of nodes if they do not | |||
|
608 | have replacements. operation is a string, like "rebase". | |||
605 | """ |
|
609 | """ | |
606 | if not util.safehasattr(mapping, 'items'): |
|
610 | if not replacements and not moves: | |
607 | mapping = {n: () for n in mapping} |
|
611 | return | |
|
612 | ||||
|
613 | # translate mapping's other forms | |||
|
614 | if not util.safehasattr(replacements, 'items'): | |||
|
615 | replacements = {n: () for n in replacements} | |||
|
616 | ||||
|
617 | # Calculate bookmark movements | |||
|
618 | if moves is None: | |||
|
619 | moves = {} | |||
|
620 | # Unfiltered repo is needed since nodes in replacements might be hidden. | |||
|
621 | unfi = repo.unfiltered() | |||
|
622 | for oldnode, newnodes in replacements.items(): | |||
|
623 | if oldnode in moves: | |||
|
624 | continue | |||
|
625 | if len(newnodes) > 1: | |||
|
626 | # usually a split, take the one with biggest rev number | |||
|
627 | newnode = next(unfi.set('max(%ln)', newnodes)).node() | |||
|
628 | elif len(newnodes) == 0: | |||
|
629 | # move bookmark backwards | |||
|
630 | roots = list(unfi.set('max((::%n) - %ln)', oldnode, | |||
|
631 | list(replacements))) | |||
|
632 | if roots: | |||
|
633 | newnode = roots[0].node() | |||
|
634 | else: | |||
|
635 | newnode = nullid | |||
|
636 | else: | |||
|
637 | newnode = newnodes[0] | |||
|
638 | moves[oldnode] = newnode | |||
608 |
|
639 | |||
609 | with repo.transaction('cleanup') as tr: |
|
640 | with repo.transaction('cleanup') as tr: | |
610 | # Move bookmarks |
|
641 | # Move bookmarks | |
611 | bmarks = repo._bookmarks |
|
642 | bmarks = repo._bookmarks | |
612 | bmarkchanges = [] |
|
643 | bmarkchanges = [] | |
613 |
allnewnodes = [n for ns in |
|
644 | allnewnodes = [n for ns in replacements.values() for n in ns] | |
614 |
for oldnode, newnode |
|
645 | for oldnode, newnode in moves.items(): | |
615 | oldbmarks = repo.nodebookmarks(oldnode) |
|
646 | oldbmarks = repo.nodebookmarks(oldnode) | |
616 | if not oldbmarks: |
|
647 | if not oldbmarks: | |
617 | continue |
|
648 | continue | |
618 | from . import bookmarks # avoid import cycle |
|
649 | from . import bookmarks # avoid import cycle | |
619 | if len(newnodes) > 1: |
|
|||
620 | # usually a split, take the one with biggest rev number |
|
|||
621 | newnode = next(repo.set('max(%ln)', newnodes)).node() |
|
|||
622 | elif len(newnodes) == 0: |
|
|||
623 | # move bookmark backwards |
|
|||
624 | roots = list(repo.set('max((::%n) - %ln)', oldnode, |
|
|||
625 | list(mapping))) |
|
|||
626 | if roots: |
|
|||
627 | newnode = roots[0].node() |
|
|||
628 | else: |
|
|||
629 | newnode = nullid |
|
|||
630 | else: |
|
|||
631 | newnode = newnodes[0] |
|
|||
632 | repo.ui.debug('moving bookmarks %r from %s to %s\n' % |
|
650 | repo.ui.debug('moving bookmarks %r from %s to %s\n' % | |
633 | (oldbmarks, hex(oldnode), hex(newnode))) |
|
651 | (oldbmarks, hex(oldnode), hex(newnode))) | |
634 | # Delete divergent bookmarks being parents of related newnodes |
|
652 | # Delete divergent bookmarks being parents of related newnodes | |
@@ -651,18 +669,19 b' def cleanupnodes(repo, mapping, operatio' | |||||
651 | # Also sort the node in topology order, that might be useful for |
|
669 | # Also sort the node in topology order, that might be useful for | |
652 | # some obsstore logic. |
|
670 | # some obsstore logic. | |
653 | # NOTE: the filtering and sorting might belong to createmarkers. |
|
671 | # NOTE: the filtering and sorting might belong to createmarkers. | |
654 | # Unfiltered repo is needed since nodes in mapping might be hidden. |
|
|||
655 | unfi = repo.unfiltered() |
|
|||
656 | isobs = unfi.obsstore.successors.__contains__ |
|
672 | isobs = unfi.obsstore.successors.__contains__ | |
657 | torev = unfi.changelog.rev |
|
673 | torev = unfi.changelog.rev | |
658 | sortfunc = lambda ns: torev(ns[0]) |
|
674 | sortfunc = lambda ns: torev(ns[0]) | |
659 | rels = [(unfi[n], tuple(unfi[m] for m in s)) |
|
675 | rels = [(unfi[n], tuple(unfi[m] for m in s)) | |
660 |
for n, s in sorted( |
|
676 | for n, s in sorted(replacements.items(), key=sortfunc) | |
661 | if s or not isobs(n)] |
|
677 | if s or not isobs(n)] | |
662 | obsolete.createmarkers(repo, rels, operation=operation) |
|
678 | if rels: | |
|
679 | obsolete.createmarkers(repo, rels, operation=operation) | |||
663 | else: |
|
680 | else: | |
664 | from . import repair # avoid import cycle |
|
681 | from . import repair # avoid import cycle | |
665 | repair.delayedstrip(repo.ui, repo, list(mapping), operation) |
|
682 | tostrip = list(replacements) | |
|
683 | if tostrip: | |||
|
684 | repair.delayedstrip(repo.ui, repo, tostrip, operation) | |||
666 |
|
685 | |||
667 | def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): |
|
686 | def addremove(repo, matcher, prefix, opts=None, dry_run=None, similarity=None): | |
668 | if opts is None: |
|
687 | if opts is None: |
@@ -1488,7 +1488,7 b' class ui(object):' | |||||
1488 |
|
1488 | |||
1489 | def _progclear(self): |
|
1489 | def _progclear(self): | |
1490 | """clear progress bar output if any. use it before any output""" |
|
1490 | """clear progress bar output if any. use it before any output""" | |
1491 |
if |
|
1491 | if not haveprogbar(): # nothing loaded yet | |
1492 | return |
|
1492 | return | |
1493 | if self._progbar is not None and self._progbar.printed: |
|
1493 | if self._progbar is not None and self._progbar.printed: | |
1494 | self._progbar.clear() |
|
1494 | self._progbar.clear() | |
@@ -1792,3 +1792,6 b' def getprogbar(ui):' | |||||
1792 | # this is how the extension used to work but feel free to rework it. |
|
1792 | # this is how the extension used to work but feel free to rework it. | |
1793 | _progresssingleton = progress.progbar(ui) |
|
1793 | _progresssingleton = progress.progbar(ui) | |
1794 | return _progresssingleton |
|
1794 | return _progresssingleton | |
|
1795 | ||||
|
1796 | def haveprogbar(): | |||
|
1797 | return _progresssingleton is not 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" (bisect tip) |
|
212 | rebasing 7:325c16001345 "bisect3" (bisect tip) | |
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 |
|
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 |
|
64 | | o 4 E | |
65 | | | |
|
65 | | | | |
66 |
| o 3 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, |
@@ -63,6 +63,14 b" Preparing the 'main' repo which depends " | |||||
63 | \r (no-eol) (esc) |
|
63 | \r (no-eol) (esc) | |
64 | \r (no-eol) (esc) |
|
64 | \r (no-eol) (esc) | |
65 | updating [===========================================>] 3/3\r (no-eol) (esc) |
|
65 | updating [===========================================>] 3/3\r (no-eol) (esc) | |
|
66 | \r (no-eol) (esc) | |||
|
67 | \r (no-eol) (esc) | |||
|
68 | linking [ <=> ] 1\r (no-eol) (esc) | |||
|
69 | linking [ <=> ] 2\r (no-eol) (esc) | |||
|
70 | linking [ <=> ] 3\r (no-eol) (esc) | |||
|
71 | linking [ <=> ] 4\r (no-eol) (esc) | |||
|
72 | linking [ <=> ] 5\r (no-eol) (esc) | |||
|
73 | linking [ <=> ] 6\r (no-eol) (esc) | |||
66 | updating [===========================================>] 1/1\r (no-eol) (esc) |
|
74 | updating [===========================================>] 1/1\r (no-eol) (esc) | |
67 | \r (no-eol) (esc) |
|
75 | \r (no-eol) (esc) | |
68 | updating to branch default |
|
76 | updating to branch default | |
@@ -154,7 +162,25 b' Clone main' | |||||
154 | \r (no-eol) (esc) |
|
162 | \r (no-eol) (esc) | |
155 | \r (no-eol) (esc) |
|
163 | \r (no-eol) (esc) | |
156 | updating [===========================================>] 3/3\r (no-eol) (esc) |
|
164 | updating [===========================================>] 3/3\r (no-eol) (esc) | |
|
165 | \r (no-eol) (esc) | |||
|
166 | \r (no-eol) (esc) | |||
|
167 | linking [ <=> ] 1\r (no-eol) (esc) | |||
|
168 | linking [ <=> ] 2\r (no-eol) (esc) | |||
|
169 | linking [ <=> ] 3\r (no-eol) (esc) | |||
|
170 | linking [ <=> ] 4\r (no-eol) (esc) | |||
|
171 | linking [ <=> ] 5\r (no-eol) (esc) | |||
|
172 | linking [ <=> ] 6\r (no-eol) (esc) | |||
|
173 | linking [ <=> ] 7\r (no-eol) (esc) | |||
|
174 | linking [ <=> ] 8\r (no-eol) (esc) | |||
157 | updating [===========================================>] 3/3\r (no-eol) (esc) |
|
175 | updating [===========================================>] 3/3\r (no-eol) (esc) | |
|
176 | \r (no-eol) (esc) | |||
|
177 | \r (no-eol) (esc) | |||
|
178 | linking [ <=> ] 1\r (no-eol) (esc) | |||
|
179 | linking [ <=> ] 2\r (no-eol) (esc) | |||
|
180 | linking [ <=> ] 3\r (no-eol) (esc) | |||
|
181 | linking [ <=> ] 4\r (no-eol) (esc) | |||
|
182 | linking [ <=> ] 5\r (no-eol) (esc) | |||
|
183 | linking [ <=> ] 6\r (no-eol) (esc) | |||
158 | updating [===========================================>] 1/1\r (no-eol) (esc) |
|
184 | updating [===========================================>] 1/1\r (no-eol) (esc) | |
159 | \r (no-eol) (esc) |
|
185 | \r (no-eol) (esc) | |
160 | updating to branch default |
|
186 | updating to branch default |
General Comments 0
You need to be logged in to leave comments.
Login now