Mercurial > hg
comparison hgext/rebase.py @ 7278:45495d784ad6
rebase: avoid redundant merges (issue1301)
author | Stefano Tortarolo <stefano.tortarolo@gmail.com> |
---|---|
date | Tue, 16 Sep 2008 17:51:14 +0200 |
parents | 292fb2ad2846 |
children | ddab62b2fec4 |
comparison
equal
deleted
inserted
replaced
7277:3e000e2bf5f6 | 7278:45495d784ad6 |
---|---|
11 | 11 |
12 For more information: | 12 For more information: |
13 http://www.selenic.com/mercurial/wiki/index.cgi/RebaseProject | 13 http://www.selenic.com/mercurial/wiki/index.cgi/RebaseProject |
14 ''' | 14 ''' |
15 | 15 |
16 from mercurial import util, repair, merge, cmdutil, dispatch, commands, extensions | 16 from mercurial import util, repair, merge, cmdutil, dispatch, commands |
17 from mercurial import extensions, ancestor | |
17 from mercurial.commands import templateopts | 18 from mercurial.commands import templateopts |
18 from mercurial.node import nullrev | 19 from mercurial.node import nullrev |
19 from mercurial.i18n import _ | 20 from mercurial.i18n import _ |
20 import os, errno | 21 import os, errno |
22 | |
23 def rebasemerge(repo, rev, first=False): | |
24 'return the correct ancestor' | |
25 oldancestor = ancestor.ancestor | |
26 | |
27 def newancestor(a, b, pfunc): | |
28 ancestor.ancestor = oldancestor | |
29 anc = ancestor.ancestor(a, b, pfunc) | |
30 if b == rev: | |
31 return repo[rev].parents()[0].rev() | |
32 return ancestor.ancestor(a, b, pfunc) | |
33 | |
34 if not first: | |
35 ancestor.ancestor = newancestor | |
36 else: | |
37 repo.ui.debug(_("First revision, do not change ancestor\n")) | |
38 stats = merge.update(repo, rev, True, True, False) | |
39 return stats | |
21 | 40 |
22 def rebase(ui, repo, **opts): | 41 def rebase(ui, repo, **opts): |
23 """move changeset (and descendants) to a different branch | 42 """move changeset (and descendants) to a different branch |
24 | 43 |
25 Rebase uses repeated merging to graft changesets from one part of history | 44 Rebase uses repeated merging to graft changesets from one part of history |
114 | 133 |
115 def concludenode(repo, rev, p1, p2, state, collapse, last=False, skipped={}): | 134 def concludenode(repo, rev, p1, p2, state, collapse, last=False, skipped={}): |
116 """Skip commit if collapsing has been required and rev is not the last | 135 """Skip commit if collapsing has been required and rev is not the last |
117 revision, commit otherwise | 136 revision, commit otherwise |
118 """ | 137 """ |
138 repo.ui.debug(_(" set parents\n")) | |
139 if collapse and not last: | |
140 repo.dirstate.setparents(repo[p1].node()) | |
141 return None | |
142 | |
119 repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) | 143 repo.dirstate.setparents(repo[p1].node(), repo[p2].node()) |
120 | |
121 if collapse and not last: | |
122 return None | |
123 | 144 |
124 # Commit, record the old nodeid | 145 # Commit, record the old nodeid |
125 m, a, r = repo.status()[:3] | 146 m, a, r = repo.status()[:3] |
126 newrev = nullrev | 147 newrev = nullrev |
127 try: | 148 try: |
145 repo.dirstate.invalidate() | 166 repo.dirstate.invalidate() |
146 raise | 167 raise |
147 | 168 |
148 def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse): | 169 def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse): |
149 'Rebase a single revision' | 170 'Rebase a single revision' |
150 repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev].node())) | 171 repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev])) |
151 | 172 |
152 p1, p2 = defineparents(repo, rev, target, state, targetancestors) | 173 p1, p2 = defineparents(repo, rev, target, state, targetancestors) |
153 | 174 |
175 repo.ui.debug(_(" future parents are %d and %d\n") % (repo[p1].rev(), | |
176 repo[p2].rev())) | |
177 | |
154 # Merge phase | 178 # Merge phase |
155 if len(repo.parents()) != 2: | 179 if len(repo.parents()) != 2: |
156 # Update to target and merge it with local | 180 # Update to target and merge it with local |
157 merge.update(repo, p1, False, True, False) | 181 if repo['.'].rev() != repo[p1].rev(): |
182 repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1])) | |
183 merge.update(repo, p1, False, True, False) | |
184 else: | |
185 repo.ui.debug(_(" already in target\n")) | |
158 repo.dirstate.write() | 186 repo.dirstate.write() |
159 stats = merge.update(repo, rev, True, False, False) | 187 repo.ui.debug(_(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev])) |
188 first = repo[rev].rev() == repo[min(state)].rev() | |
189 stats = rebasemerge(repo, rev, first) | |
160 | 190 |
161 if stats[3] > 0: | 191 if stats[3] > 0: |
162 raise util.Abort(_('fix unresolved conflicts with hg resolve then ' | 192 raise util.Abort(_('fix unresolved conflicts with hg resolve then ' |
163 'run hg rebase --continue')) | 193 'run hg rebase --continue')) |
164 else: # we have an interrupted rebase | 194 else: # we have an interrupted rebase |