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