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