##// END OF EJS Templates
destutil: raise more specific error when histedit.defaultrev is empty...
Martin von Zweigbergk -
r46447:c7abdbc8 default
parent child Browse files
Show More
@@ -1,490 +1,490 b''
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from .i18n import _
10 from .i18n import _
11 from . import bookmarks, error, obsutil, scmutil, stack
11 from . import bookmarks, error, obsutil, scmutil, stack
12
12
13
13
14 def orphanpossibledestination(repo, rev):
14 def orphanpossibledestination(repo, rev):
15 """Return all changesets that may be a new parent for orphan `rev`.
15 """Return all changesets that may be a new parent for orphan `rev`.
16
16
17 This function works fine on non-orphan revisions, it's just silly
17 This function works fine on non-orphan revisions, it's just silly
18 because there's no destination implied by obsolete markers, so
18 because there's no destination implied by obsolete markers, so
19 it'll return nothing.
19 it'll return nothing.
20 """
20 """
21 tonode = repo.changelog.node
21 tonode = repo.changelog.node
22 parents = repo.changelog.parentrevs
22 parents = repo.changelog.parentrevs
23 torev = repo.changelog.rev
23 torev = repo.changelog.rev
24 dest = set()
24 dest = set()
25 tovisit = list(parents(rev))
25 tovisit = list(parents(rev))
26 while tovisit:
26 while tovisit:
27 r = tovisit.pop()
27 r = tovisit.pop()
28 succsets = obsutil.successorssets(repo, tonode(r))
28 succsets = obsutil.successorssets(repo, tonode(r))
29 if not succsets:
29 if not succsets:
30 # if there are no successors for r, r was probably pruned
30 # if there are no successors for r, r was probably pruned
31 # and we should walk up to r's parents to try and find
31 # and we should walk up to r's parents to try and find
32 # some successors.
32 # some successors.
33 tovisit.extend(parents(r))
33 tovisit.extend(parents(r))
34 else:
34 else:
35 # We should probably pick only one destination from split
35 # We should probably pick only one destination from split
36 # (case where '1 < len(ss)'), This could be the currently
36 # (case where '1 < len(ss)'), This could be the currently
37 # tipmost, but the correct result is less clear when
37 # tipmost, but the correct result is less clear when
38 # results of the split have been moved such that they
38 # results of the split have been moved such that they
39 # reside on multiple branches.
39 # reside on multiple branches.
40 for ss in succsets:
40 for ss in succsets:
41 for n in ss:
41 for n in ss:
42 dr = torev(n)
42 dr = torev(n)
43 if dr != -1:
43 if dr != -1:
44 dest.add(dr)
44 dest.add(dr)
45 return dest
45 return dest
46
46
47
47
48 def _destupdateobs(repo, clean):
48 def _destupdateobs(repo, clean):
49 """decide of an update destination from obsolescence markers"""
49 """decide of an update destination from obsolescence markers"""
50 node = None
50 node = None
51 wc = repo[None]
51 wc = repo[None]
52 p1 = wc.p1()
52 p1 = wc.p1()
53 movemark = None
53 movemark = None
54
54
55 if p1.obsolete() and not p1.children():
55 if p1.obsolete() and not p1.children():
56 # allow updating to successors
56 # allow updating to successors
57 successors = obsutil.successorssets(repo, p1.node())
57 successors = obsutil.successorssets(repo, p1.node())
58
58
59 # behavior of certain cases is as follows,
59 # behavior of certain cases is as follows,
60 #
60 #
61 # divergent changesets: update to highest rev, similar to what
61 # divergent changesets: update to highest rev, similar to what
62 # is currently done when there are more than one head
62 # is currently done when there are more than one head
63 # (i.e. 'tip')
63 # (i.e. 'tip')
64 #
64 #
65 # replaced changesets: same as divergent except we know there
65 # replaced changesets: same as divergent except we know there
66 # is no conflict
66 # is no conflict
67 #
67 #
68 # pruned changeset: no update is done; though, we could
68 # pruned changeset: no update is done; though, we could
69 # consider updating to the first non-obsolete parent,
69 # consider updating to the first non-obsolete parent,
70 # similar to what is current done for 'hg prune'
70 # similar to what is current done for 'hg prune'
71
71
72 if successors:
72 if successors:
73 # flatten the list here handles both divergent (len > 1)
73 # flatten the list here handles both divergent (len > 1)
74 # and the usual case (len = 1)
74 # and the usual case (len = 1)
75 successors = [n for sub in successors for n in sub]
75 successors = [n for sub in successors for n in sub]
76
76
77 # get the max revision for the given successors set,
77 # get the max revision for the given successors set,
78 # i.e. the 'tip' of a set
78 # i.e. the 'tip' of a set
79 node = repo.revs(b'max(%ln)', successors).first()
79 node = repo.revs(b'max(%ln)', successors).first()
80 if bookmarks.isactivewdirparent(repo):
80 if bookmarks.isactivewdirparent(repo):
81 movemark = repo[b'.'].node()
81 movemark = repo[b'.'].node()
82 return node, movemark, None
82 return node, movemark, None
83
83
84
84
85 def _destupdatebook(repo, clean):
85 def _destupdatebook(repo, clean):
86 """decide on an update destination from active bookmark"""
86 """decide on an update destination from active bookmark"""
87 # we also move the active bookmark, if any
87 # we also move the active bookmark, if any
88 node = None
88 node = None
89 activemark, movemark = bookmarks.calculateupdate(repo.ui, repo)
89 activemark, movemark = bookmarks.calculateupdate(repo.ui, repo)
90 if activemark is not None:
90 if activemark is not None:
91 node = repo._bookmarks[activemark]
91 node = repo._bookmarks[activemark]
92 return node, movemark, activemark
92 return node, movemark, activemark
93
93
94
94
95 def _destupdatebranch(repo, clean):
95 def _destupdatebranch(repo, clean):
96 """decide on an update destination from current branch
96 """decide on an update destination from current branch
97
97
98 This ignores closed branch heads.
98 This ignores closed branch heads.
99 """
99 """
100 wc = repo[None]
100 wc = repo[None]
101 movemark = node = None
101 movemark = node = None
102 currentbranch = wc.branch()
102 currentbranch = wc.branch()
103
103
104 if clean:
104 if clean:
105 currentbranch = repo[b'.'].branch()
105 currentbranch = repo[b'.'].branch()
106
106
107 if currentbranch in repo.branchmap():
107 if currentbranch in repo.branchmap():
108 heads = repo.branchheads(currentbranch)
108 heads = repo.branchheads(currentbranch)
109 if heads:
109 if heads:
110 node = repo.revs(b'max(.::(%ln))', heads).first()
110 node = repo.revs(b'max(.::(%ln))', heads).first()
111 if bookmarks.isactivewdirparent(repo):
111 if bookmarks.isactivewdirparent(repo):
112 movemark = repo[b'.'].node()
112 movemark = repo[b'.'].node()
113 elif currentbranch == b'default' and not wc.p1():
113 elif currentbranch == b'default' and not wc.p1():
114 # "null" parent belongs to "default" branch, but it doesn't exist, so
114 # "null" parent belongs to "default" branch, but it doesn't exist, so
115 # update to the tipmost non-closed branch head
115 # update to the tipmost non-closed branch head
116 node = repo.revs(b'max(head() and not closed())').first()
116 node = repo.revs(b'max(head() and not closed())').first()
117 else:
117 else:
118 node = repo[b'.'].node()
118 node = repo[b'.'].node()
119 return node, movemark, None
119 return node, movemark, None
120
120
121
121
122 def _destupdatebranchfallback(repo, clean):
122 def _destupdatebranchfallback(repo, clean):
123 """decide on an update destination from closed heads in current branch"""
123 """decide on an update destination from closed heads in current branch"""
124 wc = repo[None]
124 wc = repo[None]
125 currentbranch = wc.branch()
125 currentbranch = wc.branch()
126 movemark = None
126 movemark = None
127 if currentbranch in repo.branchmap():
127 if currentbranch in repo.branchmap():
128 # here, all descendant branch heads are closed
128 # here, all descendant branch heads are closed
129 heads = repo.branchheads(currentbranch, closed=True)
129 heads = repo.branchheads(currentbranch, closed=True)
130 assert heads, b"any branch has at least one head"
130 assert heads, b"any branch has at least one head"
131 node = repo.revs(b'max(.::(%ln))', heads).first()
131 node = repo.revs(b'max(.::(%ln))', heads).first()
132 assert (
132 assert (
133 node is not None
133 node is not None
134 ), b"any revision has at least one descendant branch head"
134 ), b"any revision has at least one descendant branch head"
135 if bookmarks.isactivewdirparent(repo):
135 if bookmarks.isactivewdirparent(repo):
136 movemark = repo[b'.'].node()
136 movemark = repo[b'.'].node()
137 else:
137 else:
138 # here, no "default" branch, and all branches are closed
138 # here, no "default" branch, and all branches are closed
139 node = repo.lookup(b'tip')
139 node = repo.lookup(b'tip')
140 assert node is not None, b"'tip' exists even in empty repository"
140 assert node is not None, b"'tip' exists even in empty repository"
141 return node, movemark, None
141 return node, movemark, None
142
142
143
143
144 # order in which each step should be evaluated
144 # order in which each step should be evaluated
145 # steps are run until one finds a destination
145 # steps are run until one finds a destination
146 destupdatesteps = [b'evolution', b'bookmark', b'branch', b'branchfallback']
146 destupdatesteps = [b'evolution', b'bookmark', b'branch', b'branchfallback']
147 # mapping to ease extension overriding steps.
147 # mapping to ease extension overriding steps.
148 destupdatestepmap = {
148 destupdatestepmap = {
149 b'evolution': _destupdateobs,
149 b'evolution': _destupdateobs,
150 b'bookmark': _destupdatebook,
150 b'bookmark': _destupdatebook,
151 b'branch': _destupdatebranch,
151 b'branch': _destupdatebranch,
152 b'branchfallback': _destupdatebranchfallback,
152 b'branchfallback': _destupdatebranchfallback,
153 }
153 }
154
154
155
155
156 def destupdate(repo, clean=False):
156 def destupdate(repo, clean=False):
157 """destination for bare update operation
157 """destination for bare update operation
158
158
159 return (rev, movemark, activemark)
159 return (rev, movemark, activemark)
160
160
161 - rev: the revision to update to,
161 - rev: the revision to update to,
162 - movemark: node to move the active bookmark from
162 - movemark: node to move the active bookmark from
163 (cf bookmark.calculate update),
163 (cf bookmark.calculate update),
164 - activemark: a bookmark to activate at the end of the update.
164 - activemark: a bookmark to activate at the end of the update.
165 """
165 """
166 node = movemark = activemark = None
166 node = movemark = activemark = None
167
167
168 for step in destupdatesteps:
168 for step in destupdatesteps:
169 node, movemark, activemark = destupdatestepmap[step](repo, clean)
169 node, movemark, activemark = destupdatestepmap[step](repo, clean)
170 if node is not None:
170 if node is not None:
171 break
171 break
172 rev = repo[node].rev()
172 rev = repo[node].rev()
173
173
174 return rev, movemark, activemark
174 return rev, movemark, activemark
175
175
176
176
177 msgdestmerge = {
177 msgdestmerge = {
178 # too many matching divergent bookmark
178 # too many matching divergent bookmark
179 b'toomanybookmarks': {
179 b'toomanybookmarks': {
180 b'merge': (
180 b'merge': (
181 _(
181 _(
182 b"multiple matching bookmarks to merge -"
182 b"multiple matching bookmarks to merge -"
183 b" please merge with an explicit rev or bookmark"
183 b" please merge with an explicit rev or bookmark"
184 ),
184 ),
185 _(b"run 'hg heads' to see all heads, specify rev with -r"),
185 _(b"run 'hg heads' to see all heads, specify rev with -r"),
186 ),
186 ),
187 b'rebase': (
187 b'rebase': (
188 _(
188 _(
189 b"multiple matching bookmarks to rebase -"
189 b"multiple matching bookmarks to rebase -"
190 b" please rebase to an explicit rev or bookmark"
190 b" please rebase to an explicit rev or bookmark"
191 ),
191 ),
192 _(b"run 'hg heads' to see all heads, specify destination with -d"),
192 _(b"run 'hg heads' to see all heads, specify destination with -d"),
193 ),
193 ),
194 },
194 },
195 # no other matching divergent bookmark
195 # no other matching divergent bookmark
196 b'nootherbookmarks': {
196 b'nootherbookmarks': {
197 b'merge': (
197 b'merge': (
198 _(
198 _(
199 b"no matching bookmark to merge - "
199 b"no matching bookmark to merge - "
200 b"please merge with an explicit rev or bookmark"
200 b"please merge with an explicit rev or bookmark"
201 ),
201 ),
202 _(b"run 'hg heads' to see all heads, specify rev with -r"),
202 _(b"run 'hg heads' to see all heads, specify rev with -r"),
203 ),
203 ),
204 b'rebase': (
204 b'rebase': (
205 _(
205 _(
206 b"no matching bookmark to rebase - "
206 b"no matching bookmark to rebase - "
207 b"please rebase to an explicit rev or bookmark"
207 b"please rebase to an explicit rev or bookmark"
208 ),
208 ),
209 _(b"run 'hg heads' to see all heads, specify destination with -d"),
209 _(b"run 'hg heads' to see all heads, specify destination with -d"),
210 ),
210 ),
211 },
211 },
212 # branch have too many unbookmarked heads, no obvious destination
212 # branch have too many unbookmarked heads, no obvious destination
213 b'toomanyheads': {
213 b'toomanyheads': {
214 b'merge': (
214 b'merge': (
215 _(b"branch '%s' has %d heads - please merge with an explicit rev"),
215 _(b"branch '%s' has %d heads - please merge with an explicit rev"),
216 _(b"run 'hg heads .' to see heads, specify rev with -r"),
216 _(b"run 'hg heads .' to see heads, specify rev with -r"),
217 ),
217 ),
218 b'rebase': (
218 b'rebase': (
219 _(b"branch '%s' has %d heads - please rebase to an explicit rev"),
219 _(b"branch '%s' has %d heads - please rebase to an explicit rev"),
220 _(b"run 'hg heads .' to see heads, specify destination with -d"),
220 _(b"run 'hg heads .' to see heads, specify destination with -d"),
221 ),
221 ),
222 },
222 },
223 # branch have no other unbookmarked heads
223 # branch have no other unbookmarked heads
224 b'bookmarkedheads': {
224 b'bookmarkedheads': {
225 b'merge': (
225 b'merge': (
226 _(b"heads are bookmarked - please merge with an explicit rev"),
226 _(b"heads are bookmarked - please merge with an explicit rev"),
227 _(b"run 'hg heads' to see all heads, specify rev with -r"),
227 _(b"run 'hg heads' to see all heads, specify rev with -r"),
228 ),
228 ),
229 b'rebase': (
229 b'rebase': (
230 _(b"heads are bookmarked - please rebase to an explicit rev"),
230 _(b"heads are bookmarked - please rebase to an explicit rev"),
231 _(b"run 'hg heads' to see all heads, specify destination with -d"),
231 _(b"run 'hg heads' to see all heads, specify destination with -d"),
232 ),
232 ),
233 },
233 },
234 # branch have just a single heads, but there is other branches
234 # branch have just a single heads, but there is other branches
235 b'nootherbranchheads': {
235 b'nootherbranchheads': {
236 b'merge': (
236 b'merge': (
237 _(b"branch '%s' has one head - please merge with an explicit rev"),
237 _(b"branch '%s' has one head - please merge with an explicit rev"),
238 _(b"run 'hg heads' to see all heads, specify rev with -r"),
238 _(b"run 'hg heads' to see all heads, specify rev with -r"),
239 ),
239 ),
240 b'rebase': (
240 b'rebase': (
241 _(b"branch '%s' has one head - please rebase to an explicit rev"),
241 _(b"branch '%s' has one head - please rebase to an explicit rev"),
242 _(b"run 'hg heads' to see all heads, specify destination with -d"),
242 _(b"run 'hg heads' to see all heads, specify destination with -d"),
243 ),
243 ),
244 },
244 },
245 # repository have a single head
245 # repository have a single head
246 b'nootherheads': {
246 b'nootherheads': {
247 b'merge': (_(b'nothing to merge'), None),
247 b'merge': (_(b'nothing to merge'), None),
248 b'rebase': (_(b'nothing to rebase'), None),
248 b'rebase': (_(b'nothing to rebase'), None),
249 },
249 },
250 # repository have a single head and we are not on it
250 # repository have a single head and we are not on it
251 b'nootherheadsbehind': {
251 b'nootherheadsbehind': {
252 b'merge': (_(b'nothing to merge'), _(b"use 'hg update' instead")),
252 b'merge': (_(b'nothing to merge'), _(b"use 'hg update' instead")),
253 b'rebase': (_(b'nothing to rebase'), _(b"use 'hg update' instead")),
253 b'rebase': (_(b'nothing to rebase'), _(b"use 'hg update' instead")),
254 },
254 },
255 # We are not on a head
255 # We are not on a head
256 b'notatheads': {
256 b'notatheads': {
257 b'merge': (
257 b'merge': (
258 _(b'working directory not at a head revision'),
258 _(b'working directory not at a head revision'),
259 _(b"use 'hg update' or merge with an explicit revision"),
259 _(b"use 'hg update' or merge with an explicit revision"),
260 ),
260 ),
261 b'rebase': (
261 b'rebase': (
262 _(b'working directory not at a head revision'),
262 _(b'working directory not at a head revision'),
263 _(b"use 'hg update' or rebase to an explicit revision"),
263 _(b"use 'hg update' or rebase to an explicit revision"),
264 ),
264 ),
265 },
265 },
266 b'emptysourceset': {
266 b'emptysourceset': {
267 b'merge': (_(b'source set is empty'), None),
267 b'merge': (_(b'source set is empty'), None),
268 b'rebase': (_(b'source set is empty'), None),
268 b'rebase': (_(b'source set is empty'), None),
269 },
269 },
270 b'multiplebranchessourceset': {
270 b'multiplebranchessourceset': {
271 b'merge': (_(b'source set is rooted in multiple branches'), None),
271 b'merge': (_(b'source set is rooted in multiple branches'), None),
272 b'rebase': (
272 b'rebase': (
273 _(b'rebaseset is rooted in multiple named branches'),
273 _(b'rebaseset is rooted in multiple named branches'),
274 _(b'specify an explicit destination with --dest'),
274 _(b'specify an explicit destination with --dest'),
275 ),
275 ),
276 },
276 },
277 }
277 }
278
278
279
279
280 def _destmergebook(repo, action=b'merge', sourceset=None, destspace=None):
280 def _destmergebook(repo, action=b'merge', sourceset=None, destspace=None):
281 """find merge destination in the active bookmark case"""
281 """find merge destination in the active bookmark case"""
282 node = None
282 node = None
283 bmheads = bookmarks.headsforactive(repo)
283 bmheads = bookmarks.headsforactive(repo)
284 curhead = repo._bookmarks[repo._activebookmark]
284 curhead = repo._bookmarks[repo._activebookmark]
285 if len(bmheads) == 2:
285 if len(bmheads) == 2:
286 if curhead == bmheads[0]:
286 if curhead == bmheads[0]:
287 node = bmheads[1]
287 node = bmheads[1]
288 else:
288 else:
289 node = bmheads[0]
289 node = bmheads[0]
290 elif len(bmheads) > 2:
290 elif len(bmheads) > 2:
291 msg, hint = msgdestmerge[b'toomanybookmarks'][action]
291 msg, hint = msgdestmerge[b'toomanybookmarks'][action]
292 raise error.ManyMergeDestAbort(msg, hint=hint)
292 raise error.ManyMergeDestAbort(msg, hint=hint)
293 elif len(bmheads) <= 1:
293 elif len(bmheads) <= 1:
294 msg, hint = msgdestmerge[b'nootherbookmarks'][action]
294 msg, hint = msgdestmerge[b'nootherbookmarks'][action]
295 raise error.NoMergeDestAbort(msg, hint=hint)
295 raise error.NoMergeDestAbort(msg, hint=hint)
296 assert node is not None
296 assert node is not None
297 return node
297 return node
298
298
299
299
300 def _destmergebranch(
300 def _destmergebranch(
301 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
301 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
302 ):
302 ):
303 """find merge destination based on branch heads"""
303 """find merge destination based on branch heads"""
304 node = None
304 node = None
305
305
306 if sourceset is None:
306 if sourceset is None:
307 sourceset = [repo[repo.dirstate.p1()].rev()]
307 sourceset = [repo[repo.dirstate.p1()].rev()]
308 branch = repo.dirstate.branch()
308 branch = repo.dirstate.branch()
309 elif not sourceset:
309 elif not sourceset:
310 msg, hint = msgdestmerge[b'emptysourceset'][action]
310 msg, hint = msgdestmerge[b'emptysourceset'][action]
311 raise error.NoMergeDestAbort(msg, hint=hint)
311 raise error.NoMergeDestAbort(msg, hint=hint)
312 else:
312 else:
313 branch = None
313 branch = None
314 for ctx in repo.set(b'roots(%ld::%ld)', sourceset, sourceset):
314 for ctx in repo.set(b'roots(%ld::%ld)', sourceset, sourceset):
315 if branch is not None and ctx.branch() != branch:
315 if branch is not None and ctx.branch() != branch:
316 msg, hint = msgdestmerge[b'multiplebranchessourceset'][action]
316 msg, hint = msgdestmerge[b'multiplebranchessourceset'][action]
317 raise error.ManyMergeDestAbort(msg, hint=hint)
317 raise error.ManyMergeDestAbort(msg, hint=hint)
318 branch = ctx.branch()
318 branch = ctx.branch()
319
319
320 bheads = repo.branchheads(branch)
320 bheads = repo.branchheads(branch)
321 onhead = repo.revs(b'%ld and %ln', sourceset, bheads)
321 onhead = repo.revs(b'%ld and %ln', sourceset, bheads)
322 if onheadcheck and not onhead:
322 if onheadcheck and not onhead:
323 # Case A: working copy if not on a head. (merge only)
323 # Case A: working copy if not on a head. (merge only)
324 #
324 #
325 # This is probably a user mistake We bailout pointing at 'hg update'
325 # This is probably a user mistake We bailout pointing at 'hg update'
326 if len(repo.heads()) <= 1:
326 if len(repo.heads()) <= 1:
327 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
327 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
328 else:
328 else:
329 msg, hint = msgdestmerge[b'notatheads'][action]
329 msg, hint = msgdestmerge[b'notatheads'][action]
330 raise error.Abort(msg, hint=hint)
330 raise error.Abort(msg, hint=hint)
331 # remove heads descendants of source from the set
331 # remove heads descendants of source from the set
332 bheads = list(repo.revs(b'%ln - (%ld::)', bheads, sourceset))
332 bheads = list(repo.revs(b'%ln - (%ld::)', bheads, sourceset))
333 # filters out bookmarked heads
333 # filters out bookmarked heads
334 nbhs = list(repo.revs(b'%ld - bookmark()', bheads))
334 nbhs = list(repo.revs(b'%ld - bookmark()', bheads))
335
335
336 if destspace is not None:
336 if destspace is not None:
337 # restrict search space
337 # restrict search space
338 # used in the 'hg pull --rebase' case, see issue 5214.
338 # used in the 'hg pull --rebase' case, see issue 5214.
339 nbhs = list(repo.revs(b'%ld and %ld', destspace, nbhs))
339 nbhs = list(repo.revs(b'%ld and %ld', destspace, nbhs))
340
340
341 if len(nbhs) > 1:
341 if len(nbhs) > 1:
342 # Case B: There is more than 1 other anonymous heads
342 # Case B: There is more than 1 other anonymous heads
343 #
343 #
344 # This means that there will be more than 1 candidate. This is
344 # This means that there will be more than 1 candidate. This is
345 # ambiguous. We abort asking the user to pick as explicit destination
345 # ambiguous. We abort asking the user to pick as explicit destination
346 # instead.
346 # instead.
347 msg, hint = msgdestmerge[b'toomanyheads'][action]
347 msg, hint = msgdestmerge[b'toomanyheads'][action]
348 msg %= (branch, len(bheads) + 1)
348 msg %= (branch, len(bheads) + 1)
349 raise error.ManyMergeDestAbort(msg, hint=hint)
349 raise error.ManyMergeDestAbort(msg, hint=hint)
350 elif not nbhs:
350 elif not nbhs:
351 # Case B: There is no other anonymous heads
351 # Case B: There is no other anonymous heads
352 #
352 #
353 # This means that there is no natural candidate to merge with.
353 # This means that there is no natural candidate to merge with.
354 # We abort, with various messages for various cases.
354 # We abort, with various messages for various cases.
355 if bheads:
355 if bheads:
356 msg, hint = msgdestmerge[b'bookmarkedheads'][action]
356 msg, hint = msgdestmerge[b'bookmarkedheads'][action]
357 elif len(repo.heads()) > 1:
357 elif len(repo.heads()) > 1:
358 msg, hint = msgdestmerge[b'nootherbranchheads'][action]
358 msg, hint = msgdestmerge[b'nootherbranchheads'][action]
359 msg %= branch
359 msg %= branch
360 elif not onhead:
360 elif not onhead:
361 # if 'onheadcheck == False' (rebase case),
361 # if 'onheadcheck == False' (rebase case),
362 # this was not caught in Case A.
362 # this was not caught in Case A.
363 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
363 msg, hint = msgdestmerge[b'nootherheadsbehind'][action]
364 else:
364 else:
365 msg, hint = msgdestmerge[b'nootherheads'][action]
365 msg, hint = msgdestmerge[b'nootherheads'][action]
366 raise error.NoMergeDestAbort(msg, hint=hint)
366 raise error.NoMergeDestAbort(msg, hint=hint)
367 else:
367 else:
368 node = nbhs[0]
368 node = nbhs[0]
369 assert node is not None
369 assert node is not None
370 return node
370 return node
371
371
372
372
373 def destmerge(
373 def destmerge(
374 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
374 repo, action=b'merge', sourceset=None, onheadcheck=True, destspace=None
375 ):
375 ):
376 """return the default destination for a merge
376 """return the default destination for a merge
377
377
378 (or raise exception about why it can't pick one)
378 (or raise exception about why it can't pick one)
379
379
380 :action: the action being performed, controls emitted error message
380 :action: the action being performed, controls emitted error message
381 """
381 """
382 # destspace is here to work around issues with `hg pull --rebase` see
382 # destspace is here to work around issues with `hg pull --rebase` see
383 # issue5214 for details
383 # issue5214 for details
384 if repo._activebookmark:
384 if repo._activebookmark:
385 node = _destmergebook(
385 node = _destmergebook(
386 repo, action=action, sourceset=sourceset, destspace=destspace
386 repo, action=action, sourceset=sourceset, destspace=destspace
387 )
387 )
388 else:
388 else:
389 node = _destmergebranch(
389 node = _destmergebranch(
390 repo,
390 repo,
391 action=action,
391 action=action,
392 sourceset=sourceset,
392 sourceset=sourceset,
393 onheadcheck=onheadcheck,
393 onheadcheck=onheadcheck,
394 destspace=destspace,
394 destspace=destspace,
395 )
395 )
396 return repo[node].rev()
396 return repo[node].rev()
397
397
398
398
399 def desthistedit(ui, repo):
399 def desthistedit(ui, repo):
400 """Default base revision to edit for `hg histedit`."""
400 """Default base revision to edit for `hg histedit`."""
401 default = ui.config(b'histedit', b'defaultrev')
401 default = ui.config(b'histedit', b'defaultrev')
402
402
403 if default is None:
403 if default is None:
404 revs = stack.getstack(repo)
404 revs = stack.getstack(repo)
405 elif default:
405 elif default:
406 revs = scmutil.revrange(repo, [default])
406 revs = scmutil.revrange(repo, [default])
407 else:
407 else:
408 raise error.Abort(
408 raise error.ConfigError(
409 _(b"config option histedit.defaultrev can't be empty")
409 _(b"config option histedit.defaultrev can't be empty")
410 )
410 )
411
411
412 if revs:
412 if revs:
413 # Take the first revision of the revset as the root
413 # Take the first revision of the revset as the root
414 return revs.min()
414 return revs.min()
415
415
416 return None
416 return None
417
417
418
418
419 def stackbase(ui, repo):
419 def stackbase(ui, repo):
420 revs = stack.getstack(repo)
420 revs = stack.getstack(repo)
421 return revs.first() if revs else None
421 return revs.first() if revs else None
422
422
423
423
424 def _statusotherbook(ui, repo):
424 def _statusotherbook(ui, repo):
425 bmheads = bookmarks.headsforactive(repo)
425 bmheads = bookmarks.headsforactive(repo)
426 curhead = repo._bookmarks[repo._activebookmark]
426 curhead = repo._bookmarks[repo._activebookmark]
427 if repo.revs(b'%n and parents()', curhead):
427 if repo.revs(b'%n and parents()', curhead):
428 # we are on the active bookmark
428 # we are on the active bookmark
429 bmheads = [b for b in bmheads if curhead != b]
429 bmheads = [b for b in bmheads if curhead != b]
430 if bmheads:
430 if bmheads:
431 msg = _(b'%i other divergent bookmarks for "%s"\n')
431 msg = _(b'%i other divergent bookmarks for "%s"\n')
432 ui.status(msg % (len(bmheads), repo._activebookmark))
432 ui.status(msg % (len(bmheads), repo._activebookmark))
433
433
434
434
435 def _statusotherbranchheads(ui, repo):
435 def _statusotherbranchheads(ui, repo):
436 currentbranch = repo.dirstate.branch()
436 currentbranch = repo.dirstate.branch()
437 allheads = repo.branchheads(currentbranch, closed=True)
437 allheads = repo.branchheads(currentbranch, closed=True)
438 heads = repo.branchheads(currentbranch)
438 heads = repo.branchheads(currentbranch)
439 if repo.revs(b'%ln and parents()', allheads):
439 if repo.revs(b'%ln and parents()', allheads):
440 # we are on a head, even though it might be closed
440 # we are on a head, even though it might be closed
441 #
441 #
442 # on closed otherheads
442 # on closed otherheads
443 # ========= ==========
443 # ========= ==========
444 # o 0 all heads for current branch are closed
444 # o 0 all heads for current branch are closed
445 # N only descendant branch heads are closed
445 # N only descendant branch heads are closed
446 # x 0 there is only one non-closed branch head
446 # x 0 there is only one non-closed branch head
447 # N there are some non-closed branch heads
447 # N there are some non-closed branch heads
448 # ========= ==========
448 # ========= ==========
449 otherheads = repo.revs(b'%ln - parents()', heads)
449 otherheads = repo.revs(b'%ln - parents()', heads)
450 if repo[b'.'].closesbranch():
450 if repo[b'.'].closesbranch():
451 ui.warn(
451 ui.warn(
452 _(
452 _(
453 b'no open descendant heads on branch "%s", '
453 b'no open descendant heads on branch "%s", '
454 b'updating to a closed head\n'
454 b'updating to a closed head\n'
455 )
455 )
456 % currentbranch
456 % currentbranch
457 )
457 )
458 if otherheads:
458 if otherheads:
459 ui.warn(
459 ui.warn(
460 _(
460 _(
461 b"(committing will reopen the head, "
461 b"(committing will reopen the head, "
462 b"use 'hg heads .' to see %i other heads)\n"
462 b"use 'hg heads .' to see %i other heads)\n"
463 )
463 )
464 % (len(otherheads))
464 % (len(otherheads))
465 )
465 )
466 else:
466 else:
467 ui.warn(
467 ui.warn(
468 _(b'(committing will reopen branch "%s")\n') % currentbranch
468 _(b'(committing will reopen branch "%s")\n') % currentbranch
469 )
469 )
470 elif otherheads:
470 elif otherheads:
471 curhead = repo[b'.']
471 curhead = repo[b'.']
472 ui.status(
472 ui.status(
473 _(b'updated to "%s: %s"\n')
473 _(b'updated to "%s: %s"\n')
474 % (curhead, curhead.description().split(b'\n')[0])
474 % (curhead, curhead.description().split(b'\n')[0])
475 )
475 )
476 ui.status(
476 ui.status(
477 _(b'%i other heads for branch "%s"\n')
477 _(b'%i other heads for branch "%s"\n')
478 % (len(otherheads), currentbranch)
478 % (len(otherheads), currentbranch)
479 )
479 )
480
480
481
481
482 def statusotherdests(ui, repo):
482 def statusotherdests(ui, repo):
483 """Print message about other head"""
483 """Print message about other head"""
484 # XXX we should probably include a hint:
484 # XXX we should probably include a hint:
485 # - about what to do
485 # - about what to do
486 # - how to see such heads
486 # - how to see such heads
487 if repo._activebookmark:
487 if repo._activebookmark:
488 _statusotherbook(ui, repo)
488 _statusotherbook(ui, repo)
489 else:
489 else:
490 _statusotherbranchheads(ui, repo)
490 _statusotherbranchheads(ui, repo)
@@ -1,605 +1,605 b''
1 #testcases abortcommand abortflag
1 #testcases abortcommand abortflag
2
2
3 #if abortflag
3 #if abortflag
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [alias]
5 > [alias]
6 > abort = histedit --abort
6 > abort = histedit --abort
7 > EOF
7 > EOF
8 #endif
8 #endif
9
9
10 Test argument handling and various data parsing
10 Test argument handling and various data parsing
11 ==================================================
11 ==================================================
12
12
13
13
14 Enable extensions used by this test.
14 Enable extensions used by this test.
15 $ cat >>$HGRCPATH <<EOF
15 $ cat >>$HGRCPATH <<EOF
16 > [extensions]
16 > [extensions]
17 > histedit=
17 > histedit=
18 > EOF
18 > EOF
19
19
20 Repo setup.
20 Repo setup.
21 $ hg init foo
21 $ hg init foo
22 $ cd foo
22 $ cd foo
23 $ echo alpha >> alpha
23 $ echo alpha >> alpha
24 $ hg addr
24 $ hg addr
25 adding alpha
25 adding alpha
26 $ hg ci -m one
26 $ hg ci -m one
27 $ echo alpha >> alpha
27 $ echo alpha >> alpha
28 $ hg ci -m two
28 $ hg ci -m two
29 $ echo alpha >> alpha
29 $ echo alpha >> alpha
30 $ hg ci -m three
30 $ hg ci -m three
31 $ echo alpha >> alpha
31 $ echo alpha >> alpha
32 $ hg ci -m four
32 $ hg ci -m four
33 $ echo alpha >> alpha
33 $ echo alpha >> alpha
34 $ hg ci -m five
34 $ hg ci -m five
35
35
36 $ hg log --style compact --graph
36 $ hg log --style compact --graph
37 @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
37 @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
38 | five
38 | five
39 |
39 |
40 o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
40 o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
41 | four
41 | four
42 |
42 |
43 o 2 eb57da33312f 1970-01-01 00:00 +0000 test
43 o 2 eb57da33312f 1970-01-01 00:00 +0000 test
44 | three
44 | three
45 |
45 |
46 o 1 579e40513370 1970-01-01 00:00 +0000 test
46 o 1 579e40513370 1970-01-01 00:00 +0000 test
47 | two
47 | two
48 |
48 |
49 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
49 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
50 one
50 one
51
51
52
52
53 histedit --continue/--abort with no existing state
53 histedit --continue/--abort with no existing state
54 --------------------------------------------------
54 --------------------------------------------------
55
55
56 $ hg histedit --continue
56 $ hg histedit --continue
57 abort: no histedit in progress
57 abort: no histedit in progress
58 [20]
58 [20]
59 $ hg abort
59 $ hg abort
60 abort: no histedit in progress (abortflag !)
60 abort: no histedit in progress (abortflag !)
61 abort: no operation in progress (abortcommand !)
61 abort: no operation in progress (abortcommand !)
62 [20]
62 [20]
63
63
64 Run a dummy edit to make sure we get tip^^ correctly via revsingle.
64 Run a dummy edit to make sure we get tip^^ correctly via revsingle.
65 --------------------------------------------------------------------
65 --------------------------------------------------------------------
66
66
67 $ HGEDITOR=cat hg histedit "tip^^"
67 $ HGEDITOR=cat hg histedit "tip^^"
68 pick eb57da33312f 2 three
68 pick eb57da33312f 2 three
69 pick c8e68270e35a 3 four
69 pick c8e68270e35a 3 four
70 pick 08d98a8350f3 4 five
70 pick 08d98a8350f3 4 five
71
71
72 # Edit history between eb57da33312f and 08d98a8350f3
72 # Edit history between eb57da33312f and 08d98a8350f3
73 #
73 #
74 # Commits are listed from least to most recent
74 # Commits are listed from least to most recent
75 #
75 #
76 # You can reorder changesets by reordering the lines
76 # You can reorder changesets by reordering the lines
77 #
77 #
78 # Commands:
78 # Commands:
79 #
79 #
80 # e, edit = use commit, but stop for amending
80 # e, edit = use commit, but stop for amending
81 # m, mess = edit commit message without changing commit content
81 # m, mess = edit commit message without changing commit content
82 # p, pick = use commit
82 # p, pick = use commit
83 # b, base = checkout changeset and apply further changesets from there
83 # b, base = checkout changeset and apply further changesets from there
84 # d, drop = remove commit from history
84 # d, drop = remove commit from history
85 # f, fold = use commit, but combine it with the one above
85 # f, fold = use commit, but combine it with the one above
86 # r, roll = like fold, but discard this commit's description and date
86 # r, roll = like fold, but discard this commit's description and date
87 #
87 #
88
88
89 Run on a revision not ancestors of the current working directory.
89 Run on a revision not ancestors of the current working directory.
90 --------------------------------------------------------------------
90 --------------------------------------------------------------------
91
91
92 $ hg up 2
92 $ hg up 2
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 $ hg histedit -r 4
94 $ hg histedit -r 4
95 abort: 08d98a8350f3 is not an ancestor of working directory
95 abort: 08d98a8350f3 is not an ancestor of working directory
96 [255]
96 [255]
97 $ hg up --quiet
97 $ hg up --quiet
98
98
99
99
100 Test that we pick the minimum of a revrange
100 Test that we pick the minimum of a revrange
101 ---------------------------------------
101 ---------------------------------------
102
102
103 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
103 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
104 > pick eb57da33312f 2 three
104 > pick eb57da33312f 2 three
105 > pick c8e68270e35a 3 four
105 > pick c8e68270e35a 3 four
106 > pick 08d98a8350f3 4 five
106 > pick 08d98a8350f3 4 five
107 > EOF
107 > EOF
108 $ hg up --quiet
108 $ hg up --quiet
109
109
110 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
110 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
111 > pick eb57da33312f 2 three
111 > pick eb57da33312f 2 three
112 > pick c8e68270e35a 3 four
112 > pick c8e68270e35a 3 four
113 > pick 08d98a8350f3 4 five
113 > pick 08d98a8350f3 4 five
114 > EOF
114 > EOF
115 $ hg up --quiet
115 $ hg up --quiet
116
116
117 Test config specified default
117 Test config specified default
118 -----------------------------
118 -----------------------------
119
119
120 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
120 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
121 > pick c8e68270e35a 3 four
121 > pick c8e68270e35a 3 four
122 > pick 08d98a8350f3 4 five
122 > pick 08d98a8350f3 4 five
123 > EOF
123 > EOF
124
124
125 Test invalid config default
125 Test invalid config default
126 ---------------------------
126 ---------------------------
127
127
128 $ hg histedit --config "histedit.defaultrev="
128 $ hg histedit --config "histedit.defaultrev="
129 abort: config option histedit.defaultrev can't be empty
129 abort: config option histedit.defaultrev can't be empty
130 [255]
130 [30]
131
131
132 Run on a revision not descendants of the initial parent
132 Run on a revision not descendants of the initial parent
133 --------------------------------------------------------------------
133 --------------------------------------------------------------------
134
134
135 Test the message shown for inconsistent histedit state, which may be
135 Test the message shown for inconsistent histedit state, which may be
136 created (and forgotten) by Mercurial earlier than 2.7. This emulates
136 created (and forgotten) by Mercurial earlier than 2.7. This emulates
137 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
137 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
138 temporarily.
138 temporarily.
139
139
140 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
140 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
141 @ 4 08d9 five
141 @ 4 08d9 five
142 |
142 |
143 o 3 c8e6 four
143 o 3 c8e6 four
144 |
144 |
145 o 2 eb57 three
145 o 2 eb57 three
146 |
146 |
147 ~
147 ~
148 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
148 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
149 > edit 08d98a8350f3 4 five
149 > edit 08d98a8350f3 4 five
150 > EOF
150 > EOF
151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
151 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 Editing (08d98a8350f3), you may commit or record as needed now.
152 Editing (08d98a8350f3), you may commit or record as needed now.
153 (hg histedit --continue to resume)
153 (hg histedit --continue to resume)
154 [240]
154 [240]
155
155
156 $ hg graft --continue
156 $ hg graft --continue
157 abort: no graft in progress
157 abort: no graft in progress
158 (continue: hg histedit --continue)
158 (continue: hg histedit --continue)
159 [20]
159 [20]
160
160
161 $ mv .hg/histedit-state .hg/histedit-state.back
161 $ mv .hg/histedit-state .hg/histedit-state.back
162 $ hg update --quiet --clean 2
162 $ hg update --quiet --clean 2
163 $ echo alpha >> alpha
163 $ echo alpha >> alpha
164 $ mv .hg/histedit-state.back .hg/histedit-state
164 $ mv .hg/histedit-state.back .hg/histedit-state
165
165
166 $ hg histedit --continue
166 $ hg histedit --continue
167 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
167 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
168 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
168 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
169 @ 4 f5ed five
169 @ 4 f5ed five
170 |
170 |
171 | o 3 c8e6 four
171 | o 3 c8e6 four
172 |/
172 |/
173 o 2 eb57 three
173 o 2 eb57 three
174 |
174 |
175 ~
175 ~
176
176
177 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
177 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-histedit.hg
178 $ hg strip -q -r f5ed --config extensions.strip=
178 $ hg strip -q -r f5ed --config extensions.strip=
179 $ hg up -q 08d98a8350f3
179 $ hg up -q 08d98a8350f3
180
180
181 Test that missing revisions are detected
181 Test that missing revisions are detected
182 ---------------------------------------
182 ---------------------------------------
183
183
184 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
184 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
185 > pick eb57da33312f 2 three
185 > pick eb57da33312f 2 three
186 > pick 08d98a8350f3 4 five
186 > pick 08d98a8350f3 4 five
187 > EOF
187 > EOF
188 hg: parse error: missing rules for changeset c8e68270e35a
188 hg: parse error: missing rules for changeset c8e68270e35a
189 (use "drop c8e68270e35a" to discard, see also: 'hg help -e histedit.config')
189 (use "drop c8e68270e35a" to discard, see also: 'hg help -e histedit.config')
190 [255]
190 [255]
191
191
192 Test that extra revisions are detected
192 Test that extra revisions are detected
193 ---------------------------------------
193 ---------------------------------------
194
194
195 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
195 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
196 > pick 6058cbb6cfd7 0 one
196 > pick 6058cbb6cfd7 0 one
197 > pick c8e68270e35a 3 four
197 > pick c8e68270e35a 3 four
198 > pick 08d98a8350f3 4 five
198 > pick 08d98a8350f3 4 five
199 > EOF
199 > EOF
200 hg: parse error: pick "6058cbb6cfd7" changeset was not a candidate
200 hg: parse error: pick "6058cbb6cfd7" changeset was not a candidate
201 (only use listed changesets)
201 (only use listed changesets)
202 [255]
202 [255]
203
203
204 Test malformed line
204 Test malformed line
205 ---------------------------------------
205 ---------------------------------------
206
206
207 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
207 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
208 > pickeb57da33312f2three
208 > pickeb57da33312f2three
209 > pick c8e68270e35a 3 four
209 > pick c8e68270e35a 3 four
210 > pick 08d98a8350f3 4 five
210 > pick 08d98a8350f3 4 five
211 > EOF
211 > EOF
212 hg: parse error: malformed line "pickeb57da33312f2three"
212 hg: parse error: malformed line "pickeb57da33312f2three"
213 [255]
213 [255]
214
214
215 Test unknown changeset
215 Test unknown changeset
216 ---------------------------------------
216 ---------------------------------------
217
217
218 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
218 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
219 > pick 0123456789ab 2 three
219 > pick 0123456789ab 2 three
220 > pick c8e68270e35a 3 four
220 > pick c8e68270e35a 3 four
221 > pick 08d98a8350f3 4 five
221 > pick 08d98a8350f3 4 five
222 > EOF
222 > EOF
223 hg: parse error: unknown changeset 0123456789ab listed
223 hg: parse error: unknown changeset 0123456789ab listed
224 [255]
224 [255]
225
225
226 Test unknown command
226 Test unknown command
227 ---------------------------------------
227 ---------------------------------------
228
228
229 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
229 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
230 > coin eb57da33312f 2 three
230 > coin eb57da33312f 2 three
231 > pick c8e68270e35a 3 four
231 > pick c8e68270e35a 3 four
232 > pick 08d98a8350f3 4 five
232 > pick 08d98a8350f3 4 five
233 > EOF
233 > EOF
234 hg: parse error: unknown action "coin"
234 hg: parse error: unknown action "coin"
235 [255]
235 [255]
236
236
237 Test duplicated changeset
237 Test duplicated changeset
238 ---------------------------------------
238 ---------------------------------------
239
239
240 So one is missing and one appear twice.
240 So one is missing and one appear twice.
241
241
242 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
242 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
243 > pick eb57da33312f 2 three
243 > pick eb57da33312f 2 three
244 > pick eb57da33312f 2 three
244 > pick eb57da33312f 2 three
245 > pick 08d98a8350f3 4 five
245 > pick 08d98a8350f3 4 five
246 > EOF
246 > EOF
247 hg: parse error: duplicated command for changeset eb57da33312f
247 hg: parse error: duplicated command for changeset eb57da33312f
248 [255]
248 [255]
249
249
250 Test bogus rev
250 Test bogus rev
251 ---------------------------------------
251 ---------------------------------------
252
252
253 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
253 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
254 > pick eb57da33312f 2 three
254 > pick eb57da33312f 2 three
255 > pick 0u98
255 > pick 0u98
256 > pick 08d98a8350f3 4 five
256 > pick 08d98a8350f3 4 five
257 > EOF
257 > EOF
258 hg: parse error: invalid changeset 0u98
258 hg: parse error: invalid changeset 0u98
259 [255]
259 [255]
260
260
261 Test short version of command
261 Test short version of command
262 ---------------------------------------
262 ---------------------------------------
263
263
264 Note: we use varying amounts of white space between command name and changeset
264 Note: we use varying amounts of white space between command name and changeset
265 short hash. This tests issue3893.
265 short hash. This tests issue3893.
266
266
267 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
267 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
268 > pick eb57da33312f 2 three
268 > pick eb57da33312f 2 three
269 > p c8e68270e35a 3 four
269 > p c8e68270e35a 3 four
270 > f 08d98a8350f3 4 five
270 > f 08d98a8350f3 4 five
271 > EOF
271 > EOF
272 four
272 four
273 ***
273 ***
274 five
274 five
275
275
276
276
277
277
278 HG: Enter commit message. Lines beginning with 'HG:' are removed.
278 HG: Enter commit message. Lines beginning with 'HG:' are removed.
279 HG: Leave message empty to abort commit.
279 HG: Leave message empty to abort commit.
280 HG: --
280 HG: --
281 HG: user: test
281 HG: user: test
282 HG: branch 'default'
282 HG: branch 'default'
283 HG: changed alpha
283 HG: changed alpha
284 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/c8e68270e35a-63d8b8d8-histedit.hg
284 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/c8e68270e35a-63d8b8d8-histedit.hg
285
285
286 $ hg update -q 2
286 $ hg update -q 2
287 $ echo x > x
287 $ echo x > x
288 $ hg add x
288 $ hg add x
289 $ hg commit -m'x' x
289 $ hg commit -m'x' x
290 created new head
290 created new head
291 $ hg histedit -r 'heads(all())'
291 $ hg histedit -r 'heads(all())'
292 abort: The specified revisions must have exactly one common root
292 abort: The specified revisions must have exactly one common root
293 [255]
293 [255]
294
294
295 Test that trimming description using multi-byte characters
295 Test that trimming description using multi-byte characters
296 --------------------------------------------------------------------
296 --------------------------------------------------------------------
297
297
298 $ "$PYTHON" <<EOF
298 $ "$PYTHON" <<EOF
299 > fp = open('logfile', 'wb')
299 > fp = open('logfile', 'wb')
300 > fp.write(b'12345678901234567890123456789012345678901234567890' +
300 > fp.write(b'12345678901234567890123456789012345678901234567890' +
301 > b'12345') # there are 5 more columns for 80 columns
301 > b'12345') # there are 5 more columns for 80 columns
302 >
302 >
303 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
303 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
304 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
304 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
305 >
305 >
306 > fp.close()
306 > fp.close()
307 > EOF
307 > EOF
308 $ echo xx >> x
308 $ echo xx >> x
309 $ hg --encoding utf-8 commit --logfile logfile
309 $ hg --encoding utf-8 commit --logfile logfile
310
310
311 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
311 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
312 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
312 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
313
313
314 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
314 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
315 #
315 #
316 # Commits are listed from least to most recent
316 # Commits are listed from least to most recent
317 #
317 #
318 # You can reorder changesets by reordering the lines
318 # You can reorder changesets by reordering the lines
319 #
319 #
320 # Commands:
320 # Commands:
321 #
321 #
322 # e, edit = use commit, but stop for amending
322 # e, edit = use commit, but stop for amending
323 # m, mess = edit commit message without changing commit content
323 # m, mess = edit commit message without changing commit content
324 # p, pick = use commit
324 # p, pick = use commit
325 # b, base = checkout changeset and apply further changesets from there
325 # b, base = checkout changeset and apply further changesets from there
326 # d, drop = remove commit from history
326 # d, drop = remove commit from history
327 # f, fold = use commit, but combine it with the one above
327 # f, fold = use commit, but combine it with the one above
328 # r, roll = like fold, but discard this commit's description and date
328 # r, roll = like fold, but discard this commit's description and date
329 #
329 #
330
330
331 Test --continue with --keep
331 Test --continue with --keep
332
332
333 $ hg strip -q -r . --config extensions.strip=
333 $ hg strip -q -r . --config extensions.strip=
334 $ hg histedit '.^' -q --keep --commands - << EOF
334 $ hg histedit '.^' -q --keep --commands - << EOF
335 > edit eb57da33312f 2 three
335 > edit eb57da33312f 2 three
336 > pick f3cfcca30c44 4 x
336 > pick f3cfcca30c44 4 x
337 > EOF
337 > EOF
338 Editing (eb57da33312f), you may commit or record as needed now.
338 Editing (eb57da33312f), you may commit or record as needed now.
339 (hg histedit --continue to resume)
339 (hg histedit --continue to resume)
340 [240]
340 [240]
341 $ echo edit >> alpha
341 $ echo edit >> alpha
342 $ hg histedit -q --continue
342 $ hg histedit -q --continue
343 $ hg log -G -T '{rev}:{node|short} {desc}'
343 $ hg log -G -T '{rev}:{node|short} {desc}'
344 @ 6:8fda0c726bf2 x
344 @ 6:8fda0c726bf2 x
345 |
345 |
346 o 5:63379946892c three
346 o 5:63379946892c three
347 |
347 |
348 | o 4:f3cfcca30c44 x
348 | o 4:f3cfcca30c44 x
349 | |
349 | |
350 | | o 3:2a30f3cfee78 four
350 | | o 3:2a30f3cfee78 four
351 | |/ ***
351 | |/ ***
352 | | five
352 | | five
353 | o 2:eb57da33312f three
353 | o 2:eb57da33312f three
354 |/
354 |/
355 o 1:579e40513370 two
355 o 1:579e40513370 two
356 |
356 |
357 o 0:6058cbb6cfd7 one
357 o 0:6058cbb6cfd7 one
358
358
359
359
360 Test that abort fails gracefully on exception
360 Test that abort fails gracefully on exception
361 ----------------------------------------------
361 ----------------------------------------------
362 $ hg histedit . -q --commands - << EOF
362 $ hg histedit . -q --commands - << EOF
363 > edit 8fda0c726bf2 6 x
363 > edit 8fda0c726bf2 6 x
364 > EOF
364 > EOF
365 Editing (8fda0c726bf2), you may commit or record as needed now.
365 Editing (8fda0c726bf2), you may commit or record as needed now.
366 (hg histedit --continue to resume)
366 (hg histedit --continue to resume)
367 [240]
367 [240]
368 Corrupt histedit state file
368 Corrupt histedit state file
369 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
369 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
370 $ mv ../corrupt-histedit .hg/histedit-state
370 $ mv ../corrupt-histedit .hg/histedit-state
371 $ hg abort
371 $ hg abort
372 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
372 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
373 abort: $TESTTMP/foo/.hg/strip-backup/*-histedit.hg: $ENOENT$ (glob) (windows !)
373 abort: $TESTTMP/foo/.hg/strip-backup/*-histedit.hg: $ENOENT$ (glob) (windows !)
374 abort: $ENOENT$: '$TESTTMP/foo/.hg/strip-backup/*-histedit.hg' (glob) (no-windows !)
374 abort: $ENOENT$: '$TESTTMP/foo/.hg/strip-backup/*-histedit.hg' (glob) (no-windows !)
375 [255]
375 [255]
376 Histedit state has been exited
376 Histedit state has been exited
377 $ hg summary -q
377 $ hg summary -q
378 parent: 5:63379946892c
378 parent: 5:63379946892c
379 commit: 1 added, 1 unknown (new branch head)
379 commit: 1 added, 1 unknown (new branch head)
380 update: 4 new changesets (update)
380 update: 4 new changesets (update)
381
381
382 $ cd ..
382 $ cd ..
383
383
384 Set up default base revision tests
384 Set up default base revision tests
385
385
386 $ hg init defaultbase
386 $ hg init defaultbase
387 $ cd defaultbase
387 $ cd defaultbase
388 $ touch foo
388 $ touch foo
389 $ hg -q commit -A -m root
389 $ hg -q commit -A -m root
390 $ echo 1 > foo
390 $ echo 1 > foo
391 $ hg commit -m 'public 1'
391 $ hg commit -m 'public 1'
392 $ hg phase --force --public -r .
392 $ hg phase --force --public -r .
393 $ echo 2 > foo
393 $ echo 2 > foo
394 $ hg commit -m 'draft after public'
394 $ hg commit -m 'draft after public'
395 $ hg -q up -r 1
395 $ hg -q up -r 1
396 $ echo 3 > foo
396 $ echo 3 > foo
397 $ hg commit -m 'head 1 public'
397 $ hg commit -m 'head 1 public'
398 created new head
398 created new head
399 $ hg phase --force --public -r .
399 $ hg phase --force --public -r .
400 $ echo 4 > foo
400 $ echo 4 > foo
401 $ hg commit -m 'head 1 draft 1'
401 $ hg commit -m 'head 1 draft 1'
402 $ echo 5 > foo
402 $ echo 5 > foo
403 $ hg commit -m 'head 1 draft 2'
403 $ hg commit -m 'head 1 draft 2'
404 $ hg -q up -r 2
404 $ hg -q up -r 2
405 $ echo 6 > foo
405 $ echo 6 > foo
406 $ hg commit -m 'head 2 commit 1'
406 $ hg commit -m 'head 2 commit 1'
407 $ echo 7 > foo
407 $ echo 7 > foo
408 $ hg commit -m 'head 2 commit 2'
408 $ hg commit -m 'head 2 commit 2'
409 $ hg -q up -r 2
409 $ hg -q up -r 2
410 $ echo 8 > foo
410 $ echo 8 > foo
411 $ hg commit -m 'head 3'
411 $ hg commit -m 'head 3'
412 created new head
412 created new head
413 $ hg -q up -r 2
413 $ hg -q up -r 2
414 $ echo 9 > foo
414 $ echo 9 > foo
415 $ hg commit -m 'head 4'
415 $ hg commit -m 'head 4'
416 created new head
416 created new head
417 $ hg merge --tool :local -r 8
417 $ hg merge --tool :local -r 8
418 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
418 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
419 (branch merge, don't forget to commit)
419 (branch merge, don't forget to commit)
420 $ hg commit -m 'merge head 3 into head 4'
420 $ hg commit -m 'merge head 3 into head 4'
421 $ echo 11 > foo
421 $ echo 11 > foo
422 $ hg commit -m 'commit 1 after merge'
422 $ hg commit -m 'commit 1 after merge'
423 $ echo 12 > foo
423 $ echo 12 > foo
424 $ hg commit -m 'commit 2 after merge'
424 $ hg commit -m 'commit 2 after merge'
425
425
426 $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
426 $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
427 @ 12:8cde254db839 draft commit 2 after merge
427 @ 12:8cde254db839 draft commit 2 after merge
428 |
428 |
429 o 11:6f2f0241f119 draft commit 1 after merge
429 o 11:6f2f0241f119 draft commit 1 after merge
430 |
430 |
431 o 10:90506cc76b00 draft merge head 3 into head 4
431 o 10:90506cc76b00 draft merge head 3 into head 4
432 |\
432 |\
433 | o 9:f8607a373a97 draft head 4
433 | o 9:f8607a373a97 draft head 4
434 | |
434 | |
435 o | 8:0da92be05148 draft head 3
435 o | 8:0da92be05148 draft head 3
436 |/
436 |/
437 | o 7:4c35cdf97d5e draft head 2 commit 2
437 | o 7:4c35cdf97d5e draft head 2 commit 2
438 | |
438 | |
439 | o 6:931820154288 draft head 2 commit 1
439 | o 6:931820154288 draft head 2 commit 1
440 |/
440 |/
441 | o 5:8cdc02b9bc63 draft head 1 draft 2
441 | o 5:8cdc02b9bc63 draft head 1 draft 2
442 | |
442 | |
443 | o 4:463b8c0d2973 draft head 1 draft 1
443 | o 4:463b8c0d2973 draft head 1 draft 1
444 | |
444 | |
445 | o 3:23a0c4eefcbf public head 1 public
445 | o 3:23a0c4eefcbf public head 1 public
446 | |
446 | |
447 o | 2:4117331c3abb draft draft after public
447 o | 2:4117331c3abb draft draft after public
448 |/
448 |/
449 o 1:4426d359ea59 public public 1
449 o 1:4426d359ea59 public public 1
450 |
450 |
451 o 0:54136a8ddf32 public root
451 o 0:54136a8ddf32 public root
452
452
453
453
454 Default base revision should stop at public changesets
454 Default base revision should stop at public changesets
455
455
456 $ hg -q up 8cdc02b9bc63
456 $ hg -q up 8cdc02b9bc63
457 $ hg histedit --commands - <<EOF
457 $ hg histedit --commands - <<EOF
458 > pick 463b8c0d2973
458 > pick 463b8c0d2973
459 > pick 8cdc02b9bc63
459 > pick 8cdc02b9bc63
460 > EOF
460 > EOF
461
461
462 Default base revision should stop at branchpoint
462 Default base revision should stop at branchpoint
463
463
464 $ hg -q up 4c35cdf97d5e
464 $ hg -q up 4c35cdf97d5e
465 $ hg histedit --commands - <<EOF
465 $ hg histedit --commands - <<EOF
466 > pick 931820154288
466 > pick 931820154288
467 > pick 4c35cdf97d5e
467 > pick 4c35cdf97d5e
468 > EOF
468 > EOF
469
469
470 Default base revision should stop at merge commit
470 Default base revision should stop at merge commit
471
471
472 $ hg -q up 8cde254db839
472 $ hg -q up 8cde254db839
473 $ hg histedit --commands - <<EOF
473 $ hg histedit --commands - <<EOF
474 > pick 6f2f0241f119
474 > pick 6f2f0241f119
475 > pick 8cde254db839
475 > pick 8cde254db839
476 > EOF
476 > EOF
477
477
478 commit --amend should abort if histedit is in progress
478 commit --amend should abort if histedit is in progress
479 (issue4800) and markers are not being created.
479 (issue4800) and markers are not being created.
480 Eventually, histedit could perhaps look at `source` extra,
480 Eventually, histedit could perhaps look at `source` extra,
481 in which case this test should be revisited.
481 in which case this test should be revisited.
482
482
483 $ hg -q up 8cde254db839
483 $ hg -q up 8cde254db839
484 $ hg histedit 6f2f0241f119 --commands - <<EOF
484 $ hg histedit 6f2f0241f119 --commands - <<EOF
485 > pick 8cde254db839
485 > pick 8cde254db839
486 > edit 6f2f0241f119
486 > edit 6f2f0241f119
487 > EOF
487 > EOF
488 merging foo
488 merging foo
489 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
489 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
490 Fix up the change (pick 8cde254db839)
490 Fix up the change (pick 8cde254db839)
491 (hg histedit --continue to resume)
491 (hg histedit --continue to resume)
492 [240]
492 [240]
493 $ hg resolve -m --all
493 $ hg resolve -m --all
494 (no more unresolved files)
494 (no more unresolved files)
495 continue: hg histedit --continue
495 continue: hg histedit --continue
496 $ hg histedit --cont
496 $ hg histedit --cont
497 merging foo
497 merging foo
498 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
498 warning: conflicts while merging foo! (edit, then use 'hg resolve --mark')
499 Editing (6f2f0241f119), you may commit or record as needed now.
499 Editing (6f2f0241f119), you may commit or record as needed now.
500 (hg histedit --continue to resume)
500 (hg histedit --continue to resume)
501 [240]
501 [240]
502 $ hg resolve -m --all
502 $ hg resolve -m --all
503 (no more unresolved files)
503 (no more unresolved files)
504 continue: hg histedit --continue
504 continue: hg histedit --continue
505 $ hg commit --amend -m 'reject this fold'
505 $ hg commit --amend -m 'reject this fold'
506 abort: histedit in progress
506 abort: histedit in progress
507 (use 'hg histedit --continue' or 'hg histedit --abort')
507 (use 'hg histedit --continue' or 'hg histedit --abort')
508 [20]
508 [20]
509
509
510 With markers enabled, histedit does not get confused, and
510 With markers enabled, histedit does not get confused, and
511 amend should not be blocked by the ongoing histedit.
511 amend should not be blocked by the ongoing histedit.
512
512
513 $ cat >>$HGRCPATH <<EOF
513 $ cat >>$HGRCPATH <<EOF
514 > [experimental]
514 > [experimental]
515 > evolution.createmarkers=True
515 > evolution.createmarkers=True
516 > evolution.allowunstable=True
516 > evolution.allowunstable=True
517 > EOF
517 > EOF
518 $ hg commit --amend -m 'allow this fold'
518 $ hg commit --amend -m 'allow this fold'
519 $ hg histedit --continue
519 $ hg histedit --continue
520
520
521 $ cd ..
521 $ cd ..
522
522
523 Test autoverb feature
523 Test autoverb feature
524
524
525 $ hg init autoverb
525 $ hg init autoverb
526 $ cd autoverb
526 $ cd autoverb
527 $ echo alpha >> alpha
527 $ echo alpha >> alpha
528 $ hg ci -qAm one
528 $ hg ci -qAm one
529 $ echo alpha >> alpha
529 $ echo alpha >> alpha
530 $ hg ci -qm two
530 $ hg ci -qm two
531 $ echo beta >> beta
531 $ echo beta >> beta
532 $ hg ci -qAm "roll! one"
532 $ hg ci -qAm "roll! one"
533
533
534 $ hg log --style compact --graph
534 $ hg log --style compact --graph
535 @ 2[tip] 4f34d0f8b5fa 1970-01-01 00:00 +0000 test
535 @ 2[tip] 4f34d0f8b5fa 1970-01-01 00:00 +0000 test
536 | roll! one
536 | roll! one
537 |
537 |
538 o 1 579e40513370 1970-01-01 00:00 +0000 test
538 o 1 579e40513370 1970-01-01 00:00 +0000 test
539 | two
539 | two
540 |
540 |
541 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
541 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
542 one
542 one
543
543
544
544
545 Check that 'roll' is selected by default
545 Check that 'roll' is selected by default
546
546
547 $ HGEDITOR=cat hg histedit 0 --config experimental.histedit.autoverb=True
547 $ HGEDITOR=cat hg histedit 0 --config experimental.histedit.autoverb=True
548 pick 6058cbb6cfd7 0 one
548 pick 6058cbb6cfd7 0 one
549 roll 4f34d0f8b5fa 2 roll! one
549 roll 4f34d0f8b5fa 2 roll! one
550 pick 579e40513370 1 two
550 pick 579e40513370 1 two
551
551
552 # Edit history between 6058cbb6cfd7 and 4f34d0f8b5fa
552 # Edit history between 6058cbb6cfd7 and 4f34d0f8b5fa
553 #
553 #
554 # Commits are listed from least to most recent
554 # Commits are listed from least to most recent
555 #
555 #
556 # You can reorder changesets by reordering the lines
556 # You can reorder changesets by reordering the lines
557 #
557 #
558 # Commands:
558 # Commands:
559 #
559 #
560 # e, edit = use commit, but stop for amending
560 # e, edit = use commit, but stop for amending
561 # m, mess = edit commit message without changing commit content
561 # m, mess = edit commit message without changing commit content
562 # p, pick = use commit
562 # p, pick = use commit
563 # b, base = checkout changeset and apply further changesets from there
563 # b, base = checkout changeset and apply further changesets from there
564 # d, drop = remove commit from history
564 # d, drop = remove commit from history
565 # f, fold = use commit, but combine it with the one above
565 # f, fold = use commit, but combine it with the one above
566 # r, roll = like fold, but discard this commit's description and date
566 # r, roll = like fold, but discard this commit's description and date
567 #
567 #
568
568
569 $ cd ..
569 $ cd ..
570
570
571 Check that histedit's commands accept revsets
571 Check that histedit's commands accept revsets
572 $ hg init bar
572 $ hg init bar
573 $ cd bar
573 $ cd bar
574 $ echo w >> a
574 $ echo w >> a
575 $ hg ci -qAm "adds a"
575 $ hg ci -qAm "adds a"
576 $ echo x >> b
576 $ echo x >> b
577 $ hg ci -qAm "adds b"
577 $ hg ci -qAm "adds b"
578 $ echo y >> c
578 $ echo y >> c
579 $ hg ci -qAm "adds c"
579 $ hg ci -qAm "adds c"
580 $ echo z >> d
580 $ echo z >> d
581 $ hg ci -qAm "adds d"
581 $ hg ci -qAm "adds d"
582 $ hg log -G -T '{rev} {desc}\n'
582 $ hg log -G -T '{rev} {desc}\n'
583 @ 3 adds d
583 @ 3 adds d
584 |
584 |
585 o 2 adds c
585 o 2 adds c
586 |
586 |
587 o 1 adds b
587 o 1 adds b
588 |
588 |
589 o 0 adds a
589 o 0 adds a
590
590
591 $ HGEDITOR=cat hg histedit "2" --commands - << EOF
591 $ HGEDITOR=cat hg histedit "2" --commands - << EOF
592 > base -4 adds c
592 > base -4 adds c
593 > pick 2 adds c
593 > pick 2 adds c
594 > pick tip adds d
594 > pick tip adds d
595 > EOF
595 > EOF
596 $ hg log -G -T '{rev} {desc}\n'
596 $ hg log -G -T '{rev} {desc}\n'
597 @ 5 adds d
597 @ 5 adds d
598 |
598 |
599 o 4 adds c
599 o 4 adds c
600 |
600 |
601 | o 1 adds b
601 | o 1 adds b
602 |/
602 |/
603 o 0 adds a
603 o 0 adds a
604
604
605
605
General Comments 0
You need to be logged in to leave comments. Login now