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