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