##// END OF EJS Templates
rebase: stress that only local changesets should be rebased
Martin Geisler -
r11188:b5c0f6a1 stable
parent child Browse files
Show More
@@ -1,541 +1,546 b''
1 # rebase.py - rebasing feature for mercurial
1 # rebase.py - rebasing feature for mercurial
2 #
2 #
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to move sets of revisions to a different ancestor
8 '''command to move sets of revisions to a different ancestor
9
9
10 This extension lets you rebase changesets in an existing Mercurial
10 This extension lets you rebase changesets in an existing Mercurial
11 repository.
11 repository.
12
12
13 For more information:
13 For more information:
14 http://mercurial.selenic.com/wiki/RebaseExtension
14 http://mercurial.selenic.com/wiki/RebaseExtension
15 '''
15 '''
16
16
17 from mercurial import util, repair, merge, cmdutil, commands, error
17 from mercurial import util, repair, merge, cmdutil, commands, error
18 from mercurial import extensions, ancestor, copies, patch
18 from mercurial import extensions, ancestor, copies, patch
19 from mercurial.commands import templateopts
19 from mercurial.commands import templateopts
20 from mercurial.node import nullrev
20 from mercurial.node import nullrev
21 from mercurial.lock import release
21 from mercurial.lock import release
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 import os, errno
23 import os, errno
24
24
25 nullmerge = -2
25 nullmerge = -2
26
26
27 def rebase(ui, repo, **opts):
27 def rebase(ui, repo, **opts):
28 """move changeset (and descendants) to a different branch
28 """move changeset (and descendants) to a different branch
29
29
30 Rebase uses repeated merging to graft changesets from one part of
30 Rebase uses repeated merging to graft changesets from one part of
31 history (the source) onto another (the destination). This can be
31 history (the source) onto another (the destination). This can be
32 useful for linearizing local changes relative to a master
32 useful for linearizing *local* changes relative to a master
33 development tree.
33 development tree.
34
34
35 You should not rebase changesets that have already been shared
36 with others. Doing so will force everybody else to perform the
37 same rebase or they will end up with duplicated changesets after
38 pulling in your rebased changesets.
39
35 If you don't specify a destination changeset (``-d/--dest``),
40 If you don't specify a destination changeset (``-d/--dest``),
36 rebase uses the tipmost head of the current named branch as the
41 rebase uses the tipmost head of the current named branch as the
37 destination. (The destination changeset is not modified by
42 destination. (The destination changeset is not modified by
38 rebasing, but new changesets are added as its descendants.)
43 rebasing, but new changesets are added as its descendants.)
39
44
40 You can specify which changesets to rebase in two ways: as a
45 You can specify which changesets to rebase in two ways: as a
41 "source" changeset or as a "base" changeset. Both are shorthand
46 "source" changeset or as a "base" changeset. Both are shorthand
42 for a topologically related set of changesets (the "source
47 for a topologically related set of changesets (the "source
43 branch"). If you specify source (``-s/--source``), rebase will
48 branch"). If you specify source (``-s/--source``), rebase will
44 rebase that changeset and all of its descendants onto dest. If you
49 rebase that changeset and all of its descendants onto dest. If you
45 specify base (``-b/--base``), rebase will select ancestors of base
50 specify base (``-b/--base``), rebase will select ancestors of base
46 back to but not including the common ancestor with dest. Thus,
51 back to but not including the common ancestor with dest. Thus,
47 ``-b`` is less precise but more convenient than ``-s``: you can
52 ``-b`` is less precise but more convenient than ``-s``: you can
48 specify any changeset in the source branch, and rebase will select
53 specify any changeset in the source branch, and rebase will select
49 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
54 the whole branch. If you specify neither ``-s`` nor ``-b``, rebase
50 uses the parent of the working directory as the base.
55 uses the parent of the working directory as the base.
51
56
52 By default, rebase recreates the changesets in the source branch
57 By default, rebase recreates the changesets in the source branch
53 as descendants of dest and then destroys the originals. Use
58 as descendants of dest and then destroys the originals. Use
54 ``--keep`` to preserve the original source changesets. Some
59 ``--keep`` to preserve the original source changesets. Some
55 changesets in the source branch (e.g. merges from the destination
60 changesets in the source branch (e.g. merges from the destination
56 branch) may be dropped if they no longer contribute any change.
61 branch) may be dropped if they no longer contribute any change.
57
62
58 One result of the rules for selecting the destination changeset
63 One result of the rules for selecting the destination changeset
59 and source branch is that, unlike ``merge``, rebase will do
64 and source branch is that, unlike ``merge``, rebase will do
60 nothing if you are at the latest (tipmost) head of a named branch
65 nothing if you are at the latest (tipmost) head of a named branch
61 with two heads. You need to explicitly specify source and/or
66 with two heads. You need to explicitly specify source and/or
62 destination (or ``update`` to the other head, if it's the head of
67 destination (or ``update`` to the other head, if it's the head of
63 the intended source branch).
68 the intended source branch).
64
69
65 If a rebase is interrupted to manually resolve a merge, it can be
70 If a rebase is interrupted to manually resolve a merge, it can be
66 continued with --continue/-c or aborted with --abort/-a.
71 continued with --continue/-c or aborted with --abort/-a.
67 """
72 """
68 originalwd = target = None
73 originalwd = target = None
69 external = nullrev
74 external = nullrev
70 state = {}
75 state = {}
71 skipped = set()
76 skipped = set()
72 targetancestors = set()
77 targetancestors = set()
73
78
74 lock = wlock = None
79 lock = wlock = None
75 try:
80 try:
76 lock = repo.lock()
81 lock = repo.lock()
77 wlock = repo.wlock()
82 wlock = repo.wlock()
78
83
79 # Validate input and define rebasing points
84 # Validate input and define rebasing points
80 destf = opts.get('dest', None)
85 destf = opts.get('dest', None)
81 srcf = opts.get('source', None)
86 srcf = opts.get('source', None)
82 basef = opts.get('base', None)
87 basef = opts.get('base', None)
83 contf = opts.get('continue')
88 contf = opts.get('continue')
84 abortf = opts.get('abort')
89 abortf = opts.get('abort')
85 collapsef = opts.get('collapse', False)
90 collapsef = opts.get('collapse', False)
86 extrafn = opts.get('extrafn')
91 extrafn = opts.get('extrafn')
87 keepf = opts.get('keep', False)
92 keepf = opts.get('keep', False)
88 keepbranchesf = opts.get('keepbranches', False)
93 keepbranchesf = opts.get('keepbranches', False)
89 detachf = opts.get('detach', False)
94 detachf = opts.get('detach', False)
90
95
91 if contf or abortf:
96 if contf or abortf:
92 if contf and abortf:
97 if contf and abortf:
93 raise error.ParseError('rebase',
98 raise error.ParseError('rebase',
94 _('cannot use both abort and continue'))
99 _('cannot use both abort and continue'))
95 if collapsef:
100 if collapsef:
96 raise error.ParseError(
101 raise error.ParseError(
97 'rebase', _('cannot use collapse with continue or abort'))
102 'rebase', _('cannot use collapse with continue or abort'))
98
103
99 if detachf:
104 if detachf:
100 raise error.ParseError(
105 raise error.ParseError(
101 'rebase', _('cannot use detach with continue or abort'))
106 'rebase', _('cannot use detach with continue or abort'))
102
107
103 if srcf or basef or destf:
108 if srcf or basef or destf:
104 raise error.ParseError('rebase',
109 raise error.ParseError('rebase',
105 _('abort and continue do not allow specifying revisions'))
110 _('abort and continue do not allow specifying revisions'))
106
111
107 (originalwd, target, state, collapsef, keepf,
112 (originalwd, target, state, collapsef, keepf,
108 keepbranchesf, external) = restorestatus(repo)
113 keepbranchesf, external) = restorestatus(repo)
109 if abortf:
114 if abortf:
110 abort(repo, originalwd, target, state)
115 abort(repo, originalwd, target, state)
111 return
116 return
112 else:
117 else:
113 if srcf and basef:
118 if srcf and basef:
114 raise error.ParseError('rebase', _('cannot specify both a '
119 raise error.ParseError('rebase', _('cannot specify both a '
115 'revision and a base'))
120 'revision and a base'))
116 if detachf:
121 if detachf:
117 if not srcf:
122 if not srcf:
118 raise error.ParseError(
123 raise error.ParseError(
119 'rebase', _('detach requires a revision to be specified'))
124 'rebase', _('detach requires a revision to be specified'))
120 if basef:
125 if basef:
121 raise error.ParseError(
126 raise error.ParseError(
122 'rebase', _('cannot specify a base with detach'))
127 'rebase', _('cannot specify a base with detach'))
123
128
124 cmdutil.bail_if_changed(repo)
129 cmdutil.bail_if_changed(repo)
125 result = buildstate(repo, destf, srcf, basef, detachf)
130 result = buildstate(repo, destf, srcf, basef, detachf)
126 if not result:
131 if not result:
127 # Empty state built, nothing to rebase
132 # Empty state built, nothing to rebase
128 ui.status(_('nothing to rebase\n'))
133 ui.status(_('nothing to rebase\n'))
129 return
134 return
130 else:
135 else:
131 originalwd, target, state = result
136 originalwd, target, state = result
132 if collapsef:
137 if collapsef:
133 targetancestors = set(repo.changelog.ancestors(target))
138 targetancestors = set(repo.changelog.ancestors(target))
134 external = checkexternal(repo, state, targetancestors)
139 external = checkexternal(repo, state, targetancestors)
135
140
136 if keepbranchesf:
141 if keepbranchesf:
137 if extrafn:
142 if extrafn:
138 raise error.ParseError(
143 raise error.ParseError(
139 'rebase', _('cannot use both keepbranches and extrafn'))
144 'rebase', _('cannot use both keepbranches and extrafn'))
140 def extrafn(ctx, extra):
145 def extrafn(ctx, extra):
141 extra['branch'] = ctx.branch()
146 extra['branch'] = ctx.branch()
142
147
143 # Rebase
148 # Rebase
144 if not targetancestors:
149 if not targetancestors:
145 targetancestors = set(repo.changelog.ancestors(target))
150 targetancestors = set(repo.changelog.ancestors(target))
146 targetancestors.add(target)
151 targetancestors.add(target)
147
152
148 for rev in sorted(state):
153 for rev in sorted(state):
149 if state[rev] == -1:
154 if state[rev] == -1:
150 ui.debug("rebasing %d:%s\n" % (rev, repo[rev]))
155 ui.debug("rebasing %d:%s\n" % (rev, repo[rev]))
151 storestatus(repo, originalwd, target, state, collapsef, keepf,
156 storestatus(repo, originalwd, target, state, collapsef, keepf,
152 keepbranchesf, external)
157 keepbranchesf, external)
153 p1, p2 = defineparents(repo, rev, target, state,
158 p1, p2 = defineparents(repo, rev, target, state,
154 targetancestors)
159 targetancestors)
155 if len(repo.parents()) == 2:
160 if len(repo.parents()) == 2:
156 repo.ui.debug('resuming interrupted rebase\n')
161 repo.ui.debug('resuming interrupted rebase\n')
157 else:
162 else:
158 stats = rebasenode(repo, rev, p1, p2, state)
163 stats = rebasenode(repo, rev, p1, p2, state)
159 if stats and stats[3] > 0:
164 if stats and stats[3] > 0:
160 raise util.Abort(_('fix unresolved conflicts with hg '
165 raise util.Abort(_('fix unresolved conflicts with hg '
161 'resolve then run hg rebase --continue'))
166 'resolve then run hg rebase --continue'))
162 updatedirstate(repo, rev, target, p2)
167 updatedirstate(repo, rev, target, p2)
163 if not collapsef:
168 if not collapsef:
164 newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn)
169 newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn)
165 else:
170 else:
166 # Skip commit if we are collapsing
171 # Skip commit if we are collapsing
167 repo.dirstate.setparents(repo[p1].node())
172 repo.dirstate.setparents(repo[p1].node())
168 newrev = None
173 newrev = None
169 # Update the state
174 # Update the state
170 if newrev is not None:
175 if newrev is not None:
171 state[rev] = repo[newrev].rev()
176 state[rev] = repo[newrev].rev()
172 else:
177 else:
173 if not collapsef:
178 if not collapsef:
174 ui.note(_('no changes, revision %d skipped\n') % rev)
179 ui.note(_('no changes, revision %d skipped\n') % rev)
175 ui.debug('next revision set to %s\n' % p1)
180 ui.debug('next revision set to %s\n' % p1)
176 skipped.add(rev)
181 skipped.add(rev)
177 state[rev] = p1
182 state[rev] = p1
178
183
179 ui.note(_('rebase merging completed\n'))
184 ui.note(_('rebase merging completed\n'))
180
185
181 if collapsef:
186 if collapsef:
182 p1, p2 = defineparents(repo, min(state), target,
187 p1, p2 = defineparents(repo, min(state), target,
183 state, targetancestors)
188 state, targetancestors)
184 commitmsg = 'Collapsed revision'
189 commitmsg = 'Collapsed revision'
185 for rebased in state:
190 for rebased in state:
186 if rebased not in skipped and state[rebased] != nullmerge:
191 if rebased not in skipped and state[rebased] != nullmerge:
187 commitmsg += '\n* %s' % repo[rebased].description()
192 commitmsg += '\n* %s' % repo[rebased].description()
188 commitmsg = ui.edit(commitmsg, repo.ui.username())
193 commitmsg = ui.edit(commitmsg, repo.ui.username())
189 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
194 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
190 extrafn=extrafn)
195 extrafn=extrafn)
191
196
192 if 'qtip' in repo.tags():
197 if 'qtip' in repo.tags():
193 updatemq(repo, state, skipped, **opts)
198 updatemq(repo, state, skipped, **opts)
194
199
195 if not keepf:
200 if not keepf:
196 # Remove no more useful revisions
201 # Remove no more useful revisions
197 rebased = [rev for rev in state if state[rev] != nullmerge]
202 rebased = [rev for rev in state if state[rev] != nullmerge]
198 if rebased:
203 if rebased:
199 if set(repo.changelog.descendants(min(rebased))) - set(state):
204 if set(repo.changelog.descendants(min(rebased))) - set(state):
200 ui.warn(_("warning: new changesets detected "
205 ui.warn(_("warning: new changesets detected "
201 "on source branch, not stripping\n"))
206 "on source branch, not stripping\n"))
202 else:
207 else:
203 repair.strip(ui, repo, repo[min(rebased)].node(), "strip")
208 repair.strip(ui, repo, repo[min(rebased)].node(), "strip")
204
209
205 clearstatus(repo)
210 clearstatus(repo)
206 ui.status(_("rebase completed\n"))
211 ui.status(_("rebase completed\n"))
207 if os.path.exists(repo.sjoin('undo')):
212 if os.path.exists(repo.sjoin('undo')):
208 util.unlink(repo.sjoin('undo'))
213 util.unlink(repo.sjoin('undo'))
209 if skipped:
214 if skipped:
210 ui.note(_("%d revisions have been skipped\n") % len(skipped))
215 ui.note(_("%d revisions have been skipped\n") % len(skipped))
211 finally:
216 finally:
212 release(lock, wlock)
217 release(lock, wlock)
213
218
214 def rebasemerge(repo, rev, first=False):
219 def rebasemerge(repo, rev, first=False):
215 'return the correct ancestor'
220 'return the correct ancestor'
216 oldancestor = ancestor.ancestor
221 oldancestor = ancestor.ancestor
217
222
218 def newancestor(a, b, pfunc):
223 def newancestor(a, b, pfunc):
219 if b == rev:
224 if b == rev:
220 return repo[rev].parents()[0].rev()
225 return repo[rev].parents()[0].rev()
221 return oldancestor(a, b, pfunc)
226 return oldancestor(a, b, pfunc)
222
227
223 if not first:
228 if not first:
224 ancestor.ancestor = newancestor
229 ancestor.ancestor = newancestor
225 else:
230 else:
226 repo.ui.debug("first revision, do not change ancestor\n")
231 repo.ui.debug("first revision, do not change ancestor\n")
227 try:
232 try:
228 stats = merge.update(repo, rev, True, True, False)
233 stats = merge.update(repo, rev, True, True, False)
229 return stats
234 return stats
230 finally:
235 finally:
231 ancestor.ancestor = oldancestor
236 ancestor.ancestor = oldancestor
232
237
233 def checkexternal(repo, state, targetancestors):
238 def checkexternal(repo, state, targetancestors):
234 """Check whether one or more external revisions need to be taken in
239 """Check whether one or more external revisions need to be taken in
235 consideration. In the latter case, abort.
240 consideration. In the latter case, abort.
236 """
241 """
237 external = nullrev
242 external = nullrev
238 source = min(state)
243 source = min(state)
239 for rev in state:
244 for rev in state:
240 if rev == source:
245 if rev == source:
241 continue
246 continue
242 # Check externals and fail if there are more than one
247 # Check externals and fail if there are more than one
243 for p in repo[rev].parents():
248 for p in repo[rev].parents():
244 if (p.rev() not in state
249 if (p.rev() not in state
245 and p.rev() not in targetancestors):
250 and p.rev() not in targetancestors):
246 if external != nullrev:
251 if external != nullrev:
247 raise util.Abort(_('unable to collapse, there is more '
252 raise util.Abort(_('unable to collapse, there is more '
248 'than one external parent'))
253 'than one external parent'))
249 external = p.rev()
254 external = p.rev()
250 return external
255 return external
251
256
252 def updatedirstate(repo, rev, p1, p2):
257 def updatedirstate(repo, rev, p1, p2):
253 """Keep track of renamed files in the revision that is going to be rebased
258 """Keep track of renamed files in the revision that is going to be rebased
254 """
259 """
255 # Here we simulate the copies and renames in the source changeset
260 # Here we simulate the copies and renames in the source changeset
256 cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
261 cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
257 m1 = repo[rev].manifest()
262 m1 = repo[rev].manifest()
258 m2 = repo[p1].manifest()
263 m2 = repo[p1].manifest()
259 for k, v in cop.iteritems():
264 for k, v in cop.iteritems():
260 if k in m1:
265 if k in m1:
261 if v in m1 or v in m2:
266 if v in m1 or v in m2:
262 repo.dirstate.copy(v, k)
267 repo.dirstate.copy(v, k)
263 if v in m2 and v not in m1:
268 if v in m2 and v not in m1:
264 repo.dirstate.remove(v)
269 repo.dirstate.remove(v)
265
270
266 def concludenode(repo, rev, p1, p2, commitmsg=None, extrafn=None):
271 def concludenode(repo, rev, p1, p2, commitmsg=None, extrafn=None):
267 'Commit the changes and store useful information in extra'
272 'Commit the changes and store useful information in extra'
268 try:
273 try:
269 repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
274 repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
270 if commitmsg is None:
275 if commitmsg is None:
271 commitmsg = repo[rev].description()
276 commitmsg = repo[rev].description()
272 ctx = repo[rev]
277 ctx = repo[rev]
273 extra = {'rebase_source': ctx.hex()}
278 extra = {'rebase_source': ctx.hex()}
274 if extrafn:
279 if extrafn:
275 extrafn(ctx, extra)
280 extrafn(ctx, extra)
276 # Commit might fail if unresolved files exist
281 # Commit might fail if unresolved files exist
277 newrev = repo.commit(text=commitmsg, user=ctx.user(),
282 newrev = repo.commit(text=commitmsg, user=ctx.user(),
278 date=ctx.date(), extra=extra)
283 date=ctx.date(), extra=extra)
279 repo.dirstate.setbranch(repo[newrev].branch())
284 repo.dirstate.setbranch(repo[newrev].branch())
280 return newrev
285 return newrev
281 except util.Abort:
286 except util.Abort:
282 # Invalidate the previous setparents
287 # Invalidate the previous setparents
283 repo.dirstate.invalidate()
288 repo.dirstate.invalidate()
284 raise
289 raise
285
290
286 def rebasenode(repo, rev, p1, p2, state):
291 def rebasenode(repo, rev, p1, p2, state):
287 'Rebase a single revision'
292 'Rebase a single revision'
288 # Merge phase
293 # Merge phase
289 # Update to target and merge it with local
294 # Update to target and merge it with local
290 if repo['.'].rev() != repo[p1].rev():
295 if repo['.'].rev() != repo[p1].rev():
291 repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
296 repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
292 merge.update(repo, p1, False, True, False)
297 merge.update(repo, p1, False, True, False)
293 else:
298 else:
294 repo.ui.debug(" already in target\n")
299 repo.ui.debug(" already in target\n")
295 repo.dirstate.write()
300 repo.dirstate.write()
296 repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
301 repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
297 first = repo[rev].rev() == repo[min(state)].rev()
302 first = repo[rev].rev() == repo[min(state)].rev()
298 stats = rebasemerge(repo, rev, first)
303 stats = rebasemerge(repo, rev, first)
299 return stats
304 return stats
300
305
301 def defineparents(repo, rev, target, state, targetancestors):
306 def defineparents(repo, rev, target, state, targetancestors):
302 'Return the new parent relationship of the revision that will be rebased'
307 'Return the new parent relationship of the revision that will be rebased'
303 parents = repo[rev].parents()
308 parents = repo[rev].parents()
304 p1 = p2 = nullrev
309 p1 = p2 = nullrev
305
310
306 P1n = parents[0].rev()
311 P1n = parents[0].rev()
307 if P1n in targetancestors:
312 if P1n in targetancestors:
308 p1 = target
313 p1 = target
309 elif P1n in state:
314 elif P1n in state:
310 if state[P1n] == nullmerge:
315 if state[P1n] == nullmerge:
311 p1 = target
316 p1 = target
312 else:
317 else:
313 p1 = state[P1n]
318 p1 = state[P1n]
314 else: # P1n external
319 else: # P1n external
315 p1 = target
320 p1 = target
316 p2 = P1n
321 p2 = P1n
317
322
318 if len(parents) == 2 and parents[1].rev() not in targetancestors:
323 if len(parents) == 2 and parents[1].rev() not in targetancestors:
319 P2n = parents[1].rev()
324 P2n = parents[1].rev()
320 # interesting second parent
325 # interesting second parent
321 if P2n in state:
326 if P2n in state:
322 if p1 == target: # P1n in targetancestors or external
327 if p1 == target: # P1n in targetancestors or external
323 p1 = state[P2n]
328 p1 = state[P2n]
324 else:
329 else:
325 p2 = state[P2n]
330 p2 = state[P2n]
326 else: # P2n external
331 else: # P2n external
327 if p2 != nullrev: # P1n external too => rev is a merged revision
332 if p2 != nullrev: # P1n external too => rev is a merged revision
328 raise util.Abort(_('cannot use revision %d as base, result '
333 raise util.Abort(_('cannot use revision %d as base, result '
329 'would have 3 parents') % rev)
334 'would have 3 parents') % rev)
330 p2 = P2n
335 p2 = P2n
331 repo.ui.debug(" future parents are %d and %d\n" %
336 repo.ui.debug(" future parents are %d and %d\n" %
332 (repo[p1].rev(), repo[p2].rev()))
337 (repo[p1].rev(), repo[p2].rev()))
333 return p1, p2
338 return p1, p2
334
339
335 def isagitpatch(repo, patchname):
340 def isagitpatch(repo, patchname):
336 'Return true if the given patch is in git format'
341 'Return true if the given patch is in git format'
337 mqpatch = os.path.join(repo.mq.path, patchname)
342 mqpatch = os.path.join(repo.mq.path, patchname)
338 for line in patch.linereader(file(mqpatch, 'rb')):
343 for line in patch.linereader(file(mqpatch, 'rb')):
339 if line.startswith('diff --git'):
344 if line.startswith('diff --git'):
340 return True
345 return True
341 return False
346 return False
342
347
343 def updatemq(repo, state, skipped, **opts):
348 def updatemq(repo, state, skipped, **opts):
344 'Update rebased mq patches - finalize and then import them'
349 'Update rebased mq patches - finalize and then import them'
345 mqrebase = {}
350 mqrebase = {}
346 for p in repo.mq.applied:
351 for p in repo.mq.applied:
347 if repo[p.rev].rev() in state:
352 if repo[p.rev].rev() in state:
348 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
353 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
349 (repo[p.rev].rev(), p.name))
354 (repo[p.rev].rev(), p.name))
350 mqrebase[repo[p.rev].rev()] = (p.name, isagitpatch(repo, p.name))
355 mqrebase[repo[p.rev].rev()] = (p.name, isagitpatch(repo, p.name))
351
356
352 if mqrebase:
357 if mqrebase:
353 repo.mq.finish(repo, mqrebase.keys())
358 repo.mq.finish(repo, mqrebase.keys())
354
359
355 # We must start import from the newest revision
360 # We must start import from the newest revision
356 for rev in sorted(mqrebase, reverse=True):
361 for rev in sorted(mqrebase, reverse=True):
357 if rev not in skipped:
362 if rev not in skipped:
358 repo.ui.debug('import mq patch %d (%s)\n'
363 repo.ui.debug('import mq patch %d (%s)\n'
359 % (state[rev], mqrebase[rev][0]))
364 % (state[rev], mqrebase[rev][0]))
360 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
365 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
361 git=mqrebase[rev][1],rev=[str(state[rev])])
366 git=mqrebase[rev][1],rev=[str(state[rev])])
362 repo.mq.save_dirty()
367 repo.mq.save_dirty()
363
368
364 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
369 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
365 external):
370 external):
366 'Store the current status to allow recovery'
371 'Store the current status to allow recovery'
367 f = repo.opener("rebasestate", "w")
372 f = repo.opener("rebasestate", "w")
368 f.write(repo[originalwd].hex() + '\n')
373 f.write(repo[originalwd].hex() + '\n')
369 f.write(repo[target].hex() + '\n')
374 f.write(repo[target].hex() + '\n')
370 f.write(repo[external].hex() + '\n')
375 f.write(repo[external].hex() + '\n')
371 f.write('%d\n' % int(collapse))
376 f.write('%d\n' % int(collapse))
372 f.write('%d\n' % int(keep))
377 f.write('%d\n' % int(keep))
373 f.write('%d\n' % int(keepbranches))
378 f.write('%d\n' % int(keepbranches))
374 for d, v in state.iteritems():
379 for d, v in state.iteritems():
375 oldrev = repo[d].hex()
380 oldrev = repo[d].hex()
376 newrev = repo[v].hex()
381 newrev = repo[v].hex()
377 f.write("%s:%s\n" % (oldrev, newrev))
382 f.write("%s:%s\n" % (oldrev, newrev))
378 f.close()
383 f.close()
379 repo.ui.debug('rebase status stored\n')
384 repo.ui.debug('rebase status stored\n')
380
385
381 def clearstatus(repo):
386 def clearstatus(repo):
382 'Remove the status files'
387 'Remove the status files'
383 if os.path.exists(repo.join("rebasestate")):
388 if os.path.exists(repo.join("rebasestate")):
384 util.unlink(repo.join("rebasestate"))
389 util.unlink(repo.join("rebasestate"))
385
390
386 def restorestatus(repo):
391 def restorestatus(repo):
387 'Restore a previously stored status'
392 'Restore a previously stored status'
388 try:
393 try:
389 target = None
394 target = None
390 collapse = False
395 collapse = False
391 external = nullrev
396 external = nullrev
392 state = {}
397 state = {}
393 f = repo.opener("rebasestate")
398 f = repo.opener("rebasestate")
394 for i, l in enumerate(f.read().splitlines()):
399 for i, l in enumerate(f.read().splitlines()):
395 if i == 0:
400 if i == 0:
396 originalwd = repo[l].rev()
401 originalwd = repo[l].rev()
397 elif i == 1:
402 elif i == 1:
398 target = repo[l].rev()
403 target = repo[l].rev()
399 elif i == 2:
404 elif i == 2:
400 external = repo[l].rev()
405 external = repo[l].rev()
401 elif i == 3:
406 elif i == 3:
402 collapse = bool(int(l))
407 collapse = bool(int(l))
403 elif i == 4:
408 elif i == 4:
404 keep = bool(int(l))
409 keep = bool(int(l))
405 elif i == 5:
410 elif i == 5:
406 keepbranches = bool(int(l))
411 keepbranches = bool(int(l))
407 else:
412 else:
408 oldrev, newrev = l.split(':')
413 oldrev, newrev = l.split(':')
409 state[repo[oldrev].rev()] = repo[newrev].rev()
414 state[repo[oldrev].rev()] = repo[newrev].rev()
410 repo.ui.debug('rebase status resumed\n')
415 repo.ui.debug('rebase status resumed\n')
411 return originalwd, target, state, collapse, keep, keepbranches, external
416 return originalwd, target, state, collapse, keep, keepbranches, external
412 except IOError, err:
417 except IOError, err:
413 if err.errno != errno.ENOENT:
418 if err.errno != errno.ENOENT:
414 raise
419 raise
415 raise util.Abort(_('no rebase in progress'))
420 raise util.Abort(_('no rebase in progress'))
416
421
417 def abort(repo, originalwd, target, state):
422 def abort(repo, originalwd, target, state):
418 'Restore the repository to its original state'
423 'Restore the repository to its original state'
419 if set(repo.changelog.descendants(target)) - set(state.values()):
424 if set(repo.changelog.descendants(target)) - set(state.values()):
420 repo.ui.warn(_("warning: new changesets detected on target branch, "
425 repo.ui.warn(_("warning: new changesets detected on target branch, "
421 "not stripping\n"))
426 "not stripping\n"))
422 else:
427 else:
423 # Strip from the first rebased revision
428 # Strip from the first rebased revision
424 merge.update(repo, repo[originalwd].rev(), False, True, False)
429 merge.update(repo, repo[originalwd].rev(), False, True, False)
425 rebased = filter(lambda x: x > -1, state.values())
430 rebased = filter(lambda x: x > -1, state.values())
426 if rebased:
431 if rebased:
427 strippoint = min(rebased)
432 strippoint = min(rebased)
428 repair.strip(repo.ui, repo, repo[strippoint].node(), "strip")
433 repair.strip(repo.ui, repo, repo[strippoint].node(), "strip")
429 clearstatus(repo)
434 clearstatus(repo)
430 repo.ui.status(_('rebase aborted\n'))
435 repo.ui.status(_('rebase aborted\n'))
431
436
432 def buildstate(repo, dest, src, base, detach):
437 def buildstate(repo, dest, src, base, detach):
433 'Define which revisions are going to be rebased and where'
438 'Define which revisions are going to be rebased and where'
434 targetancestors = set()
439 targetancestors = set()
435 detachset = set()
440 detachset = set()
436
441
437 if not dest:
442 if not dest:
438 # Destination defaults to the latest revision in the current branch
443 # Destination defaults to the latest revision in the current branch
439 branch = repo[None].branch()
444 branch = repo[None].branch()
440 dest = repo[branch].rev()
445 dest = repo[branch].rev()
441 else:
446 else:
442 dest = repo[dest].rev()
447 dest = repo[dest].rev()
443
448
444 # This check isn't strictly necessary, since mq detects commits over an
449 # This check isn't strictly necessary, since mq detects commits over an
445 # applied patch. But it prevents messing up the working directory when
450 # applied patch. But it prevents messing up the working directory when
446 # a partially completed rebase is blocked by mq.
451 # a partially completed rebase is blocked by mq.
447 if 'qtip' in repo.tags() and (repo[dest].hex() in
452 if 'qtip' in repo.tags() and (repo[dest].hex() in
448 [s.rev for s in repo.mq.applied]):
453 [s.rev for s in repo.mq.applied]):
449 raise util.Abort(_('cannot rebase onto an applied mq patch'))
454 raise util.Abort(_('cannot rebase onto an applied mq patch'))
450
455
451 if src:
456 if src:
452 commonbase = repo[src].ancestor(repo[dest])
457 commonbase = repo[src].ancestor(repo[dest])
453 if commonbase == repo[src]:
458 if commonbase == repo[src]:
454 raise util.Abort(_('source is ancestor of destination'))
459 raise util.Abort(_('source is ancestor of destination'))
455 if commonbase == repo[dest]:
460 if commonbase == repo[dest]:
456 raise util.Abort(_('source is descendant of destination'))
461 raise util.Abort(_('source is descendant of destination'))
457 source = repo[src].rev()
462 source = repo[src].rev()
458 if detach:
463 if detach:
459 # We need to keep track of source's ancestors up to the common base
464 # We need to keep track of source's ancestors up to the common base
460 srcancestors = set(repo.changelog.ancestors(source))
465 srcancestors = set(repo.changelog.ancestors(source))
461 baseancestors = set(repo.changelog.ancestors(commonbase.rev()))
466 baseancestors = set(repo.changelog.ancestors(commonbase.rev()))
462 detachset = srcancestors - baseancestors
467 detachset = srcancestors - baseancestors
463 detachset.remove(commonbase.rev())
468 detachset.remove(commonbase.rev())
464 else:
469 else:
465 if base:
470 if base:
466 cwd = repo[base].rev()
471 cwd = repo[base].rev()
467 else:
472 else:
468 cwd = repo['.'].rev()
473 cwd = repo['.'].rev()
469
474
470 if cwd == dest:
475 if cwd == dest:
471 repo.ui.debug('source and destination are the same\n')
476 repo.ui.debug('source and destination are the same\n')
472 return None
477 return None
473
478
474 targetancestors = set(repo.changelog.ancestors(dest))
479 targetancestors = set(repo.changelog.ancestors(dest))
475 if cwd in targetancestors:
480 if cwd in targetancestors:
476 repo.ui.debug('source is ancestor of destination\n')
481 repo.ui.debug('source is ancestor of destination\n')
477 return None
482 return None
478
483
479 cwdancestors = set(repo.changelog.ancestors(cwd))
484 cwdancestors = set(repo.changelog.ancestors(cwd))
480 if dest in cwdancestors:
485 if dest in cwdancestors:
481 repo.ui.debug('source is descendant of destination\n')
486 repo.ui.debug('source is descendant of destination\n')
482 return None
487 return None
483
488
484 cwdancestors.add(cwd)
489 cwdancestors.add(cwd)
485 rebasingbranch = cwdancestors - targetancestors
490 rebasingbranch = cwdancestors - targetancestors
486 source = min(rebasingbranch)
491 source = min(rebasingbranch)
487
492
488 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
493 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
489 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
494 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
490 state.update(dict.fromkeys(detachset, nullmerge))
495 state.update(dict.fromkeys(detachset, nullmerge))
491 state[source] = nullrev
496 state[source] = nullrev
492 return repo['.'].rev(), repo[dest].rev(), state
497 return repo['.'].rev(), repo[dest].rev(), state
493
498
494 def pullrebase(orig, ui, repo, *args, **opts):
499 def pullrebase(orig, ui, repo, *args, **opts):
495 'Call rebase after pull if the latter has been invoked with --rebase'
500 'Call rebase after pull if the latter has been invoked with --rebase'
496 if opts.get('rebase'):
501 if opts.get('rebase'):
497 if opts.get('update'):
502 if opts.get('update'):
498 del opts['update']
503 del opts['update']
499 ui.debug('--update and --rebase are not compatible, ignoring '
504 ui.debug('--update and --rebase are not compatible, ignoring '
500 'the update flag\n')
505 'the update flag\n')
501
506
502 cmdutil.bail_if_changed(repo)
507 cmdutil.bail_if_changed(repo)
503 revsprepull = len(repo)
508 revsprepull = len(repo)
504 orig(ui, repo, *args, **opts)
509 orig(ui, repo, *args, **opts)
505 revspostpull = len(repo)
510 revspostpull = len(repo)
506 if revspostpull > revsprepull:
511 if revspostpull > revsprepull:
507 rebase(ui, repo, **opts)
512 rebase(ui, repo, **opts)
508 branch = repo[None].branch()
513 branch = repo[None].branch()
509 dest = repo[branch].rev()
514 dest = repo[branch].rev()
510 if dest != repo['.'].rev():
515 if dest != repo['.'].rev():
511 # there was nothing to rebase we force an update
516 # there was nothing to rebase we force an update
512 merge.update(repo, dest, False, False, False)
517 merge.update(repo, dest, False, False, False)
513 else:
518 else:
514 orig(ui, repo, *args, **opts)
519 orig(ui, repo, *args, **opts)
515
520
516 def uisetup(ui):
521 def uisetup(ui):
517 'Replace pull with a decorator to provide --rebase option'
522 'Replace pull with a decorator to provide --rebase option'
518 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
523 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
519 entry[1].append(('', 'rebase', None,
524 entry[1].append(('', 'rebase', None,
520 _("rebase working directory to branch head"))
525 _("rebase working directory to branch head"))
521 )
526 )
522
527
523 cmdtable = {
528 cmdtable = {
524 "rebase":
529 "rebase":
525 (rebase,
530 (rebase,
526 [
531 [
527 ('s', 'source', '', _('rebase from the specified changeset')),
532 ('s', 'source', '', _('rebase from the specified changeset')),
528 ('b', 'base', '', _('rebase from the base of the specified changeset '
533 ('b', 'base', '', _('rebase from the base of the specified changeset '
529 '(up to greatest common ancestor of base and dest)')),
534 '(up to greatest common ancestor of base and dest)')),
530 ('d', 'dest', '', _('rebase onto the specified changeset')),
535 ('d', 'dest', '', _('rebase onto the specified changeset')),
531 ('', 'collapse', False, _('collapse the rebased changesets')),
536 ('', 'collapse', False, _('collapse the rebased changesets')),
532 ('', 'keep', False, _('keep original changesets')),
537 ('', 'keep', False, _('keep original changesets')),
533 ('', 'keepbranches', False, _('keep original branch names')),
538 ('', 'keepbranches', False, _('keep original branch names')),
534 ('', 'detach', False, _('force detaching of source from its original '
539 ('', 'detach', False, _('force detaching of source from its original '
535 'branch')),
540 'branch')),
536 ('c', 'continue', False, _('continue an interrupted rebase')),
541 ('c', 'continue', False, _('continue an interrupted rebase')),
537 ('a', 'abort', False, _('abort an interrupted rebase'))] +
542 ('a', 'abort', False, _('abort an interrupted rebase'))] +
538 templateopts,
543 templateopts,
539 _('hg rebase [-s REV | -b REV] [-d REV] [options]\n'
544 _('hg rebase [-s REV | -b REV] [-d REV] [options]\n'
540 'hg rebase {-a|-c}'))
545 'hg rebase {-a|-c}'))
541 }
546 }
@@ -1,324 +1,344 b''
1 % These fail
1 % These fail
2
2
3 % Use continue and abort
3 % Use continue and abort
4 hg rebase: cannot use both abort and continue
4 hg rebase: cannot use both abort and continue
5 hg rebase [-s REV | -b REV] [-d REV] [options]
5 hg rebase [-s REV | -b REV] [-d REV] [options]
6 hg rebase {-a|-c}
6 hg rebase {-a|-c}
7
7
8 move changeset (and descendants) to a different branch
8 move changeset (and descendants) to a different branch
9
9
10 Rebase uses repeated merging to graft changesets from one part of history
10 Rebase uses repeated merging to graft changesets from one part of history
11 (the source) onto another (the destination). This can be useful for
11 (the source) onto another (the destination). This can be useful for
12 linearizing local changes relative to a master development tree.
12 linearizing *local* changes relative to a master development tree.
13
14 You should not rebase changesets that have already been shared with
15 others. Doing so will force everybody else to perform the same rebase or
16 they will end up with duplicated changesets after pulling in your rebased
17 changesets.
13
18
14 If you don't specify a destination changeset ("-d/--dest"), rebase uses
19 If you don't specify a destination changeset ("-d/--dest"), rebase uses
15 the tipmost head of the current named branch as the destination. (The
20 the tipmost head of the current named branch as the destination. (The
16 destination changeset is not modified by rebasing, but new changesets are
21 destination changeset is not modified by rebasing, but new changesets are
17 added as its descendants.)
22 added as its descendants.)
18
23
19 You can specify which changesets to rebase in two ways: as a "source"
24 You can specify which changesets to rebase in two ways: as a "source"
20 changeset or as a "base" changeset. Both are shorthand for a topologically
25 changeset or as a "base" changeset. Both are shorthand for a topologically
21 related set of changesets (the "source branch"). If you specify source
26 related set of changesets (the "source branch"). If you specify source
22 ("-s/--source"), rebase will rebase that changeset and all of its
27 ("-s/--source"), rebase will rebase that changeset and all of its
23 descendants onto dest. If you specify base ("-b/--base"), rebase will
28 descendants onto dest. If you specify base ("-b/--base"), rebase will
24 select ancestors of base back to but not including the common ancestor
29 select ancestors of base back to but not including the common ancestor
25 with dest. Thus, "-b" is less precise but more convenient than "-s": you
30 with dest. Thus, "-b" is less precise but more convenient than "-s": you
26 can specify any changeset in the source branch, and rebase will select the
31 can specify any changeset in the source branch, and rebase will select the
27 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
32 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
28 of the working directory as the base.
33 of the working directory as the base.
29
34
30 By default, rebase recreates the changesets in the source branch as
35 By default, rebase recreates the changesets in the source branch as
31 descendants of dest and then destroys the originals. Use "--keep" to
36 descendants of dest and then destroys the originals. Use "--keep" to
32 preserve the original source changesets. Some changesets in the source
37 preserve the original source changesets. Some changesets in the source
33 branch (e.g. merges from the destination branch) may be dropped if they no
38 branch (e.g. merges from the destination branch) may be dropped if they no
34 longer contribute any change.
39 longer contribute any change.
35
40
36 One result of the rules for selecting the destination changeset and source
41 One result of the rules for selecting the destination changeset and source
37 branch is that, unlike "merge", rebase will do nothing if you are at the
42 branch is that, unlike "merge", rebase will do nothing if you are at the
38 latest (tipmost) head of a named branch with two heads. You need to
43 latest (tipmost) head of a named branch with two heads. You need to
39 explicitly specify source and/or destination (or "update" to the other
44 explicitly specify source and/or destination (or "update" to the other
40 head, if it's the head of the intended source branch).
45 head, if it's the head of the intended source branch).
41
46
42 If a rebase is interrupted to manually resolve a merge, it can be
47 If a rebase is interrupted to manually resolve a merge, it can be
43 continued with --continue/-c or aborted with --abort/-a.
48 continued with --continue/-c or aborted with --abort/-a.
44
49
45 options:
50 options:
46
51
47 -s --source rebase from the specified changeset
52 -s --source rebase from the specified changeset
48 -b --base rebase from the base of the specified changeset (up to
53 -b --base rebase from the base of the specified changeset (up to
49 greatest common ancestor of base and dest)
54 greatest common ancestor of base and dest)
50 -d --dest rebase onto the specified changeset
55 -d --dest rebase onto the specified changeset
51 --collapse collapse the rebased changesets
56 --collapse collapse the rebased changesets
52 --keep keep original changesets
57 --keep keep original changesets
53 --keepbranches keep original branch names
58 --keepbranches keep original branch names
54 --detach force detaching of source from its original branch
59 --detach force detaching of source from its original branch
55 -c --continue continue an interrupted rebase
60 -c --continue continue an interrupted rebase
56 -a --abort abort an interrupted rebase
61 -a --abort abort an interrupted rebase
57 --style display using template map file
62 --style display using template map file
58 --template display with template
63 --template display with template
59
64
60 use "hg -v help rebase" to show global options
65 use "hg -v help rebase" to show global options
61
66
62 % Use continue and collapse
67 % Use continue and collapse
63 hg rebase: cannot use collapse with continue or abort
68 hg rebase: cannot use collapse with continue or abort
64 hg rebase [-s REV | -b REV] [-d REV] [options]
69 hg rebase [-s REV | -b REV] [-d REV] [options]
65 hg rebase {-a|-c}
70 hg rebase {-a|-c}
66
71
67 move changeset (and descendants) to a different branch
72 move changeset (and descendants) to a different branch
68
73
69 Rebase uses repeated merging to graft changesets from one part of history
74 Rebase uses repeated merging to graft changesets from one part of history
70 (the source) onto another (the destination). This can be useful for
75 (the source) onto another (the destination). This can be useful for
71 linearizing local changes relative to a master development tree.
76 linearizing *local* changes relative to a master development tree.
77
78 You should not rebase changesets that have already been shared with
79 others. Doing so will force everybody else to perform the same rebase or
80 they will end up with duplicated changesets after pulling in your rebased
81 changesets.
72
82
73 If you don't specify a destination changeset ("-d/--dest"), rebase uses
83 If you don't specify a destination changeset ("-d/--dest"), rebase uses
74 the tipmost head of the current named branch as the destination. (The
84 the tipmost head of the current named branch as the destination. (The
75 destination changeset is not modified by rebasing, but new changesets are
85 destination changeset is not modified by rebasing, but new changesets are
76 added as its descendants.)
86 added as its descendants.)
77
87
78 You can specify which changesets to rebase in two ways: as a "source"
88 You can specify which changesets to rebase in two ways: as a "source"
79 changeset or as a "base" changeset. Both are shorthand for a topologically
89 changeset or as a "base" changeset. Both are shorthand for a topologically
80 related set of changesets (the "source branch"). If you specify source
90 related set of changesets (the "source branch"). If you specify source
81 ("-s/--source"), rebase will rebase that changeset and all of its
91 ("-s/--source"), rebase will rebase that changeset and all of its
82 descendants onto dest. If you specify base ("-b/--base"), rebase will
92 descendants onto dest. If you specify base ("-b/--base"), rebase will
83 select ancestors of base back to but not including the common ancestor
93 select ancestors of base back to but not including the common ancestor
84 with dest. Thus, "-b" is less precise but more convenient than "-s": you
94 with dest. Thus, "-b" is less precise but more convenient than "-s": you
85 can specify any changeset in the source branch, and rebase will select the
95 can specify any changeset in the source branch, and rebase will select the
86 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
96 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
87 of the working directory as the base.
97 of the working directory as the base.
88
98
89 By default, rebase recreates the changesets in the source branch as
99 By default, rebase recreates the changesets in the source branch as
90 descendants of dest and then destroys the originals. Use "--keep" to
100 descendants of dest and then destroys the originals. Use "--keep" to
91 preserve the original source changesets. Some changesets in the source
101 preserve the original source changesets. Some changesets in the source
92 branch (e.g. merges from the destination branch) may be dropped if they no
102 branch (e.g. merges from the destination branch) may be dropped if they no
93 longer contribute any change.
103 longer contribute any change.
94
104
95 One result of the rules for selecting the destination changeset and source
105 One result of the rules for selecting the destination changeset and source
96 branch is that, unlike "merge", rebase will do nothing if you are at the
106 branch is that, unlike "merge", rebase will do nothing if you are at the
97 latest (tipmost) head of a named branch with two heads. You need to
107 latest (tipmost) head of a named branch with two heads. You need to
98 explicitly specify source and/or destination (or "update" to the other
108 explicitly specify source and/or destination (or "update" to the other
99 head, if it's the head of the intended source branch).
109 head, if it's the head of the intended source branch).
100
110
101 If a rebase is interrupted to manually resolve a merge, it can be
111 If a rebase is interrupted to manually resolve a merge, it can be
102 continued with --continue/-c or aborted with --abort/-a.
112 continued with --continue/-c or aborted with --abort/-a.
103
113
104 options:
114 options:
105
115
106 -s --source rebase from the specified changeset
116 -s --source rebase from the specified changeset
107 -b --base rebase from the base of the specified changeset (up to
117 -b --base rebase from the base of the specified changeset (up to
108 greatest common ancestor of base and dest)
118 greatest common ancestor of base and dest)
109 -d --dest rebase onto the specified changeset
119 -d --dest rebase onto the specified changeset
110 --collapse collapse the rebased changesets
120 --collapse collapse the rebased changesets
111 --keep keep original changesets
121 --keep keep original changesets
112 --keepbranches keep original branch names
122 --keepbranches keep original branch names
113 --detach force detaching of source from its original branch
123 --detach force detaching of source from its original branch
114 -c --continue continue an interrupted rebase
124 -c --continue continue an interrupted rebase
115 -a --abort abort an interrupted rebase
125 -a --abort abort an interrupted rebase
116 --style display using template map file
126 --style display using template map file
117 --template display with template
127 --template display with template
118
128
119 use "hg -v help rebase" to show global options
129 use "hg -v help rebase" to show global options
120
130
121 % Use continue/abort and dest/source
131 % Use continue/abort and dest/source
122 hg rebase: abort and continue do not allow specifying revisions
132 hg rebase: abort and continue do not allow specifying revisions
123 hg rebase [-s REV | -b REV] [-d REV] [options]
133 hg rebase [-s REV | -b REV] [-d REV] [options]
124 hg rebase {-a|-c}
134 hg rebase {-a|-c}
125
135
126 move changeset (and descendants) to a different branch
136 move changeset (and descendants) to a different branch
127
137
128 Rebase uses repeated merging to graft changesets from one part of history
138 Rebase uses repeated merging to graft changesets from one part of history
129 (the source) onto another (the destination). This can be useful for
139 (the source) onto another (the destination). This can be useful for
130 linearizing local changes relative to a master development tree.
140 linearizing *local* changes relative to a master development tree.
141
142 You should not rebase changesets that have already been shared with
143 others. Doing so will force everybody else to perform the same rebase or
144 they will end up with duplicated changesets after pulling in your rebased
145 changesets.
131
146
132 If you don't specify a destination changeset ("-d/--dest"), rebase uses
147 If you don't specify a destination changeset ("-d/--dest"), rebase uses
133 the tipmost head of the current named branch as the destination. (The
148 the tipmost head of the current named branch as the destination. (The
134 destination changeset is not modified by rebasing, but new changesets are
149 destination changeset is not modified by rebasing, but new changesets are
135 added as its descendants.)
150 added as its descendants.)
136
151
137 You can specify which changesets to rebase in two ways: as a "source"
152 You can specify which changesets to rebase in two ways: as a "source"
138 changeset or as a "base" changeset. Both are shorthand for a topologically
153 changeset or as a "base" changeset. Both are shorthand for a topologically
139 related set of changesets (the "source branch"). If you specify source
154 related set of changesets (the "source branch"). If you specify source
140 ("-s/--source"), rebase will rebase that changeset and all of its
155 ("-s/--source"), rebase will rebase that changeset and all of its
141 descendants onto dest. If you specify base ("-b/--base"), rebase will
156 descendants onto dest. If you specify base ("-b/--base"), rebase will
142 select ancestors of base back to but not including the common ancestor
157 select ancestors of base back to but not including the common ancestor
143 with dest. Thus, "-b" is less precise but more convenient than "-s": you
158 with dest. Thus, "-b" is less precise but more convenient than "-s": you
144 can specify any changeset in the source branch, and rebase will select the
159 can specify any changeset in the source branch, and rebase will select the
145 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
160 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
146 of the working directory as the base.
161 of the working directory as the base.
147
162
148 By default, rebase recreates the changesets in the source branch as
163 By default, rebase recreates the changesets in the source branch as
149 descendants of dest and then destroys the originals. Use "--keep" to
164 descendants of dest and then destroys the originals. Use "--keep" to
150 preserve the original source changesets. Some changesets in the source
165 preserve the original source changesets. Some changesets in the source
151 branch (e.g. merges from the destination branch) may be dropped if they no
166 branch (e.g. merges from the destination branch) may be dropped if they no
152 longer contribute any change.
167 longer contribute any change.
153
168
154 One result of the rules for selecting the destination changeset and source
169 One result of the rules for selecting the destination changeset and source
155 branch is that, unlike "merge", rebase will do nothing if you are at the
170 branch is that, unlike "merge", rebase will do nothing if you are at the
156 latest (tipmost) head of a named branch with two heads. You need to
171 latest (tipmost) head of a named branch with two heads. You need to
157 explicitly specify source and/or destination (or "update" to the other
172 explicitly specify source and/or destination (or "update" to the other
158 head, if it's the head of the intended source branch).
173 head, if it's the head of the intended source branch).
159
174
160 If a rebase is interrupted to manually resolve a merge, it can be
175 If a rebase is interrupted to manually resolve a merge, it can be
161 continued with --continue/-c or aborted with --abort/-a.
176 continued with --continue/-c or aborted with --abort/-a.
162
177
163 options:
178 options:
164
179
165 -s --source rebase from the specified changeset
180 -s --source rebase from the specified changeset
166 -b --base rebase from the base of the specified changeset (up to
181 -b --base rebase from the base of the specified changeset (up to
167 greatest common ancestor of base and dest)
182 greatest common ancestor of base and dest)
168 -d --dest rebase onto the specified changeset
183 -d --dest rebase onto the specified changeset
169 --collapse collapse the rebased changesets
184 --collapse collapse the rebased changesets
170 --keep keep original changesets
185 --keep keep original changesets
171 --keepbranches keep original branch names
186 --keepbranches keep original branch names
172 --detach force detaching of source from its original branch
187 --detach force detaching of source from its original branch
173 -c --continue continue an interrupted rebase
188 -c --continue continue an interrupted rebase
174 -a --abort abort an interrupted rebase
189 -a --abort abort an interrupted rebase
175 --style display using template map file
190 --style display using template map file
176 --template display with template
191 --template display with template
177
192
178 use "hg -v help rebase" to show global options
193 use "hg -v help rebase" to show global options
179
194
180 % Use source and base
195 % Use source and base
181 hg rebase: cannot specify both a revision and a base
196 hg rebase: cannot specify both a revision and a base
182 hg rebase [-s REV | -b REV] [-d REV] [options]
197 hg rebase [-s REV | -b REV] [-d REV] [options]
183 hg rebase {-a|-c}
198 hg rebase {-a|-c}
184
199
185 move changeset (and descendants) to a different branch
200 move changeset (and descendants) to a different branch
186
201
187 Rebase uses repeated merging to graft changesets from one part of history
202 Rebase uses repeated merging to graft changesets from one part of history
188 (the source) onto another (the destination). This can be useful for
203 (the source) onto another (the destination). This can be useful for
189 linearizing local changes relative to a master development tree.
204 linearizing *local* changes relative to a master development tree.
205
206 You should not rebase changesets that have already been shared with
207 others. Doing so will force everybody else to perform the same rebase or
208 they will end up with duplicated changesets after pulling in your rebased
209 changesets.
190
210
191 If you don't specify a destination changeset ("-d/--dest"), rebase uses
211 If you don't specify a destination changeset ("-d/--dest"), rebase uses
192 the tipmost head of the current named branch as the destination. (The
212 the tipmost head of the current named branch as the destination. (The
193 destination changeset is not modified by rebasing, but new changesets are
213 destination changeset is not modified by rebasing, but new changesets are
194 added as its descendants.)
214 added as its descendants.)
195
215
196 You can specify which changesets to rebase in two ways: as a "source"
216 You can specify which changesets to rebase in two ways: as a "source"
197 changeset or as a "base" changeset. Both are shorthand for a topologically
217 changeset or as a "base" changeset. Both are shorthand for a topologically
198 related set of changesets (the "source branch"). If you specify source
218 related set of changesets (the "source branch"). If you specify source
199 ("-s/--source"), rebase will rebase that changeset and all of its
219 ("-s/--source"), rebase will rebase that changeset and all of its
200 descendants onto dest. If you specify base ("-b/--base"), rebase will
220 descendants onto dest. If you specify base ("-b/--base"), rebase will
201 select ancestors of base back to but not including the common ancestor
221 select ancestors of base back to but not including the common ancestor
202 with dest. Thus, "-b" is less precise but more convenient than "-s": you
222 with dest. Thus, "-b" is less precise but more convenient than "-s": you
203 can specify any changeset in the source branch, and rebase will select the
223 can specify any changeset in the source branch, and rebase will select the
204 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
224 whole branch. If you specify neither "-s" nor "-b", rebase uses the parent
205 of the working directory as the base.
225 of the working directory as the base.
206
226
207 By default, rebase recreates the changesets in the source branch as
227 By default, rebase recreates the changesets in the source branch as
208 descendants of dest and then destroys the originals. Use "--keep" to
228 descendants of dest and then destroys the originals. Use "--keep" to
209 preserve the original source changesets. Some changesets in the source
229 preserve the original source changesets. Some changesets in the source
210 branch (e.g. merges from the destination branch) may be dropped if they no
230 branch (e.g. merges from the destination branch) may be dropped if they no
211 longer contribute any change.
231 longer contribute any change.
212
232
213 One result of the rules for selecting the destination changeset and source
233 One result of the rules for selecting the destination changeset and source
214 branch is that, unlike "merge", rebase will do nothing if you are at the
234 branch is that, unlike "merge", rebase will do nothing if you are at the
215 latest (tipmost) head of a named branch with two heads. You need to
235 latest (tipmost) head of a named branch with two heads. You need to
216 explicitly specify source and/or destination (or "update" to the other
236 explicitly specify source and/or destination (or "update" to the other
217 head, if it's the head of the intended source branch).
237 head, if it's the head of the intended source branch).
218
238
219 If a rebase is interrupted to manually resolve a merge, it can be
239 If a rebase is interrupted to manually resolve a merge, it can be
220 continued with --continue/-c or aborted with --abort/-a.
240 continued with --continue/-c or aborted with --abort/-a.
221
241
222 options:
242 options:
223
243
224 -s --source rebase from the specified changeset
244 -s --source rebase from the specified changeset
225 -b --base rebase from the base of the specified changeset (up to
245 -b --base rebase from the base of the specified changeset (up to
226 greatest common ancestor of base and dest)
246 greatest common ancestor of base and dest)
227 -d --dest rebase onto the specified changeset
247 -d --dest rebase onto the specified changeset
228 --collapse collapse the rebased changesets
248 --collapse collapse the rebased changesets
229 --keep keep original changesets
249 --keep keep original changesets
230 --keepbranches keep original branch names
250 --keepbranches keep original branch names
231 --detach force detaching of source from its original branch
251 --detach force detaching of source from its original branch
232 -c --continue continue an interrupted rebase
252 -c --continue continue an interrupted rebase
233 -a --abort abort an interrupted rebase
253 -a --abort abort an interrupted rebase
234 --style display using template map file
254 --style display using template map file
235 --template display with template
255 --template display with template
236
256
237 use "hg -v help rebase" to show global options
257 use "hg -v help rebase" to show global options
238
258
239 % Rebase with no arguments - from current
259 % Rebase with no arguments - from current
240 nothing to rebase
260 nothing to rebase
241
261
242 % Rebase with no arguments - from the current branch
262 % Rebase with no arguments - from the current branch
243 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
263 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
244 nothing to rebase
264 nothing to rebase
245 % ----------
265 % ----------
246 % These work
266 % These work
247
267
248 % Rebase with no arguments (from 3 onto 7)
268 % Rebase with no arguments (from 3 onto 7)
249 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
269 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
250 saving bundle to
270 saving bundle to
251 adding branch
271 adding branch
252 adding changesets
272 adding changesets
253 adding manifests
273 adding manifests
254 adding file changes
274 adding file changes
255 added 5 changesets with 5 changes to 5 files
275 added 5 changesets with 5 changes to 5 files
256 rebase completed
276 rebase completed
257 % Try to rollback after a rebase (fail)
277 % Try to rollback after a rebase (fail)
258 no rollback information available
278 no rollback information available
259
279
260 % Rebase with base == '.' => same as no arguments (from 3 onto 7)
280 % Rebase with base == '.' => same as no arguments (from 3 onto 7)
261 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
281 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
262 saving bundle to
282 saving bundle to
263 adding branch
283 adding branch
264 adding changesets
284 adding changesets
265 adding manifests
285 adding manifests
266 adding file changes
286 adding file changes
267 added 5 changesets with 5 changes to 5 files
287 added 5 changesets with 5 changes to 5 files
268 rebase completed
288 rebase completed
269
289
270 % Rebase with dest == default => same as no arguments (from 3 onto 7)
290 % Rebase with dest == default => same as no arguments (from 3 onto 7)
271 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
291 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
272 saving bundle to
292 saving bundle to
273 adding branch
293 adding branch
274 adding changesets
294 adding changesets
275 adding manifests
295 adding manifests
276 adding file changes
296 adding file changes
277 added 5 changesets with 5 changes to 5 files
297 added 5 changesets with 5 changes to 5 files
278 rebase completed
298 rebase completed
279
299
280 % Specify only source (from 4 onto 7)
300 % Specify only source (from 4 onto 7)
281 saving bundle to
301 saving bundle to
282 adding branch
302 adding branch
283 adding changesets
303 adding changesets
284 adding manifests
304 adding manifests
285 adding file changes
305 adding file changes
286 added 4 changesets with 4 changes to 4 files (-1 heads)
306 added 4 changesets with 4 changes to 4 files (-1 heads)
287 rebase completed
307 rebase completed
288
308
289 % Specify only dest (from 3 onto 6)
309 % Specify only dest (from 3 onto 6)
290 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
310 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
291 saving bundle to
311 saving bundle to
292 adding branch
312 adding branch
293 adding changesets
313 adding changesets
294 adding manifests
314 adding manifests
295 adding file changes
315 adding file changes
296 added 5 changesets with 5 changes to 5 files (+1 heads)
316 added 5 changesets with 5 changes to 5 files (+1 heads)
297 rebase completed
317 rebase completed
298
318
299 % Specify only base (from 3 onto 7)
319 % Specify only base (from 3 onto 7)
300 saving bundle to
320 saving bundle to
301 adding branch
321 adding branch
302 adding changesets
322 adding changesets
303 adding manifests
323 adding manifests
304 adding file changes
324 adding file changes
305 added 5 changesets with 5 changes to 5 files
325 added 5 changesets with 5 changes to 5 files
306 rebase completed
326 rebase completed
307
327
308 % Specify source and dest (from 4 onto 6)
328 % Specify source and dest (from 4 onto 6)
309 saving bundle to
329 saving bundle to
310 adding branch
330 adding branch
311 adding changesets
331 adding changesets
312 adding manifests
332 adding manifests
313 adding file changes
333 adding file changes
314 added 4 changesets with 4 changes to 4 files
334 added 4 changesets with 4 changes to 4 files
315 rebase completed
335 rebase completed
316
336
317 % Specify base and dest (from 3 onto 6)
337 % Specify base and dest (from 3 onto 6)
318 saving bundle to
338 saving bundle to
319 adding branch
339 adding branch
320 adding changesets
340 adding changesets
321 adding manifests
341 adding manifests
322 adding file changes
342 adding file changes
323 added 5 changesets with 5 changes to 5 files (+1 heads)
343 added 5 changesets with 5 changes to 5 files (+1 heads)
324 rebase completed
344 rebase completed
General Comments 0
You need to be logged in to leave comments. Login now