##// END OF EJS Templates
histedit: omit useless message from update (_histedit)...
timeless -
r27406:11be6b7f default
parent child Browse files
Show More
@@ -1,1414 +1,1414 b''
1 1 # histedit.py - interactive history editing for mercurial
2 2 #
3 3 # Copyright 2009 Augie Fackler <raf@durin42.com>
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 """interactive history editing
8 8
9 9 With this extension installed, Mercurial gains one new command: histedit. Usage
10 10 is as follows, assuming the following history::
11 11
12 12 @ 3[tip] 7c2fd3b9020c 2009-04-27 18:04 -0500 durin42
13 13 | Add delta
14 14 |
15 15 o 2 030b686bedc4 2009-04-27 18:04 -0500 durin42
16 16 | Add gamma
17 17 |
18 18 o 1 c561b4e977df 2009-04-27 18:04 -0500 durin42
19 19 | Add beta
20 20 |
21 21 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
22 22 Add alpha
23 23
24 24 If you were to run ``hg histedit c561b4e977df``, you would see the following
25 25 file open in your editor::
26 26
27 27 pick c561b4e977df Add beta
28 28 pick 030b686bedc4 Add gamma
29 29 pick 7c2fd3b9020c Add delta
30 30
31 31 # Edit history between c561b4e977df and 7c2fd3b9020c
32 32 #
33 33 # Commits are listed from least to most recent
34 34 #
35 35 # Commands:
36 36 # p, pick = use commit
37 37 # e, edit = use commit, but stop for amending
38 38 # f, fold = use commit, but combine it with the one above
39 39 # r, roll = like fold, but discard this commit's description
40 40 # d, drop = remove commit from history
41 41 # m, mess = edit commit message without changing commit content
42 42 #
43 43
44 44 In this file, lines beginning with ``#`` are ignored. You must specify a rule
45 45 for each revision in your history. For example, if you had meant to add gamma
46 46 before beta, and then wanted to add delta in the same revision as beta, you
47 47 would reorganize the file to look like this::
48 48
49 49 pick 030b686bedc4 Add gamma
50 50 pick c561b4e977df Add beta
51 51 fold 7c2fd3b9020c Add delta
52 52
53 53 # Edit history between c561b4e977df and 7c2fd3b9020c
54 54 #
55 55 # Commits are listed from least to most recent
56 56 #
57 57 # Commands:
58 58 # p, pick = use commit
59 59 # e, edit = use commit, but stop for amending
60 60 # f, fold = use commit, but combine it with the one above
61 61 # r, roll = like fold, but discard this commit's description
62 62 # d, drop = remove commit from history
63 63 # m, mess = edit commit message without changing commit content
64 64 #
65 65
66 66 At which point you close the editor and ``histedit`` starts working. When you
67 67 specify a ``fold`` operation, ``histedit`` will open an editor when it folds
68 68 those revisions together, offering you a chance to clean up the commit message::
69 69
70 70 Add beta
71 71 ***
72 72 Add delta
73 73
74 74 Edit the commit message to your liking, then close the editor. For
75 75 this example, let's assume that the commit message was changed to
76 76 ``Add beta and delta.`` After histedit has run and had a chance to
77 77 remove any old or temporary revisions it needed, the history looks
78 78 like this::
79 79
80 80 @ 2[tip] 989b4d060121 2009-04-27 18:04 -0500 durin42
81 81 | Add beta and delta.
82 82 |
83 83 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
84 84 | Add gamma
85 85 |
86 86 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
87 87 Add alpha
88 88
89 89 Note that ``histedit`` does *not* remove any revisions (even its own temporary
90 90 ones) until after it has completed all the editing operations, so it will
91 91 probably perform several strip operations when it's done. For the above example,
92 92 it had to run strip twice. Strip can be slow depending on a variety of factors,
93 93 so you might need to be a little patient. You can choose to keep the original
94 94 revisions by passing the ``--keep`` flag.
95 95
96 96 The ``edit`` operation will drop you back to a command prompt,
97 97 allowing you to edit files freely, or even use ``hg record`` to commit
98 98 some changes as a separate commit. When you're done, any remaining
99 99 uncommitted changes will be committed as well. When done, run ``hg
100 100 histedit --continue`` to finish this step. You'll be prompted for a
101 101 new commit message, but the default commit message will be the
102 102 original message for the ``edit`` ed revision.
103 103
104 104 The ``message`` operation will give you a chance to revise a commit
105 105 message without changing the contents. It's a shortcut for doing
106 106 ``edit`` immediately followed by `hg histedit --continue``.
107 107
108 108 If ``histedit`` encounters a conflict when moving a revision (while
109 109 handling ``pick`` or ``fold``), it'll stop in a similar manner to
110 110 ``edit`` with the difference that it won't prompt you for a commit
111 111 message when done. If you decide at this point that you don't like how
112 112 much work it will be to rearrange history, or that you made a mistake,
113 113 you can use ``hg histedit --abort`` to abandon the new changes you
114 114 have made and return to the state before you attempted to edit your
115 115 history.
116 116
117 117 If we clone the histedit-ed example repository above and add four more
118 118 changes, such that we have the following history::
119 119
120 120 @ 6[tip] 038383181893 2009-04-27 18:04 -0500 stefan
121 121 | Add theta
122 122 |
123 123 o 5 140988835471 2009-04-27 18:04 -0500 stefan
124 124 | Add eta
125 125 |
126 126 o 4 122930637314 2009-04-27 18:04 -0500 stefan
127 127 | Add zeta
128 128 |
129 129 o 3 836302820282 2009-04-27 18:04 -0500 stefan
130 130 | Add epsilon
131 131 |
132 132 o 2 989b4d060121 2009-04-27 18:04 -0500 durin42
133 133 | Add beta and delta.
134 134 |
135 135 o 1 081603921c3f 2009-04-27 18:04 -0500 durin42
136 136 | Add gamma
137 137 |
138 138 o 0 d8d2fcd0e319 2009-04-27 18:04 -0500 durin42
139 139 Add alpha
140 140
141 141 If you run ``hg histedit --outgoing`` on the clone then it is the same
142 142 as running ``hg histedit 836302820282``. If you need plan to push to a
143 143 repository that Mercurial does not detect to be related to the source
144 144 repo, you can add a ``--force`` option.
145 145
146 146 Histedit rule lines are truncated to 80 characters by default. You
147 147 can customize this behavior by setting a different length in your
148 148 configuration file::
149 149
150 150 [histedit]
151 151 linelen = 120 # truncate rule lines at 120 characters
152 152
153 153 ``hg histedit`` attempts to automatically choose an appropriate base
154 154 revision to use. To change which base revision is used, define a
155 155 revset in your configuration file::
156 156
157 157 [histedit]
158 158 defaultrev = only(.) & draft()
159 159 """
160 160
161 161 try:
162 162 import cPickle as pickle
163 163 pickle.dump # import now
164 164 except ImportError:
165 165 import pickle
166 166 import errno
167 167 import os
168 168 import sys
169 169
170 170 from mercurial import bundle2
171 171 from mercurial import cmdutil
172 172 from mercurial import discovery
173 173 from mercurial import error
174 174 from mercurial import copies
175 175 from mercurial import context
176 176 from mercurial import destutil
177 177 from mercurial import exchange
178 178 from mercurial import extensions
179 179 from mercurial import hg
180 180 from mercurial import node
181 181 from mercurial import repair
182 182 from mercurial import scmutil
183 183 from mercurial import util
184 184 from mercurial import obsolete
185 185 from mercurial import merge as mergemod
186 186 from mercurial.lock import release
187 187 from mercurial.i18n import _
188 188
189 189 cmdtable = {}
190 190 command = cmdutil.command(cmdtable)
191 191
192 192 class _constraints(object):
193 193 # aborts if there are multiple rules for one node
194 194 noduplicates = 'noduplicates'
195 195 # abort if the node does belong to edited stack
196 196 forceother = 'forceother'
197 197 # abort if the node doesn't belong to edited stack
198 198 noother = 'noother'
199 199
200 200 @classmethod
201 201 def known(cls):
202 202 return set([v for k, v in cls.__dict__.items() if k[0] != '_'])
203 203
204 204 # Note for extension authors: ONLY specify testedwith = 'internal' for
205 205 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
206 206 # be specifying the version(s) of Mercurial they are tested with, or
207 207 # leave the attribute unspecified.
208 208 testedwith = 'internal'
209 209
210 210 # i18n: command names and abbreviations must remain untranslated
211 211 editcomment = _("""# Edit history between %s and %s
212 212 #
213 213 # Commits are listed from least to most recent
214 214 #
215 215 # Commands:
216 216 # p, pick = use commit
217 217 # e, edit = use commit, but stop for amending
218 218 # f, fold = use commit, but combine it with the one above
219 219 # r, roll = like fold, but discard this commit's description
220 220 # d, drop = remove commit from history
221 221 # m, mess = edit commit message without changing commit content
222 222 #
223 223 """)
224 224
225 225 class histeditstate(object):
226 226 def __init__(self, repo, parentctxnode=None, actions=None, keep=None,
227 227 topmost=None, replacements=None, lock=None, wlock=None):
228 228 self.repo = repo
229 229 self.actions = actions
230 230 self.keep = keep
231 231 self.topmost = topmost
232 232 self.parentctxnode = parentctxnode
233 233 self.lock = lock
234 234 self.wlock = wlock
235 235 self.backupfile = None
236 236 if replacements is None:
237 237 self.replacements = []
238 238 else:
239 239 self.replacements = replacements
240 240
241 241 def read(self):
242 242 """Load histedit state from disk and set fields appropriately."""
243 243 try:
244 244 fp = self.repo.vfs('histedit-state', 'r')
245 245 except IOError as err:
246 246 if err.errno != errno.ENOENT:
247 247 raise
248 248 raise error.Abort(_('no histedit in progress'))
249 249
250 250 try:
251 251 data = pickle.load(fp)
252 252 parentctxnode, rules, keep, topmost, replacements = data
253 253 backupfile = None
254 254 except pickle.UnpicklingError:
255 255 data = self._load()
256 256 parentctxnode, rules, keep, topmost, replacements, backupfile = data
257 257
258 258 self.parentctxnode = parentctxnode
259 259 rules = "\n".join(["%s %s" % (verb, rest) for [verb, rest] in rules])
260 260 actions = parserules(rules, self)
261 261 self.actions = actions
262 262 self.keep = keep
263 263 self.topmost = topmost
264 264 self.replacements = replacements
265 265 self.backupfile = backupfile
266 266
267 267 def write(self):
268 268 fp = self.repo.vfs('histedit-state', 'w')
269 269 fp.write('v1\n')
270 270 fp.write('%s\n' % node.hex(self.parentctxnode))
271 271 fp.write('%s\n' % node.hex(self.topmost))
272 272 fp.write('%s\n' % self.keep)
273 273 fp.write('%d\n' % len(self.actions))
274 274 for action in self.actions:
275 275 fp.write('%s\n' % action.tostate())
276 276 fp.write('%d\n' % len(self.replacements))
277 277 for replacement in self.replacements:
278 278 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
279 279 for r in replacement[1])))
280 280 backupfile = self.backupfile
281 281 if not backupfile:
282 282 backupfile = ''
283 283 fp.write('%s\n' % backupfile)
284 284 fp.close()
285 285
286 286 def _load(self):
287 287 fp = self.repo.vfs('histedit-state', 'r')
288 288 lines = [l[:-1] for l in fp.readlines()]
289 289
290 290 index = 0
291 291 lines[index] # version number
292 292 index += 1
293 293
294 294 parentctxnode = node.bin(lines[index])
295 295 index += 1
296 296
297 297 topmost = node.bin(lines[index])
298 298 index += 1
299 299
300 300 keep = lines[index] == 'True'
301 301 index += 1
302 302
303 303 # Rules
304 304 rules = []
305 305 rulelen = int(lines[index])
306 306 index += 1
307 307 for i in xrange(rulelen):
308 308 ruleaction = lines[index]
309 309 index += 1
310 310 rule = lines[index]
311 311 index += 1
312 312 rules.append((ruleaction, rule))
313 313
314 314 # Replacements
315 315 replacements = []
316 316 replacementlen = int(lines[index])
317 317 index += 1
318 318 for i in xrange(replacementlen):
319 319 replacement = lines[index]
320 320 original = node.bin(replacement[:40])
321 321 succ = [node.bin(replacement[i:i + 40]) for i in
322 322 range(40, len(replacement), 40)]
323 323 replacements.append((original, succ))
324 324 index += 1
325 325
326 326 backupfile = lines[index]
327 327 index += 1
328 328
329 329 fp.close()
330 330
331 331 return parentctxnode, rules, keep, topmost, replacements, backupfile
332 332
333 333 def clear(self):
334 334 if self.inprogress():
335 335 self.repo.vfs.unlink('histedit-state')
336 336
337 337 def inprogress(self):
338 338 return self.repo.vfs.exists('histedit-state')
339 339
340 340
341 341 class histeditaction(object):
342 342 def __init__(self, state, node):
343 343 self.state = state
344 344 self.repo = state.repo
345 345 self.node = node
346 346
347 347 @classmethod
348 348 def fromrule(cls, state, rule):
349 349 """Parses the given rule, returning an instance of the histeditaction.
350 350 """
351 351 rulehash = rule.strip().split(' ', 1)[0]
352 352 return cls(state, node.bin(rulehash))
353 353
354 354 def verify(self):
355 355 """ Verifies semantic correctness of the rule"""
356 356 repo = self.repo
357 357 ha = node.hex(self.node)
358 358 try:
359 359 self.node = repo[ha].node()
360 360 except error.RepoError:
361 361 raise error.Abort(_('unknown changeset %s listed')
362 362 % ha[:12])
363 363
364 364 def torule(self):
365 365 """build a histedit rule line for an action
366 366
367 367 by default lines are in the form:
368 368 <hash> <rev> <summary>
369 369 """
370 370 ctx = self.repo[self.node]
371 371 summary = ''
372 372 if ctx.description():
373 373 summary = ctx.description().splitlines()[0]
374 374 line = '%s %s %d %s' % (self.verb, ctx, ctx.rev(), summary)
375 375 # trim to 75 columns by default so it's not stupidly wide in my editor
376 376 # (the 5 more are left for verb)
377 377 maxlen = self.repo.ui.configint('histedit', 'linelen', default=80)
378 378 maxlen = max(maxlen, 22) # avoid truncating hash
379 379 return util.ellipsis(line, maxlen)
380 380
381 381 def tostate(self):
382 382 """Print an action in format used by histedit state files
383 383 (the first line is a verb, the remainder is the second)
384 384 """
385 385 return "%s\n%s" % (self.verb, node.hex(self.node))
386 386
387 387 def constraints(self):
388 388 """Return a set of constrains that this action should be verified for
389 389 """
390 390 return set([_constraints.noduplicates, _constraints.noother])
391 391
392 392 def nodetoverify(self):
393 393 """Returns a node associated with the action that will be used for
394 394 verification purposes.
395 395
396 396 If the action doesn't correspond to node it should return None
397 397 """
398 398 return self.node
399 399
400 400 def run(self):
401 401 """Runs the action. The default behavior is simply apply the action's
402 402 rulectx onto the current parentctx."""
403 403 self.applychange()
404 404 self.continuedirty()
405 405 return self.continueclean()
406 406
407 407 def applychange(self):
408 408 """Applies the changes from this action's rulectx onto the current
409 409 parentctx, but does not commit them."""
410 410 repo = self.repo
411 411 rulectx = repo[self.node]
412 412 hg.update(repo, self.state.parentctxnode, quietempty=True)
413 413 stats = applychanges(repo.ui, repo, rulectx, {})
414 414 if stats and stats[3] > 0:
415 415 raise error.InterventionRequired(_('Fix up the change and run '
416 416 'hg histedit --continue'))
417 417
418 418 def continuedirty(self):
419 419 """Continues the action when changes have been applied to the working
420 420 copy. The default behavior is to commit the dirty changes."""
421 421 repo = self.repo
422 422 rulectx = repo[self.node]
423 423
424 424 editor = self.commiteditor()
425 425 commit = commitfuncfor(repo, rulectx)
426 426
427 427 commit(text=rulectx.description(), user=rulectx.user(),
428 428 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
429 429
430 430 def commiteditor(self):
431 431 """The editor to be used to edit the commit message."""
432 432 return False
433 433
434 434 def continueclean(self):
435 435 """Continues the action when the working copy is clean. The default
436 436 behavior is to accept the current commit as the new version of the
437 437 rulectx."""
438 438 ctx = self.repo['.']
439 439 if ctx.node() == self.state.parentctxnode:
440 440 self.repo.ui.warn(_('%s: empty changeset\n') %
441 441 node.short(self.node))
442 442 return ctx, [(self.node, tuple())]
443 443 if ctx.node() == self.node:
444 444 # Nothing changed
445 445 return ctx, []
446 446 return ctx, [(self.node, (ctx.node(),))]
447 447
448 448 def commitfuncfor(repo, src):
449 449 """Build a commit function for the replacement of <src>
450 450
451 451 This function ensure we apply the same treatment to all changesets.
452 452
453 453 - Add a 'histedit_source' entry in extra.
454 454
455 455 Note that fold has its own separated logic because its handling is a bit
456 456 different and not easily factored out of the fold method.
457 457 """
458 458 phasemin = src.phase()
459 459 def commitfunc(**kwargs):
460 460 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
461 461 try:
462 462 repo.ui.setconfig('phases', 'new-commit', phasemin,
463 463 'histedit')
464 464 extra = kwargs.get('extra', {}).copy()
465 465 extra['histedit_source'] = src.hex()
466 466 kwargs['extra'] = extra
467 467 return repo.commit(**kwargs)
468 468 finally:
469 469 repo.ui.restoreconfig(phasebackup)
470 470 return commitfunc
471 471
472 472 def applychanges(ui, repo, ctx, opts):
473 473 """Merge changeset from ctx (only) in the current working directory"""
474 474 wcpar = repo.dirstate.parents()[0]
475 475 if ctx.p1().node() == wcpar:
476 476 # edits are "in place" we do not need to make any merge,
477 477 # just applies changes on parent for edition
478 478 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
479 479 stats = None
480 480 else:
481 481 try:
482 482 # ui.forcemerge is an internal variable, do not document
483 483 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
484 484 'histedit')
485 485 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
486 486 finally:
487 487 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
488 488 return stats
489 489
490 490 def collapse(repo, first, last, commitopts, skipprompt=False):
491 491 """collapse the set of revisions from first to last as new one.
492 492
493 493 Expected commit options are:
494 494 - message
495 495 - date
496 496 - username
497 497 Commit message is edited in all cases.
498 498
499 499 This function works in memory."""
500 500 ctxs = list(repo.set('%d::%d', first, last))
501 501 if not ctxs:
502 502 return None
503 503 for c in ctxs:
504 504 if not c.mutable():
505 505 raise error.Abort(
506 506 _("cannot fold into public change %s") % node.short(c.node()))
507 507 base = first.parents()[0]
508 508
509 509 # commit a new version of the old changeset, including the update
510 510 # collect all files which might be affected
511 511 files = set()
512 512 for ctx in ctxs:
513 513 files.update(ctx.files())
514 514
515 515 # Recompute copies (avoid recording a -> b -> a)
516 516 copied = copies.pathcopies(base, last)
517 517
518 518 # prune files which were reverted by the updates
519 519 def samefile(f):
520 520 if f in last.manifest():
521 521 a = last.filectx(f)
522 522 if f in base.manifest():
523 523 b = base.filectx(f)
524 524 return (a.data() == b.data()
525 525 and a.flags() == b.flags())
526 526 else:
527 527 return False
528 528 else:
529 529 return f not in base.manifest()
530 530 files = [f for f in files if not samefile(f)]
531 531 # commit version of these files as defined by head
532 532 headmf = last.manifest()
533 533 def filectxfn(repo, ctx, path):
534 534 if path in headmf:
535 535 fctx = last[path]
536 536 flags = fctx.flags()
537 537 mctx = context.memfilectx(repo,
538 538 fctx.path(), fctx.data(),
539 539 islink='l' in flags,
540 540 isexec='x' in flags,
541 541 copied=copied.get(path))
542 542 return mctx
543 543 return None
544 544
545 545 if commitopts.get('message'):
546 546 message = commitopts['message']
547 547 else:
548 548 message = first.description()
549 549 user = commitopts.get('user')
550 550 date = commitopts.get('date')
551 551 extra = commitopts.get('extra')
552 552
553 553 parents = (first.p1().node(), first.p2().node())
554 554 editor = None
555 555 if not skipprompt:
556 556 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
557 557 new = context.memctx(repo,
558 558 parents=parents,
559 559 text=message,
560 560 files=files,
561 561 filectxfn=filectxfn,
562 562 user=user,
563 563 date=date,
564 564 extra=extra,
565 565 editor=editor)
566 566 return repo.commitctx(new)
567 567
568 568 def _isdirtywc(repo):
569 569 return repo[None].dirty(missing=True)
570 570
571 571 def abortdirty():
572 572 raise error.Abort(_('working copy has pending changes'),
573 573 hint=_('amend, commit, or revert them and run histedit '
574 574 '--continue, or abort with histedit --abort'))
575 575
576 576
577 577 actiontable = {}
578 578 actionlist = []
579 579
580 580 def addhisteditaction(verbs):
581 581 def wrap(cls):
582 582 cls.verb = verbs[0]
583 583 for verb in verbs:
584 584 actiontable[verb] = cls
585 585 actionlist.append(cls)
586 586 return cls
587 587 return wrap
588 588
589 589
590 590 @addhisteditaction(['pick', 'p'])
591 591 class pick(histeditaction):
592 592 def run(self):
593 593 rulectx = self.repo[self.node]
594 594 if rulectx.parents()[0].node() == self.state.parentctxnode:
595 595 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
596 596 return rulectx, []
597 597
598 598 return super(pick, self).run()
599 599
600 600 @addhisteditaction(['edit', 'e'])
601 601 class edit(histeditaction):
602 602 def run(self):
603 603 repo = self.repo
604 604 rulectx = repo[self.node]
605 605 hg.update(repo, self.state.parentctxnode)
606 606 applychanges(repo.ui, repo, rulectx, {})
607 607 raise error.InterventionRequired(
608 608 _('Make changes as needed, you may commit or record as needed '
609 609 'now.\nWhen you are finished, run hg histedit --continue to '
610 610 'resume.'))
611 611
612 612 def commiteditor(self):
613 613 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
614 614
615 615 @addhisteditaction(['fold', 'f'])
616 616 class fold(histeditaction):
617 617 def continuedirty(self):
618 618 repo = self.repo
619 619 rulectx = repo[self.node]
620 620
621 621 commit = commitfuncfor(repo, rulectx)
622 622 commit(text='fold-temp-revision %s' % node.short(self.node),
623 623 user=rulectx.user(), date=rulectx.date(),
624 624 extra=rulectx.extra())
625 625
626 626 def continueclean(self):
627 627 repo = self.repo
628 628 ctx = repo['.']
629 629 rulectx = repo[self.node]
630 630 parentctxnode = self.state.parentctxnode
631 631 if ctx.node() == parentctxnode:
632 632 repo.ui.warn(_('%s: empty changeset\n') %
633 633 node.short(self.node))
634 634 return ctx, [(self.node, (parentctxnode,))]
635 635
636 636 parentctx = repo[parentctxnode]
637 637 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
638 638 parentctx))
639 639 if not newcommits:
640 640 repo.ui.warn(_('%s: cannot fold - working copy is not a '
641 641 'descendant of previous commit %s\n') %
642 642 (node.short(self.node), node.short(parentctxnode)))
643 643 return ctx, [(self.node, (ctx.node(),))]
644 644
645 645 middlecommits = newcommits.copy()
646 646 middlecommits.discard(ctx.node())
647 647
648 648 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
649 649 middlecommits)
650 650
651 651 def skipprompt(self):
652 652 """Returns true if the rule should skip the message editor.
653 653
654 654 For example, 'fold' wants to show an editor, but 'rollup'
655 655 doesn't want to.
656 656 """
657 657 return False
658 658
659 659 def mergedescs(self):
660 660 """Returns true if the rule should merge messages of multiple changes.
661 661
662 662 This exists mainly so that 'rollup' rules can be a subclass of
663 663 'fold'.
664 664 """
665 665 return True
666 666
667 667 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
668 668 parent = ctx.parents()[0].node()
669 669 hg.update(repo, parent)
670 670 ### prepare new commit data
671 671 commitopts = {}
672 672 commitopts['user'] = ctx.user()
673 673 # commit message
674 674 if not self.mergedescs():
675 675 newmessage = ctx.description()
676 676 else:
677 677 newmessage = '\n***\n'.join(
678 678 [ctx.description()] +
679 679 [repo[r].description() for r in internalchanges] +
680 680 [oldctx.description()]) + '\n'
681 681 commitopts['message'] = newmessage
682 682 # date
683 683 commitopts['date'] = max(ctx.date(), oldctx.date())
684 684 extra = ctx.extra().copy()
685 685 # histedit_source
686 686 # note: ctx is likely a temporary commit but that the best we can do
687 687 # here. This is sufficient to solve issue3681 anyway.
688 688 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
689 689 commitopts['extra'] = extra
690 690 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
691 691 try:
692 692 phasemin = max(ctx.phase(), oldctx.phase())
693 693 repo.ui.setconfig('phases', 'new-commit', phasemin, 'histedit')
694 694 n = collapse(repo, ctx, repo[newnode], commitopts,
695 695 skipprompt=self.skipprompt())
696 696 finally:
697 697 repo.ui.restoreconfig(phasebackup)
698 698 if n is None:
699 699 return ctx, []
700 700 hg.update(repo, n)
701 701 replacements = [(oldctx.node(), (newnode,)),
702 702 (ctx.node(), (n,)),
703 703 (newnode, (n,)),
704 704 ]
705 705 for ich in internalchanges:
706 706 replacements.append((ich, (n,)))
707 707 return repo[n], replacements
708 708
709 709 class base(histeditaction):
710 710 def constraints(self):
711 711 return set([_constraints.forceother])
712 712
713 713 def run(self):
714 714 if self.repo['.'].node() != self.node:
715 715 mergemod.update(self.repo, self.node, False, True)
716 716 # branchmerge, force)
717 717 return self.continueclean()
718 718
719 719 def continuedirty(self):
720 720 abortdirty()
721 721
722 722 def continueclean(self):
723 723 basectx = self.repo['.']
724 724 return basectx, []
725 725
726 726 @addhisteditaction(['_multifold'])
727 727 class _multifold(fold):
728 728 """fold subclass used for when multiple folds happen in a row
729 729
730 730 We only want to fire the editor for the folded message once when
731 731 (say) four changes are folded down into a single change. This is
732 732 similar to rollup, but we should preserve both messages so that
733 733 when the last fold operation runs we can show the user all the
734 734 commit messages in their editor.
735 735 """
736 736 def skipprompt(self):
737 737 return True
738 738
739 739 @addhisteditaction(["roll", "r"])
740 740 class rollup(fold):
741 741 def mergedescs(self):
742 742 return False
743 743
744 744 def skipprompt(self):
745 745 return True
746 746
747 747 @addhisteditaction(["drop", "d"])
748 748 class drop(histeditaction):
749 749 def run(self):
750 750 parentctx = self.repo[self.state.parentctxnode]
751 751 return parentctx, [(self.node, tuple())]
752 752
753 753 @addhisteditaction(["mess", "m"])
754 754 class message(histeditaction):
755 755 def commiteditor(self):
756 756 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
757 757
758 758 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
759 759 """utility function to find the first outgoing changeset
760 760
761 761 Used by initialization code"""
762 762 if opts is None:
763 763 opts = {}
764 764 dest = ui.expandpath(remote or 'default-push', remote or 'default')
765 765 dest, revs = hg.parseurl(dest, None)[:2]
766 766 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
767 767
768 768 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
769 769 other = hg.peer(repo, opts, dest)
770 770
771 771 if revs:
772 772 revs = [repo.lookup(rev) for rev in revs]
773 773
774 774 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
775 775 if not outgoing.missing:
776 776 raise error.Abort(_('no outgoing ancestors'))
777 777 roots = list(repo.revs("roots(%ln)", outgoing.missing))
778 778 if 1 < len(roots):
779 779 msg = _('there are ambiguous outgoing revisions')
780 780 hint = _('see "hg help histedit" for more detail')
781 781 raise error.Abort(msg, hint=hint)
782 782 return repo.lookup(roots[0])
783 783
784 784
785 785 @command('histedit',
786 786 [('', 'commands', '',
787 787 _('read history edits from the specified file'), _('FILE')),
788 788 ('c', 'continue', False, _('continue an edit already in progress')),
789 789 ('', 'edit-plan', False, _('edit remaining actions list')),
790 790 ('k', 'keep', False,
791 791 _("don't strip old nodes after edit is complete")),
792 792 ('', 'abort', False, _('abort an edit in progress')),
793 793 ('o', 'outgoing', False, _('changesets not found in destination')),
794 794 ('f', 'force', False,
795 795 _('force outgoing even for unrelated repositories')),
796 796 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
797 797 _("[ANCESTOR] | --outgoing [URL]"))
798 798 def histedit(ui, repo, *freeargs, **opts):
799 799 """interactively edit changeset history
800 800
801 801 This command edits changesets between an ANCESTOR and the parent of
802 802 the working directory.
803 803
804 804 The value from the "histedit.defaultrev" config option is used as a
805 805 revset to select the base revision when ANCESTOR is not specified.
806 806 The first revision returned by the revset is used. By default, this
807 807 selects the editable history that is unique to the ancestry of the
808 808 working directory.
809 809
810 810 With --outgoing, this edits changesets not found in the
811 811 destination repository. If URL of the destination is omitted, the
812 812 'default-push' (or 'default') path will be used.
813 813
814 814 For safety, this command is also aborted if there are ambiguous
815 815 outgoing revisions which may confuse users: for example, if there
816 816 are multiple branches containing outgoing revisions.
817 817
818 818 Use "min(outgoing() and ::.)" or similar revset specification
819 819 instead of --outgoing to specify edit target revision exactly in
820 820 such ambiguous situation. See :hg:`help revsets` for detail about
821 821 selecting revisions.
822 822
823 823 .. container:: verbose
824 824
825 825 Examples:
826 826
827 827 - A number of changes have been made.
828 828 Revision 3 is no longer needed.
829 829
830 830 Start history editing from revision 3::
831 831
832 832 hg histedit -r 3
833 833
834 834 An editor opens, containing the list of revisions,
835 835 with specific actions specified::
836 836
837 837 pick 5339bf82f0ca 3 Zworgle the foobar
838 838 pick 8ef592ce7cc4 4 Bedazzle the zerlog
839 839 pick 0a9639fcda9d 5 Morgify the cromulancy
840 840
841 841 Additional information about the possible actions
842 842 to take appears below the list of revisions.
843 843
844 844 To remove revision 3 from the history,
845 845 its action (at the beginning of the relevant line)
846 846 is changed to 'drop'::
847 847
848 848 drop 5339bf82f0ca 3 Zworgle the foobar
849 849 pick 8ef592ce7cc4 4 Bedazzle the zerlog
850 850 pick 0a9639fcda9d 5 Morgify the cromulancy
851 851
852 852 - A number of changes have been made.
853 853 Revision 2 and 4 need to be swapped.
854 854
855 855 Start history editing from revision 2::
856 856
857 857 hg histedit -r 2
858 858
859 859 An editor opens, containing the list of revisions,
860 860 with specific actions specified::
861 861
862 862 pick 252a1af424ad 2 Blorb a morgwazzle
863 863 pick 5339bf82f0ca 3 Zworgle the foobar
864 864 pick 8ef592ce7cc4 4 Bedazzle the zerlog
865 865
866 866 To swap revision 2 and 4, its lines are swapped
867 867 in the editor::
868 868
869 869 pick 8ef592ce7cc4 4 Bedazzle the zerlog
870 870 pick 5339bf82f0ca 3 Zworgle the foobar
871 871 pick 252a1af424ad 2 Blorb a morgwazzle
872 872
873 873 Returns 0 on success, 1 if user intervention is required (not only
874 874 for intentional "edit" command, but also for resolving unexpected
875 875 conflicts).
876 876 """
877 877 state = histeditstate(repo)
878 878 try:
879 879 state.wlock = repo.wlock()
880 880 state.lock = repo.lock()
881 881 _histedit(ui, repo, state, *freeargs, **opts)
882 882 except error.Abort:
883 883 if repo.vfs.exists('histedit-last-edit.txt'):
884 884 ui.warn(_('warning: histedit rules saved '
885 885 'to: .hg/histedit-last-edit.txt\n'))
886 886 raise
887 887 finally:
888 888 release(state.lock, state.wlock)
889 889
890 890 def _histedit(ui, repo, state, *freeargs, **opts):
891 891 # TODO only abort if we try to histedit mq patches, not just
892 892 # blanket if mq patches are applied somewhere
893 893 mq = getattr(repo, 'mq', None)
894 894 if mq and mq.applied:
895 895 raise error.Abort(_('source has mq patches applied'))
896 896
897 897 # basic argument incompatibility processing
898 898 outg = opts.get('outgoing')
899 899 cont = opts.get('continue')
900 900 editplan = opts.get('edit_plan')
901 901 abort = opts.get('abort')
902 902 force = opts.get('force')
903 903 rules = opts.get('commands', '')
904 904 revs = opts.get('rev', [])
905 905 goal = 'new' # This invocation goal, in new, continue, abort
906 906 if force and not outg:
907 907 raise error.Abort(_('--force only allowed with --outgoing'))
908 908 if cont:
909 909 if any((outg, abort, revs, freeargs, rules, editplan)):
910 910 raise error.Abort(_('no arguments allowed with --continue'))
911 911 goal = 'continue'
912 912 elif abort:
913 913 if any((outg, revs, freeargs, rules, editplan)):
914 914 raise error.Abort(_('no arguments allowed with --abort'))
915 915 goal = 'abort'
916 916 elif editplan:
917 917 if any((outg, revs, freeargs)):
918 918 raise error.Abort(_('only --commands argument allowed with '
919 919 '--edit-plan'))
920 920 goal = 'edit-plan'
921 921 else:
922 922 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
923 923 raise error.Abort(_('history edit already in progress, try '
924 924 '--continue or --abort'))
925 925 if outg:
926 926 if revs:
927 927 raise error.Abort(_('no revisions allowed with --outgoing'))
928 928 if len(freeargs) > 1:
929 929 raise error.Abort(
930 930 _('only one repo argument allowed with --outgoing'))
931 931 else:
932 932 revs.extend(freeargs)
933 933 if len(revs) == 0:
934 934 defaultrev = destutil.desthistedit(ui, repo)
935 935 if defaultrev is not None:
936 936 revs.append(defaultrev)
937 937
938 938 if len(revs) != 1:
939 939 raise error.Abort(
940 940 _('histedit requires exactly one ancestor revision'))
941 941
942 942
943 943 replacements = []
944 944 state.keep = opts.get('keep', False)
945 945 supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
946 946
947 947 # rebuild state
948 948 if goal == 'continue':
949 949 state.read()
950 950 state = bootstrapcontinue(ui, state, opts)
951 951 elif goal == 'edit-plan':
952 952 state.read()
953 953 if not rules:
954 954 comment = editcomment % (node.short(state.parentctxnode),
955 955 node.short(state.topmost))
956 956 rules = ruleeditor(repo, ui, state.actions, comment)
957 957 else:
958 958 if rules == '-':
959 959 f = sys.stdin
960 960 else:
961 961 f = open(rules)
962 962 rules = f.read()
963 963 f.close()
964 964 actions = parserules(rules, state)
965 965 ctxs = [repo[act.nodetoverify()] \
966 966 for act in state.actions if act.nodetoverify()]
967 967 verifyactions(actions, state, ctxs)
968 968 state.actions = actions
969 969 state.write()
970 970 return
971 971 elif goal == 'abort':
972 972 try:
973 973 state.read()
974 974 tmpnodes, leafs = newnodestoabort(state)
975 975 ui.debug('restore wc to old parent %s\n'
976 976 % node.short(state.topmost))
977 977
978 978 # Recover our old commits if necessary
979 979 if not state.topmost in repo and state.backupfile:
980 980 backupfile = repo.join(state.backupfile)
981 981 f = hg.openpath(ui, backupfile)
982 982 gen = exchange.readbundle(ui, f, backupfile)
983 983 tr = repo.transaction('histedit.abort')
984 984 try:
985 985 if not isinstance(gen, bundle2.unbundle20):
986 986 gen.apply(repo, 'histedit', 'bundle:' + backupfile)
987 987 if isinstance(gen, bundle2.unbundle20):
988 988 bundle2.applybundle(repo, gen, tr,
989 989 source='histedit',
990 990 url='bundle:' + backupfile)
991 991 tr.close()
992 992 finally:
993 993 tr.release()
994 994
995 995 os.remove(backupfile)
996 996
997 997 # check whether we should update away
998 998 if repo.unfiltered().revs('parents() and (%n or %ln::)',
999 999 state.parentctxnode, leafs | tmpnodes):
1000 1000 hg.clean(repo, state.topmost, show_stats=True, quietempty=True)
1001 1001 cleanupnode(ui, repo, 'created', tmpnodes)
1002 1002 cleanupnode(ui, repo, 'temp', leafs)
1003 1003 except Exception:
1004 1004 if state.inprogress():
1005 1005 ui.warn(_('warning: encountered an exception during histedit '
1006 1006 '--abort; the repository may not have been completely '
1007 1007 'cleaned up\n'))
1008 1008 raise
1009 1009 finally:
1010 1010 state.clear()
1011 1011 return
1012 1012 else:
1013 1013 cmdutil.checkunfinished(repo)
1014 1014 cmdutil.bailifchanged(repo)
1015 1015
1016 1016 if repo.vfs.exists('histedit-last-edit.txt'):
1017 1017 repo.vfs.unlink('histedit-last-edit.txt')
1018 1018 topmost, empty = repo.dirstate.parents()
1019 1019 if outg:
1020 1020 if freeargs:
1021 1021 remote = freeargs[0]
1022 1022 else:
1023 1023 remote = None
1024 1024 root = findoutgoing(ui, repo, remote, force, opts)
1025 1025 else:
1026 1026 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
1027 1027 if len(rr) != 1:
1028 1028 raise error.Abort(_('The specified revisions must have '
1029 1029 'exactly one common root'))
1030 1030 root = rr[0].node()
1031 1031
1032 1032 revs = between(repo, root, topmost, state.keep)
1033 1033 if not revs:
1034 1034 raise error.Abort(_('%s is not an ancestor of working directory') %
1035 1035 node.short(root))
1036 1036
1037 1037 ctxs = [repo[r] for r in revs]
1038 1038 if not rules:
1039 1039 comment = editcomment % (node.short(root), node.short(topmost))
1040 1040 actions = [pick(state, r) for r in revs]
1041 1041 rules = ruleeditor(repo, ui, actions, comment)
1042 1042 else:
1043 1043 if rules == '-':
1044 1044 f = sys.stdin
1045 1045 else:
1046 1046 f = open(rules)
1047 1047 rules = f.read()
1048 1048 f.close()
1049 1049 actions = parserules(rules, state)
1050 1050 verifyactions(actions, state, ctxs)
1051 1051
1052 1052 parentctxnode = repo[root].parents()[0].node()
1053 1053
1054 1054 state.parentctxnode = parentctxnode
1055 1055 state.actions = actions
1056 1056 state.topmost = topmost
1057 1057 state.replacements = replacements
1058 1058
1059 1059 # Create a backup so we can always abort completely.
1060 1060 backupfile = None
1061 1061 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1062 1062 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
1063 1063 'histedit')
1064 1064 state.backupfile = backupfile
1065 1065
1066 1066 # preprocess rules so that we can hide inner folds from the user
1067 1067 # and only show one editor
1068 1068 actions = state.actions[:]
1069 1069 for idx, (action, nextact) in enumerate(
1070 1070 zip(actions, actions[1:] + [None])):
1071 1071 if action.verb == 'fold' and nextact and nextact.verb == 'fold':
1072 1072 state.actions[idx].__class__ = _multifold
1073 1073
1074 1074 while state.actions:
1075 1075 state.write()
1076 1076 actobj = state.actions.pop(0)
1077 1077 ui.debug('histedit: processing %s %s\n' % (actobj.verb,\
1078 1078 actobj.torule()))
1079 1079 parentctx, replacement_ = actobj.run()
1080 1080 state.parentctxnode = parentctx.node()
1081 1081 state.replacements.extend(replacement_)
1082 1082 state.write()
1083 1083
1084 hg.update(repo, state.parentctxnode)
1084 hg.update(repo, state.parentctxnode, quietempty=True)
1085 1085
1086 1086 mapping, tmpnodes, created, ntm = processreplacement(state)
1087 1087 if mapping:
1088 1088 for prec, succs in mapping.iteritems():
1089 1089 if not succs:
1090 1090 ui.debug('histedit: %s is dropped\n' % node.short(prec))
1091 1091 else:
1092 1092 ui.debug('histedit: %s is replaced by %s\n' % (
1093 1093 node.short(prec), node.short(succs[0])))
1094 1094 if len(succs) > 1:
1095 1095 m = 'histedit: %s'
1096 1096 for n in succs[1:]:
1097 1097 ui.debug(m % node.short(n))
1098 1098
1099 1099 if supportsmarkers:
1100 1100 # Only create markers if the temp nodes weren't already removed.
1101 1101 obsolete.createmarkers(repo, ((repo[t],()) for t in sorted(tmpnodes)
1102 1102 if t in repo))
1103 1103 else:
1104 1104 cleanupnode(ui, repo, 'temp', tmpnodes)
1105 1105
1106 1106 if not state.keep:
1107 1107 if mapping:
1108 1108 movebookmarks(ui, repo, mapping, state.topmost, ntm)
1109 1109 # TODO update mq state
1110 1110 if supportsmarkers:
1111 1111 markers = []
1112 1112 # sort by revision number because it sound "right"
1113 1113 for prec in sorted(mapping, key=repo.changelog.rev):
1114 1114 succs = mapping[prec]
1115 1115 markers.append((repo[prec],
1116 1116 tuple(repo[s] for s in succs)))
1117 1117 if markers:
1118 1118 obsolete.createmarkers(repo, markers)
1119 1119 else:
1120 1120 cleanupnode(ui, repo, 'replaced', mapping)
1121 1121
1122 1122 state.clear()
1123 1123 if os.path.exists(repo.sjoin('undo')):
1124 1124 os.unlink(repo.sjoin('undo'))
1125 1125
1126 1126 def bootstrapcontinue(ui, state, opts):
1127 1127 repo = state.repo
1128 1128 if state.actions:
1129 1129 actobj = state.actions.pop(0)
1130 1130
1131 1131 if _isdirtywc(repo):
1132 1132 actobj.continuedirty()
1133 1133 if _isdirtywc(repo):
1134 1134 abortdirty()
1135 1135
1136 1136 parentctx, replacements = actobj.continueclean()
1137 1137
1138 1138 state.parentctxnode = parentctx.node()
1139 1139 state.replacements.extend(replacements)
1140 1140
1141 1141 return state
1142 1142
1143 1143 def between(repo, old, new, keep):
1144 1144 """select and validate the set of revision to edit
1145 1145
1146 1146 When keep is false, the specified set can't have children."""
1147 1147 ctxs = list(repo.set('%n::%n', old, new))
1148 1148 if ctxs and not keep:
1149 1149 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
1150 1150 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
1151 1151 raise error.Abort(_('cannot edit history that would orphan nodes'))
1152 1152 if repo.revs('(%ld) and merge()', ctxs):
1153 1153 raise error.Abort(_('cannot edit history that contains merges'))
1154 1154 root = ctxs[0] # list is already sorted by repo.set
1155 1155 if not root.mutable():
1156 1156 raise error.Abort(_('cannot edit public changeset: %s') % root,
1157 1157 hint=_('see "hg help phases" for details'))
1158 1158 return [c.node() for c in ctxs]
1159 1159
1160 1160 def ruleeditor(repo, ui, actions, editcomment=""):
1161 1161 """open an editor to edit rules
1162 1162
1163 1163 rules are in the format [ [act, ctx], ...] like in state.rules
1164 1164 """
1165 1165 rules = '\n'.join([act.torule() for act in actions])
1166 1166 rules += '\n\n'
1167 1167 rules += editcomment
1168 1168 rules = ui.edit(rules, ui.username(), {'prefix': 'histedit'})
1169 1169
1170 1170 # Save edit rules in .hg/histedit-last-edit.txt in case
1171 1171 # the user needs to ask for help after something
1172 1172 # surprising happens.
1173 1173 f = open(repo.join('histedit-last-edit.txt'), 'w')
1174 1174 f.write(rules)
1175 1175 f.close()
1176 1176
1177 1177 return rules
1178 1178
1179 1179 def parserules(rules, state):
1180 1180 """Read the histedit rules string and return list of action objects """
1181 1181 rules = [l for l in (r.strip() for r in rules.splitlines())
1182 1182 if l and not l.startswith('#')]
1183 1183 actions = []
1184 1184 for r in rules:
1185 1185 if ' ' not in r:
1186 1186 raise error.Abort(_('malformed line "%s"') % r)
1187 1187 verb, rest = r.split(' ', 1)
1188 1188
1189 1189 if verb not in actiontable:
1190 1190 raise error.Abort(_('unknown action "%s"') % verb)
1191 1191
1192 1192 action = actiontable[verb].fromrule(state, rest)
1193 1193 actions.append(action)
1194 1194 return actions
1195 1195
1196 1196 def verifyactions(actions, state, ctxs):
1197 1197 """Verify that there exists exactly one action per given changeset and
1198 1198 other constraints.
1199 1199
1200 1200 Will abort if there are to many or too few rules, a malformed rule,
1201 1201 or a rule on a changeset outside of the user-given range.
1202 1202 """
1203 1203 expected = set(c.hex() for c in ctxs)
1204 1204 seen = set()
1205 1205 for action in actions:
1206 1206 action.verify()
1207 1207 constraints = action.constraints()
1208 1208 for constraint in constraints:
1209 1209 if constraint not in _constraints.known():
1210 1210 raise error.Abort(_('unknown constraint "%s"') % constraint)
1211 1211
1212 1212 nodetoverify = action.nodetoverify()
1213 1213 if nodetoverify is not None:
1214 1214 ha = node.hex(nodetoverify)
1215 1215 if _constraints.noother in constraints and ha not in expected:
1216 1216 raise error.Abort(
1217 1217 _('may not use "%s" with changesets '
1218 1218 'other than the ones listed') % action.verb)
1219 1219 if _constraints.forceother in constraints and ha in expected:
1220 1220 raise error.Abort(
1221 1221 _('may not use "%s" with changesets '
1222 1222 'within the edited list') % action.verb)
1223 1223 if _constraints.noduplicates in constraints and ha in seen:
1224 1224 raise error.Abort(_('duplicated command for changeset %s') %
1225 1225 ha[:12])
1226 1226 seen.add(ha)
1227 1227 missing = sorted(expected - seen) # sort to stabilize output
1228 1228 if missing:
1229 1229 raise error.Abort(_('missing rules for changeset %s') %
1230 1230 missing[0][:12],
1231 1231 hint=_('use "drop %s" to discard the change') % missing[0][:12])
1232 1232
1233 1233 def newnodestoabort(state):
1234 1234 """process the list of replacements to return
1235 1235
1236 1236 1) the list of final node
1237 1237 2) the list of temporary node
1238 1238
1239 1239 This meant to be used on abort as less data are required in this case.
1240 1240 """
1241 1241 replacements = state.replacements
1242 1242 allsuccs = set()
1243 1243 replaced = set()
1244 1244 for rep in replacements:
1245 1245 allsuccs.update(rep[1])
1246 1246 replaced.add(rep[0])
1247 1247 newnodes = allsuccs - replaced
1248 1248 tmpnodes = allsuccs & replaced
1249 1249 return newnodes, tmpnodes
1250 1250
1251 1251
1252 1252 def processreplacement(state):
1253 1253 """process the list of replacements to return
1254 1254
1255 1255 1) the final mapping between original and created nodes
1256 1256 2) the list of temporary node created by histedit
1257 1257 3) the list of new commit created by histedit"""
1258 1258 replacements = state.replacements
1259 1259 allsuccs = set()
1260 1260 replaced = set()
1261 1261 fullmapping = {}
1262 1262 # initialize basic set
1263 1263 # fullmapping records all operations recorded in replacement
1264 1264 for rep in replacements:
1265 1265 allsuccs.update(rep[1])
1266 1266 replaced.add(rep[0])
1267 1267 fullmapping.setdefault(rep[0], set()).update(rep[1])
1268 1268 new = allsuccs - replaced
1269 1269 tmpnodes = allsuccs & replaced
1270 1270 # Reduce content fullmapping into direct relation between original nodes
1271 1271 # and final node created during history edition
1272 1272 # Dropped changeset are replaced by an empty list
1273 1273 toproceed = set(fullmapping)
1274 1274 final = {}
1275 1275 while toproceed:
1276 1276 for x in list(toproceed):
1277 1277 succs = fullmapping[x]
1278 1278 for s in list(succs):
1279 1279 if s in toproceed:
1280 1280 # non final node with unknown closure
1281 1281 # We can't process this now
1282 1282 break
1283 1283 elif s in final:
1284 1284 # non final node, replace with closure
1285 1285 succs.remove(s)
1286 1286 succs.update(final[s])
1287 1287 else:
1288 1288 final[x] = succs
1289 1289 toproceed.remove(x)
1290 1290 # remove tmpnodes from final mapping
1291 1291 for n in tmpnodes:
1292 1292 del final[n]
1293 1293 # we expect all changes involved in final to exist in the repo
1294 1294 # turn `final` into list (topologically sorted)
1295 1295 nm = state.repo.changelog.nodemap
1296 1296 for prec, succs in final.items():
1297 1297 final[prec] = sorted(succs, key=nm.get)
1298 1298
1299 1299 # computed topmost element (necessary for bookmark)
1300 1300 if new:
1301 1301 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1302 1302 elif not final:
1303 1303 # Nothing rewritten at all. we won't need `newtopmost`
1304 1304 # It is the same as `oldtopmost` and `processreplacement` know it
1305 1305 newtopmost = None
1306 1306 else:
1307 1307 # every body died. The newtopmost is the parent of the root.
1308 1308 r = state.repo.changelog.rev
1309 1309 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1310 1310
1311 1311 return final, tmpnodes, new, newtopmost
1312 1312
1313 1313 def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost):
1314 1314 """Move bookmark from old to newly created node"""
1315 1315 if not mapping:
1316 1316 # if nothing got rewritten there is not purpose for this function
1317 1317 return
1318 1318 moves = []
1319 1319 for bk, old in sorted(repo._bookmarks.iteritems()):
1320 1320 if old == oldtopmost:
1321 1321 # special case ensure bookmark stay on tip.
1322 1322 #
1323 1323 # This is arguably a feature and we may only want that for the
1324 1324 # active bookmark. But the behavior is kept compatible with the old
1325 1325 # version for now.
1326 1326 moves.append((bk, newtopmost))
1327 1327 continue
1328 1328 base = old
1329 1329 new = mapping.get(base, None)
1330 1330 if new is None:
1331 1331 continue
1332 1332 while not new:
1333 1333 # base is killed, trying with parent
1334 1334 base = repo[base].p1().node()
1335 1335 new = mapping.get(base, (base,))
1336 1336 # nothing to move
1337 1337 moves.append((bk, new[-1]))
1338 1338 if moves:
1339 1339 lock = tr = None
1340 1340 try:
1341 1341 lock = repo.lock()
1342 1342 tr = repo.transaction('histedit')
1343 1343 marks = repo._bookmarks
1344 1344 for mark, new in moves:
1345 1345 old = marks[mark]
1346 1346 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
1347 1347 % (mark, node.short(old), node.short(new)))
1348 1348 marks[mark] = new
1349 1349 marks.recordchange(tr)
1350 1350 tr.close()
1351 1351 finally:
1352 1352 release(tr, lock)
1353 1353
1354 1354 def cleanupnode(ui, repo, name, nodes):
1355 1355 """strip a group of nodes from the repository
1356 1356
1357 1357 The set of node to strip may contains unknown nodes."""
1358 1358 ui.debug('should strip %s nodes %s\n' %
1359 1359 (name, ', '.join([node.short(n) for n in nodes])))
1360 1360 lock = None
1361 1361 try:
1362 1362 lock = repo.lock()
1363 1363 # do not let filtering get in the way of the cleanse
1364 1364 # we should probably get rid of obsolescence marker created during the
1365 1365 # histedit, but we currently do not have such information.
1366 1366 repo = repo.unfiltered()
1367 1367 # Find all nodes that need to be stripped
1368 1368 # (we use %lr instead of %ln to silently ignore unknown items)
1369 1369 nm = repo.changelog.nodemap
1370 1370 nodes = sorted(n for n in nodes if n in nm)
1371 1371 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1372 1372 for c in roots:
1373 1373 # We should process node in reverse order to strip tip most first.
1374 1374 # but this trigger a bug in changegroup hook.
1375 1375 # This would reduce bundle overhead
1376 1376 repair.strip(ui, repo, c)
1377 1377 finally:
1378 1378 release(lock)
1379 1379
1380 1380 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1381 1381 if isinstance(nodelist, str):
1382 1382 nodelist = [nodelist]
1383 1383 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1384 1384 state = histeditstate(repo)
1385 1385 state.read()
1386 1386 histedit_nodes = set([action.nodetoverify() for action
1387 1387 in state.actions if action.nodetoverify()])
1388 1388 strip_nodes = set([repo[n].node() for n in nodelist])
1389 1389 common_nodes = histedit_nodes & strip_nodes
1390 1390 if common_nodes:
1391 1391 raise error.Abort(_("histedit in progress, can't strip %s")
1392 1392 % ', '.join(node.short(x) for x in common_nodes))
1393 1393 return orig(ui, repo, nodelist, *args, **kwargs)
1394 1394
1395 1395 extensions.wrapfunction(repair, 'strip', stripwrapper)
1396 1396
1397 1397 def summaryhook(ui, repo):
1398 1398 if not os.path.exists(repo.join('histedit-state')):
1399 1399 return
1400 1400 state = histeditstate(repo)
1401 1401 state.read()
1402 1402 if state.actions:
1403 1403 # i18n: column positioning for "hg summary"
1404 1404 ui.write(_('hist: %s (histedit --continue)\n') %
1405 1405 (ui.label(_('%d remaining'), 'histedit.remaining') %
1406 1406 len(state.actions)))
1407 1407
1408 1408 def extsetup(ui):
1409 1409 cmdutil.summaryhooks.add('histedit', summaryhook)
1410 1410 cmdutil.unfinishedstates.append(
1411 1411 ['histedit-state', False, True, _('histedit in progress'),
1412 1412 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
1413 1413 if ui.configbool("experimental", "histeditng"):
1414 1414 globals()['base'] = addhisteditaction(['base', 'b'])(base)
@@ -1,447 +1,437 b''
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 # Commands:
67 67 # p, pick = use commit
68 68 # e, edit = use commit, but stop for amending
69 69 # f, fold = use commit, but combine it with the one above
70 70 # r, roll = like fold, but discard this commit's description
71 71 # d, drop = remove commit from history
72 72 # m, mess = edit commit message without changing commit content
73 73 #
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 74
76 75 Run on a revision not ancestors of the current working directory.
77 76 --------------------------------------------------------------------
78 77
79 78 $ hg up 2
80 79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 80 $ hg histedit -r 4
82 81 abort: 08d98a8350f3 is not an ancestor of working directory
83 82 [255]
84 83 $ hg up --quiet
85 84
86 85
87 86 Test that we pick the minimum of a revrange
88 87 ---------------------------------------
89 88
90 89 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
91 90 > pick eb57da33312f 2 three
92 91 > pick c8e68270e35a 3 four
93 92 > pick 08d98a8350f3 4 five
94 93 > EOF
95 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 94 $ hg up --quiet
97 95
98 96 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
99 97 > pick eb57da33312f 2 three
100 98 > pick c8e68270e35a 3 four
101 99 > pick 08d98a8350f3 4 five
102 100 > EOF
103 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 101 $ hg up --quiet
105 102
106 103 Test config specified default
107 104 -----------------------------
108 105
109 106 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
110 107 > pick c8e68270e35a 3 four
111 108 > pick 08d98a8350f3 4 five
112 109 > EOF
113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 110
115 111 Run on a revision not descendants of the initial parent
116 112 --------------------------------------------------------------------
117 113
118 114 Test the message shown for inconsistent histedit state, which may be
119 115 created (and forgotten) by Mercurial earlier than 2.7. This emulates
120 116 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
121 117 temporarily.
122 118
123 119 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
124 120 @ 4 08d9 five
125 121 |
126 122 o 3 c8e6 four
127 123 |
128 124 o 2 eb57 three
129 125 |
130 126 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
131 127 > edit 08d98a8350f3 4 five
132 128 > EOF
133 129 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 130 reverting alpha
135 131 Make changes as needed, you may commit or record as needed now.
136 132 When you are finished, run hg histedit --continue to resume.
137 133 [1]
138 134
139 135 $ mv .hg/histedit-state .hg/histedit-state.back
140 136 $ hg update --quiet --clean 2
141 137 $ echo alpha >> alpha
142 138 $ mv .hg/histedit-state.back .hg/histedit-state
143 139
144 140 $ hg histedit --continue
145 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 141 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg (glob)
147 142 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
148 143 @ 4 f5ed five
149 144 |
150 145 | o 3 c8e6 four
151 146 |/
152 147 o 2 eb57 three
153 148 |
154 149
155 150 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg
156 151 $ hg strip -q -r f5ed --config extensions.strip=
157 152 $ hg up -q 08d98a8350f3
158 153
159 154 Test that missing revisions are detected
160 155 ---------------------------------------
161 156
162 157 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
163 158 > pick eb57da33312f 2 three
164 159 > pick 08d98a8350f3 4 five
165 160 > EOF
166 161 abort: missing rules for changeset c8e68270e35a
167 162 (use "drop c8e68270e35a" to discard the change)
168 163 [255]
169 164
170 165 Test that extra revisions are detected
171 166 ---------------------------------------
172 167
173 168 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
174 169 > pick 6058cbb6cfd7 0 one
175 170 > pick c8e68270e35a 3 four
176 171 > pick 08d98a8350f3 4 five
177 172 > EOF
178 173 abort: may not use "pick" with changesets other than the ones listed
179 174 [255]
180 175
181 176 Test malformed line
182 177 ---------------------------------------
183 178
184 179 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
185 180 > pickeb57da33312f2three
186 181 > pick c8e68270e35a 3 four
187 182 > pick 08d98a8350f3 4 five
188 183 > EOF
189 184 abort: malformed line "pickeb57da33312f2three"
190 185 [255]
191 186
192 187 Test unknown changeset
193 188 ---------------------------------------
194 189
195 190 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
196 191 > pick 0123456789ab 2 three
197 192 > pick c8e68270e35a 3 four
198 193 > pick 08d98a8350f3 4 five
199 194 > EOF
200 195 abort: unknown changeset 0123456789ab listed
201 196 [255]
202 197
203 198 Test unknown command
204 199 ---------------------------------------
205 200
206 201 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
207 202 > coin eb57da33312f 2 three
208 203 > pick c8e68270e35a 3 four
209 204 > pick 08d98a8350f3 4 five
210 205 > EOF
211 206 abort: unknown action "coin"
212 207 [255]
213 208
214 209 Test duplicated changeset
215 210 ---------------------------------------
216 211
217 212 So one is missing and one appear twice.
218 213
219 214 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
220 215 > pick eb57da33312f 2 three
221 216 > pick eb57da33312f 2 three
222 217 > pick 08d98a8350f3 4 five
223 218 > EOF
224 219 abort: duplicated command for changeset eb57da33312f
225 220 [255]
226 221
227 222 Test short version of command
228 223 ---------------------------------------
229 224
230 225 Note: we use varying amounts of white space between command name and changeset
231 226 short hash. This tests issue3893.
232 227
233 228 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
234 229 > pick eb57da33312f 2 three
235 230 > p c8e68270e35a 3 four
236 231 > f 08d98a8350f3 4 five
237 232 > EOF
238 233 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 234 reverting alpha
240 235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 236 four
242 237 ***
243 238 five
244 239
245 240
246 241
247 242 HG: Enter commit message. Lines beginning with 'HG:' are removed.
248 243 HG: Leave message empty to abort commit.
249 244 HG: --
250 245 HG: user: test
251 246 HG: branch 'default'
252 247 HG: changed alpha
253 248 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 249 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/*-backup.hg (glob)
256 250 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/*-backup.hg (glob)
257 251
258 252 $ hg update -q 2
259 253 $ echo x > x
260 254 $ hg add x
261 255 $ hg commit -m'x' x
262 256 created new head
263 257 $ hg histedit -r 'heads(all())'
264 258 abort: The specified revisions must have exactly one common root
265 259 [255]
266 260
267 261 Test that trimming description using multi-byte characters
268 262 --------------------------------------------------------------------
269 263
270 264 $ python <<EOF
271 265 > fp = open('logfile', 'w')
272 266 > fp.write('12345678901234567890123456789012345678901234567890' +
273 267 > '12345') # there are 5 more columns for 80 columns
274 268 >
275 269 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
276 270 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
277 271 >
278 272 > fp.close()
279 273 > EOF
280 274 $ echo xx >> x
281 275 $ hg --encoding utf-8 commit --logfile logfile
282 276
283 277 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
284 278 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
285 279
286 280 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
287 281 #
288 282 # Commits are listed from least to most recent
289 283 #
290 284 # Commands:
291 285 # p, pick = use commit
292 286 # e, edit = use commit, but stop for amending
293 287 # f, fold = use commit, but combine it with the one above
294 288 # r, roll = like fold, but discard this commit's description
295 289 # d, drop = remove commit from history
296 290 # m, mess = edit commit message without changing commit content
297 291 #
298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 292
300 293 Test --continue with --keep
301 294
302 295 $ hg strip -q -r . --config extensions.strip=
303 296 $ hg histedit '.^' -q --keep --commands - << EOF
304 297 > edit eb57da33312f 2 three
305 298 > pick f3cfcca30c44 4 x
306 299 > EOF
307 300 Make changes as needed, you may commit or record as needed now.
308 301 When you are finished, run hg histedit --continue to resume.
309 302 [1]
310 303 $ echo edit >> alpha
311 304 $ hg histedit -q --continue
312 305 $ hg log -G -T '{rev}:{node|short} {desc}'
313 306 @ 6:8fda0c726bf2 x
314 307 |
315 308 o 5:63379946892c three
316 309 |
317 310 | o 4:f3cfcca30c44 x
318 311 | |
319 312 | | o 3:2a30f3cfee78 four
320 313 | |/ ***
321 314 | | five
322 315 | o 2:eb57da33312f three
323 316 |/
324 317 o 1:579e40513370 two
325 318 |
326 319 o 0:6058cbb6cfd7 one
327 320
328 321
329 322 Test that abort fails gracefully on exception
330 323 ----------------------------------------------
331 324 $ hg histedit . -q --commands - << EOF
332 325 > edit 8fda0c726bf2 6 x
333 326 > EOF
334 327 Make changes as needed, you may commit or record as needed now.
335 328 When you are finished, run hg histedit --continue to resume.
336 329 [1]
337 330 Corrupt histedit state file
338 331 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
339 332 $ mv ../corrupt-histedit .hg/histedit-state
340 333 $ hg histedit --abort
341 334 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
342 335 abort: .*(No such file or directory:|The system cannot find the file specified).* (re)
343 336 [255]
344 337 Histedit state has been exited
345 338 $ hg summary -q
346 339 parent: 5:63379946892c
347 340 commit: 1 added, 1 unknown (new branch head)
348 341 update: 4 new changesets (update)
349 342
350 343 $ cd ..
351 344
352 345 Set up default base revision tests
353 346
354 347 $ hg init defaultbase
355 348 $ cd defaultbase
356 349 $ touch foo
357 350 $ hg -q commit -A -m root
358 351 $ echo 1 > foo
359 352 $ hg commit -m 'public 1'
360 353 $ hg phase --force --public -r .
361 354 $ echo 2 > foo
362 355 $ hg commit -m 'draft after public'
363 356 $ hg -q up -r 1
364 357 $ echo 3 > foo
365 358 $ hg commit -m 'head 1 public'
366 359 created new head
367 360 $ hg phase --force --public -r .
368 361 $ echo 4 > foo
369 362 $ hg commit -m 'head 1 draft 1'
370 363 $ echo 5 > foo
371 364 $ hg commit -m 'head 1 draft 2'
372 365 $ hg -q up -r 2
373 366 $ echo 6 > foo
374 367 $ hg commit -m 'head 2 commit 1'
375 368 $ echo 7 > foo
376 369 $ hg commit -m 'head 2 commit 2'
377 370 $ hg -q up -r 2
378 371 $ echo 8 > foo
379 372 $ hg commit -m 'head 3'
380 373 created new head
381 374 $ hg -q up -r 2
382 375 $ echo 9 > foo
383 376 $ hg commit -m 'head 4'
384 377 created new head
385 378 $ hg merge --tool :local -r 8
386 379 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
387 380 (branch merge, don't forget to commit)
388 381 $ hg commit -m 'merge head 3 into head 4'
389 382 $ echo 11 > foo
390 383 $ hg commit -m 'commit 1 after merge'
391 384 $ echo 12 > foo
392 385 $ hg commit -m 'commit 2 after merge'
393 386
394 387 $ hg log -G -T '{rev}:{node|short} {phase} {desc}\n'
395 388 @ 12:8cde254db839 draft commit 2 after merge
396 389 |
397 390 o 11:6f2f0241f119 draft commit 1 after merge
398 391 |
399 392 o 10:90506cc76b00 draft merge head 3 into head 4
400 393 |\
401 394 | o 9:f8607a373a97 draft head 4
402 395 | |
403 396 o | 8:0da92be05148 draft head 3
404 397 |/
405 398 | o 7:4c35cdf97d5e draft head 2 commit 2
406 399 | |
407 400 | o 6:931820154288 draft head 2 commit 1
408 401 |/
409 402 | o 5:8cdc02b9bc63 draft head 1 draft 2
410 403 | |
411 404 | o 4:463b8c0d2973 draft head 1 draft 1
412 405 | |
413 406 | o 3:23a0c4eefcbf public head 1 public
414 407 | |
415 408 o | 2:4117331c3abb draft draft after public
416 409 |/
417 410 o 1:4426d359ea59 public public 1
418 411 |
419 412 o 0:54136a8ddf32 public root
420 413
421 414
422 415 Default base revision should stop at public changesets
423 416
424 417 $ hg -q up 8cdc02b9bc63
425 418 $ hg histedit --commands - <<EOF
426 419 > pick 463b8c0d2973
427 420 > pick 8cdc02b9bc63
428 421 > EOF
429 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 422
431 423 Default base revision should stop at branchpoint
432 424
433 425 $ hg -q up 4c35cdf97d5e
434 426 $ hg histedit --commands - <<EOF
435 427 > pick 931820154288
436 428 > pick 4c35cdf97d5e
437 429 > EOF
438 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 430
440 431 Default base revision should stop at merge commit
441 432
442 433 $ hg -q up 8cde254db839
443 434 $ hg histedit --commands - <<EOF
444 435 > pick 6f2f0241f119
445 436 > pick 8cde254db839
446 437 > EOF
447 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -1,265 +1,261 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [alias]
5 5 > tglog = log -G --template "{rev}:{node}:{phase} '{desc}'\n"
6 6 > [extensions]
7 7 > histedit=
8 8 > [experimental]
9 9 > histeditng=True
10 10 > EOF
11 11
12 12 Create repo a:
13 13
14 14 $ hg init a
15 15 $ cd a
16 16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
17 17 adding changesets
18 18 adding manifests
19 19 adding file changes
20 20 added 8 changesets with 7 changes to 7 files (+2 heads)
21 21 (run 'hg heads' to see heads, 'hg merge' to merge)
22 22 $ hg up tip
23 23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 24
25 25 $ hg tglog
26 26 @ 7:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
27 27 |
28 28 | o 6:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
29 29 |/|
30 30 o | 5:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
31 31 | |
32 32 | o 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
33 33 |/
34 34 | o 3:32af7686d403cf45b5d95f2d70cebea587ac806a:draft 'D'
35 35 | |
36 36 | o 2:5fddd98957c8a54a4d436dfe1da9d87f21a1b97b:draft 'C'
37 37 | |
38 38 | o 1:42ccdea3bb16d28e1848c95fe2e44c000f3f21b1:draft 'B'
39 39 |/
40 40 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
41 41
42 42
43 43
44 44 Go to D
45 45 $ hg update 3
46 46 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
47 47 edit the history to rebase B onto H
48 48
49 49
50 50 Rebase B onto H
51 51 $ hg histedit 1 --commands - 2>&1 << EOF | fixbundle
52 52 > base 02de42196ebe
53 53 > pick 42ccdea3bb16 B
54 54 > pick 5fddd98957c8 C
55 55 > pick 32af7686d403 D
56 56 > EOF
57 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 57
59 58 $ hg tglog
60 59 @ 7:0937e82309df47d14176ee15e45dbec5fbdef340:draft 'D'
61 60 |
62 61 o 6:f778d1cbddac4ab679d9983c9bb92e4c5e09e7fa:draft 'C'
63 62 |
64 63 o 5:3d41b7cc708545206213a842f96d812d2e73d818:draft 'B'
65 64 |
66 65 o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
67 66 |
68 67 | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
69 68 |/|
70 69 o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
71 70 | |
72 71 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
73 72 |/
74 73 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
75 74
76 75 Rebase back and drop something
77 76 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
78 77 > base cd010b8cd998
79 78 > pick 3d41b7cc7085 B
80 79 > drop f778d1cbddac C
81 80 > pick 0937e82309df D
82 81 > EOF
83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 82
85 83 $ hg tglog
86 84 @ 6:476cc3e4168da2d036b141f7f7dcff7f8e3fe846:draft 'D'
87 85 |
88 86 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
89 87 |
90 88 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
91 89 | |
92 90 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
93 91 | |/|
94 92 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
95 93 |/ /
96 94 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
97 95 |/
98 96 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
99 97
100 98 Split stack
101 99 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
102 100 > base cd010b8cd998
103 101 > pick d273e35dcdf2 B
104 102 > base cd010b8cd998
105 103 > pick 476cc3e4168d D
106 104 > EOF
107 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 105
109 106 $ hg tglog
110 107 @ 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
111 108 |
112 109 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
113 110 |/
114 111 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
115 112 | |
116 113 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
117 114 | |/|
118 115 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
119 116 |/ /
120 117 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
121 118 |/
122 119 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
123 120
124 121 Abort
125 122 $ echo x > B
126 123 $ hg add B
127 124 $ hg commit -m "X"
128 125 $ hg tglog
129 126 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
130 127 |
131 128 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
132 129 |
133 130 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
134 131 |/
135 132 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
136 133 | |
137 134 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
138 135 | |/|
139 136 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
140 137 |/ /
141 138 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
142 139 |/
143 140 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
144 141
145 142 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
146 143 > base d273e35dcdf2 B
147 144 > drop d7a6f907a822 D
148 145 > pick 591369deedfd X
149 146 > EOF
150 147 merging B
151 148 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
152 149 Fix up the change and run hg histedit --continue
153 150 $ hg histedit --abort | fixbundle
154 151 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 152 $ hg tglog
156 153 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
157 154 |
158 155 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
159 156 |
160 157 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
161 158 |/
162 159 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
163 160 | |
164 161 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
165 162 | |/|
166 163 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
167 164 |/ /
168 165 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
169 166 |/
170 167 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
171 168
172 169 Continue
173 170 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
174 171 > base d273e35dcdf2 B
175 172 > drop d7a6f907a822 D
176 173 > pick 591369deedfd X
177 174 > EOF
178 175 merging B
179 176 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
180 177 Fix up the change and run hg histedit --continue
181 178 $ echo b2 > B
182 179 $ hg resolve --mark B
183 180 (no more unresolved files)
184 181 $ hg histedit --continue | fixbundle
185 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 182 $ hg tglog
187 183 @ 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
188 184 |
189 185 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
190 186 |
191 187 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
192 188 | |
193 189 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
194 190 | |/|
195 191 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
196 192 |/ /
197 193 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
198 194 |/
199 195 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
200 196
201 197
202 198 base on a previously picked changeset
203 199 $ echo i > i
204 200 $ hg add i
205 201 $ hg commit -m "I"
206 202 $ echo j > j
207 203 $ hg add j
208 204 $ hg commit -m "J"
209 205 $ hg tglog
210 206 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
211 207 |
212 208 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
213 209 |
214 210 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
215 211 |
216 212 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
217 213 |
218 214 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
219 215 | |
220 216 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
221 217 | |/|
222 218 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
223 219 |/ /
224 220 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
225 221 |/
226 222 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
227 223
228 224 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
229 225 > pick d273e35dcdf2 B
230 226 > pick 03772da75548 X
231 227 > base d273e35dcdf2 B
232 228 > pick e8c55b19d366 J
233 229 > base d273e35dcdf2 B
234 230 > pick b2f90fd8aa85 I
235 231 > EOF
236 232 abort: may not use "base" with changesets within the edited list
237 233
238 234 $ hg --config experimental.histeditng=False histedit 5 --commands - 2>&1 << EOF | fixbundle
239 235 > base cd010b8cd998 A
240 236 > pick d273e35dcdf2 B
241 237 > pick 03772da75548 X
242 238 > pick b2f90fd8aa85 I
243 239 > pick e8c55b19d366 J
244 240 > EOF
245 241 abort: unknown action "base"
246 242
247 243 $ hg tglog
248 244 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
249 245 |
250 246 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
251 247 |
252 248 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
253 249 |
254 250 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
255 251 |
256 252 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
257 253 | |
258 254 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
259 255 | |/|
260 256 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
261 257 |/ /
262 258 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
263 259 |/
264 260 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
265 261
@@ -1,182 +1,180 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ hg init r
9 9 $ cd r
10 10
11 11 $ for x in a b c d e f ; do
12 12 > echo $x > $x
13 13 > hg add $x
14 14 > hg ci -m $x
15 15 > done
16 16
17 17 $ hg book -r 1 will-move-backwards
18 18 $ hg book -r 2 two
19 19 $ hg book -r 2 also-two
20 20 $ hg book -r 3 three
21 21 $ hg book -r 4 four
22 22 $ hg book -r tip five
23 23 $ hg log --graph
24 24 @ changeset: 5:652413bf663e
25 25 | bookmark: five
26 26 | tag: tip
27 27 | user: test
28 28 | date: Thu Jan 01 00:00:00 1970 +0000
29 29 | summary: f
30 30 |
31 31 o changeset: 4:e860deea161a
32 32 | bookmark: four
33 33 | user: test
34 34 | date: Thu Jan 01 00:00:00 1970 +0000
35 35 | summary: e
36 36 |
37 37 o changeset: 3:055a42cdd887
38 38 | bookmark: three
39 39 | user: test
40 40 | date: Thu Jan 01 00:00:00 1970 +0000
41 41 | summary: d
42 42 |
43 43 o changeset: 2:177f92b77385
44 44 | bookmark: also-two
45 45 | bookmark: two
46 46 | user: test
47 47 | date: Thu Jan 01 00:00:00 1970 +0000
48 48 | summary: c
49 49 |
50 50 o changeset: 1:d2ae7f538514
51 51 | bookmark: will-move-backwards
52 52 | user: test
53 53 | date: Thu Jan 01 00:00:00 1970 +0000
54 54 | summary: b
55 55 |
56 56 o changeset: 0:cb9a9f314b8b
57 57 user: test
58 58 date: Thu Jan 01 00:00:00 1970 +0000
59 59 summary: a
60 60
61 61 $ HGEDITOR=cat hg histedit 1
62 62 pick d2ae7f538514 1 b
63 63 pick 177f92b77385 2 c
64 64 pick 055a42cdd887 3 d
65 65 pick e860deea161a 4 e
66 66 pick 652413bf663e 5 f
67 67
68 68 # Edit history between d2ae7f538514 and 652413bf663e
69 69 #
70 70 # Commits are listed from least to most recent
71 71 #
72 72 # Commands:
73 73 # p, pick = use commit
74 74 # e, edit = use commit, but stop for amending
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
77 77 # d, drop = remove commit from history
78 78 # m, mess = edit commit message without changing commit content
79 79 #
80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 80 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
82 81 > pick 177f92b77385 2 c
83 82 > drop d2ae7f538514 1 b
84 83 > pick 055a42cdd887 3 d
85 84 > fold e860deea161a 4 e
86 85 > pick 652413bf663e 5 f
87 86 > EOF
88 87 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
89 88 histedit: moving bookmarks also-two from 177f92b77385 to b346ab9a313d
90 89 histedit: moving bookmarks five from 652413bf663e to cacdfd884a93
91 90 histedit: moving bookmarks four from e860deea161a to 59d9f330561f
92 91 histedit: moving bookmarks three from 055a42cdd887 to 59d9f330561f
93 92 histedit: moving bookmarks two from 177f92b77385 to b346ab9a313d
94 93 histedit: moving bookmarks will-move-backwards from d2ae7f538514 to cb9a9f314b8b
95 94 saved backup bundle to $TESTTMP/r/.hg/strip-backup/d2ae7f538514-48787b8d-backup.hg (glob)
96 95 $ hg log --graph
97 96 @ changeset: 3:cacdfd884a93
98 97 | bookmark: five
99 98 | tag: tip
100 99 | user: test
101 100 | date: Thu Jan 01 00:00:00 1970 +0000
102 101 | summary: f
103 102 |
104 103 o changeset: 2:59d9f330561f
105 104 | bookmark: four
106 105 | bookmark: three
107 106 | user: test
108 107 | date: Thu Jan 01 00:00:00 1970 +0000
109 108 | summary: d
110 109 |
111 110 o changeset: 1:b346ab9a313d
112 111 | bookmark: also-two
113 112 | bookmark: two
114 113 | user: test
115 114 | date: Thu Jan 01 00:00:00 1970 +0000
116 115 | summary: c
117 116 |
118 117 o changeset: 0:cb9a9f314b8b
119 118 bookmark: will-move-backwards
120 119 user: test
121 120 date: Thu Jan 01 00:00:00 1970 +0000
122 121 summary: a
123 122
124 123 $ HGEDITOR=cat hg histedit 1
125 124 pick b346ab9a313d 1 c
126 125 pick 59d9f330561f 2 d
127 126 pick cacdfd884a93 3 f
128 127
129 128 # Edit history between b346ab9a313d and cacdfd884a93
130 129 #
131 130 # Commits are listed from least to most recent
132 131 #
133 132 # Commands:
134 133 # p, pick = use commit
135 134 # e, edit = use commit, but stop for amending
136 135 # f, fold = use commit, but combine it with the one above
137 136 # r, roll = like fold, but discard this commit's description
138 137 # d, drop = remove commit from history
139 138 # m, mess = edit commit message without changing commit content
140 139 #
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 140 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
143 141 > pick b346ab9a313d 1 c
144 142 > pick cacdfd884a93 3 f
145 143 > pick 59d9f330561f 2 d
146 144 > EOF
147 145 histedit: moving bookmarks five from cacdfd884a93 to c04e50810e4b
148 146 histedit: moving bookmarks four from 59d9f330561f to c04e50810e4b
149 147 histedit: moving bookmarks three from 59d9f330561f to c04e50810e4b
150 148 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-backup.hg (glob)
151 149
152 150 We expect 'five' to stay at tip, since the tipmost bookmark is most
153 151 likely the useful signal.
154 152
155 153 $ hg log --graph
156 154 @ changeset: 3:c04e50810e4b
157 155 | bookmark: five
158 156 | bookmark: four
159 157 | bookmark: three
160 158 | tag: tip
161 159 | user: test
162 160 | date: Thu Jan 01 00:00:00 1970 +0000
163 161 | summary: d
164 162 |
165 163 o changeset: 2:c13eb81022ca
166 164 | user: test
167 165 | date: Thu Jan 01 00:00:00 1970 +0000
168 166 | summary: f
169 167 |
170 168 o changeset: 1:b346ab9a313d
171 169 | bookmark: also-two
172 170 | bookmark: two
173 171 | user: test
174 172 | date: Thu Jan 01 00:00:00 1970 +0000
175 173 | summary: c
176 174 |
177 175 o changeset: 0:cb9a9f314b8b
178 176 bookmark: will-move-backwards
179 177 user: test
180 178 date: Thu Jan 01 00:00:00 1970 +0000
181 179 summary: a
182 180
@@ -1,451 +1,443 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init r
11 11 > cd r
12 12 > for x in a b c d e f ; do
13 13 > echo $x > $x
14 14 > hg add $x
15 15 > hg ci -m $x
16 16 > done
17 17 > }
18 18
19 19 $ initrepo
20 20
21 21 log before edit
22 22 $ hg log --graph
23 23 @ changeset: 5:652413bf663e
24 24 | tag: tip
25 25 | user: test
26 26 | date: Thu Jan 01 00:00:00 1970 +0000
27 27 | summary: f
28 28 |
29 29 o changeset: 4:e860deea161a
30 30 | user: test
31 31 | date: Thu Jan 01 00:00:00 1970 +0000
32 32 | summary: e
33 33 |
34 34 o changeset: 3:055a42cdd887
35 35 | user: test
36 36 | date: Thu Jan 01 00:00:00 1970 +0000
37 37 | summary: d
38 38 |
39 39 o changeset: 2:177f92b77385
40 40 | user: test
41 41 | date: Thu Jan 01 00:00:00 1970 +0000
42 42 | summary: c
43 43 |
44 44 o changeset: 1:d2ae7f538514
45 45 | user: test
46 46 | date: Thu Jan 01 00:00:00 1970 +0000
47 47 | summary: b
48 48 |
49 49 o changeset: 0:cb9a9f314b8b
50 50 user: test
51 51 date: Thu Jan 01 00:00:00 1970 +0000
52 52 summary: a
53 53
54 54
55 55 show the edit commands offered
56 56 $ HGEDITOR=cat hg histedit 177f92b77385
57 57 pick 177f92b77385 2 c
58 58 pick 055a42cdd887 3 d
59 59 pick e860deea161a 4 e
60 60 pick 652413bf663e 5 f
61 61
62 62 # Edit history between 177f92b77385 and 652413bf663e
63 63 #
64 64 # Commits are listed from least to most recent
65 65 #
66 66 # Commands:
67 67 # p, pick = use commit
68 68 # e, edit = use commit, but stop for amending
69 69 # f, fold = use commit, but combine it with the one above
70 70 # r, roll = like fold, but discard this commit's description
71 71 # d, drop = remove commit from history
72 72 # m, mess = edit commit message without changing commit content
73 73 #
74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 74
76 75 edit the history
77 76 (use a hacky editor to check histedit-last-edit.txt backup)
78 77
79 78 $ EDITED="$TESTTMP/editedhistory"
80 79 $ cat > $EDITED <<EOF
81 80 > pick 177f92b77385 c
82 81 > pick e860deea161a e
83 82 > pick 652413bf663e f
84 83 > pick 055a42cdd887 d
85 84 > EOF
86 85 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
87 86 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 87
90 88 rules should end up in .hg/histedit-last-edit.txt:
91 89 $ cat .hg/histedit-last-edit.txt
92 90 pick 177f92b77385 c
93 91 pick e860deea161a e
94 92 pick 652413bf663e f
95 93 pick 055a42cdd887 d
96 94
97 95 log after edit
98 96 $ hg log --graph
99 97 @ changeset: 5:07114f51870f
100 98 | tag: tip
101 99 | user: test
102 100 | date: Thu Jan 01 00:00:00 1970 +0000
103 101 | summary: d
104 102 |
105 103 o changeset: 4:8ade9693061e
106 104 | user: test
107 105 | date: Thu Jan 01 00:00:00 1970 +0000
108 106 | summary: f
109 107 |
110 108 o changeset: 3:d8249471110a
111 109 | user: test
112 110 | date: Thu Jan 01 00:00:00 1970 +0000
113 111 | summary: e
114 112 |
115 113 o changeset: 2:177f92b77385
116 114 | user: test
117 115 | date: Thu Jan 01 00:00:00 1970 +0000
118 116 | summary: c
119 117 |
120 118 o changeset: 1:d2ae7f538514
121 119 | user: test
122 120 | date: Thu Jan 01 00:00:00 1970 +0000
123 121 | summary: b
124 122 |
125 123 o changeset: 0:cb9a9f314b8b
126 124 user: test
127 125 date: Thu Jan 01 00:00:00 1970 +0000
128 126 summary: a
129 127
130 128
131 129 put things back
132 130
133 131 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
134 132 > pick 177f92b77385 c
135 133 > pick 07114f51870f d
136 134 > pick d8249471110a e
137 135 > pick 8ade9693061e f
138 136 > EOF
139 137 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 138
142 139 $ hg log --graph
143 140 @ changeset: 5:7eca9b5b1148
144 141 | tag: tip
145 142 | user: test
146 143 | date: Thu Jan 01 00:00:00 1970 +0000
147 144 | summary: f
148 145 |
149 146 o changeset: 4:915da888f2de
150 147 | user: test
151 148 | date: Thu Jan 01 00:00:00 1970 +0000
152 149 | summary: e
153 150 |
154 151 o changeset: 3:10517e47bbbb
155 152 | user: test
156 153 | date: Thu Jan 01 00:00:00 1970 +0000
157 154 | summary: d
158 155 |
159 156 o changeset: 2:177f92b77385
160 157 | user: test
161 158 | date: Thu Jan 01 00:00:00 1970 +0000
162 159 | summary: c
163 160 |
164 161 o changeset: 1:d2ae7f538514
165 162 | user: test
166 163 | date: Thu Jan 01 00:00:00 1970 +0000
167 164 | summary: b
168 165 |
169 166 o changeset: 0:cb9a9f314b8b
170 167 user: test
171 168 date: Thu Jan 01 00:00:00 1970 +0000
172 169 summary: a
173 170
174 171
175 172 slightly different this time
176 173
177 174 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
178 175 > pick 10517e47bbbb d
179 176 > pick 7eca9b5b1148 f
180 177 > pick 915da888f2de e
181 178 > pick 177f92b77385 c
182 179 > EOF
183 180 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
184 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 181 $ hg log --graph
186 182 @ changeset: 5:38b92f448761
187 183 | tag: tip
188 184 | user: test
189 185 | date: Thu Jan 01 00:00:00 1970 +0000
190 186 | summary: c
191 187 |
192 188 o changeset: 4:de71b079d9ce
193 189 | user: test
194 190 | date: Thu Jan 01 00:00:00 1970 +0000
195 191 | summary: e
196 192 |
197 193 o changeset: 3:be9ae3a309c6
198 194 | user: test
199 195 | date: Thu Jan 01 00:00:00 1970 +0000
200 196 | summary: f
201 197 |
202 198 o changeset: 2:799205341b6b
203 199 | user: test
204 200 | date: Thu Jan 01 00:00:00 1970 +0000
205 201 | summary: d
206 202 |
207 203 o changeset: 1:d2ae7f538514
208 204 | user: test
209 205 | date: Thu Jan 01 00:00:00 1970 +0000
210 206 | summary: b
211 207 |
212 208 o changeset: 0:cb9a9f314b8b
213 209 user: test
214 210 date: Thu Jan 01 00:00:00 1970 +0000
215 211 summary: a
216 212
217 213
218 214 keep prevents stripping dead revs
219 215 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
220 216 > pick 799205341b6b d
221 217 > pick be9ae3a309c6 f
222 218 > pick 38b92f448761 c
223 219 > pick de71b079d9ce e
224 220 > EOF
225 221 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
226 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 222 $ hg log --graph
228 223 @ changeset: 7:803ef1c6fcfd
229 224 | tag: tip
230 225 | user: test
231 226 | date: Thu Jan 01 00:00:00 1970 +0000
232 227 | summary: e
233 228 |
234 229 o changeset: 6:ece0b8d93dda
235 230 | parent: 3:be9ae3a309c6
236 231 | user: test
237 232 | date: Thu Jan 01 00:00:00 1970 +0000
238 233 | summary: c
239 234 |
240 235 | o changeset: 5:38b92f448761
241 236 | | user: test
242 237 | | date: Thu Jan 01 00:00:00 1970 +0000
243 238 | | summary: c
244 239 | |
245 240 | o changeset: 4:de71b079d9ce
246 241 |/ user: test
247 242 | date: Thu Jan 01 00:00:00 1970 +0000
248 243 | summary: e
249 244 |
250 245 o changeset: 3:be9ae3a309c6
251 246 | user: test
252 247 | date: Thu Jan 01 00:00:00 1970 +0000
253 248 | summary: f
254 249 |
255 250 o changeset: 2:799205341b6b
256 251 | user: test
257 252 | date: Thu Jan 01 00:00:00 1970 +0000
258 253 | summary: d
259 254 |
260 255 o changeset: 1:d2ae7f538514
261 256 | user: test
262 257 | date: Thu Jan 01 00:00:00 1970 +0000
263 258 | summary: b
264 259 |
265 260 o changeset: 0:cb9a9f314b8b
266 261 user: test
267 262 date: Thu Jan 01 00:00:00 1970 +0000
268 263 summary: a
269 264
270 265
271 266 try with --rev
272 267 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
273 268 > pick de71b079d9ce e
274 269 > pick 38b92f448761 c
275 270 > EOF
276 271 abort: may not use "pick" with changesets other than the ones listed
277 272 $ hg log --graph
278 273 @ changeset: 7:803ef1c6fcfd
279 274 | tag: tip
280 275 | user: test
281 276 | date: Thu Jan 01 00:00:00 1970 +0000
282 277 | summary: e
283 278 |
284 279 o changeset: 6:ece0b8d93dda
285 280 | parent: 3:be9ae3a309c6
286 281 | user: test
287 282 | date: Thu Jan 01 00:00:00 1970 +0000
288 283 | summary: c
289 284 |
290 285 | o changeset: 5:38b92f448761
291 286 | | user: test
292 287 | | date: Thu Jan 01 00:00:00 1970 +0000
293 288 | | summary: c
294 289 | |
295 290 | o changeset: 4:de71b079d9ce
296 291 |/ user: test
297 292 | date: Thu Jan 01 00:00:00 1970 +0000
298 293 | summary: e
299 294 |
300 295 o changeset: 3:be9ae3a309c6
301 296 | user: test
302 297 | date: Thu Jan 01 00:00:00 1970 +0000
303 298 | summary: f
304 299 |
305 300 o changeset: 2:799205341b6b
306 301 | user: test
307 302 | date: Thu Jan 01 00:00:00 1970 +0000
308 303 | summary: d
309 304 |
310 305 o changeset: 1:d2ae7f538514
311 306 | user: test
312 307 | date: Thu Jan 01 00:00:00 1970 +0000
313 308 | summary: b
314 309 |
315 310 o changeset: 0:cb9a9f314b8b
316 311 user: test
317 312 date: Thu Jan 01 00:00:00 1970 +0000
318 313 summary: a
319 314
320 315 Verify that revsetalias entries work with histedit:
321 316 $ cat >> $HGRCPATH <<EOF
322 317 > [revsetalias]
323 318 > grandparent(ARG) = p1(p1(ARG))
324 319 > EOF
325 320 $ echo extra commit >> c
326 321 $ hg ci -m 'extra commit to c'
327 322 $ HGEDITOR=cat hg histedit 'grandparent(.)'
328 323 pick ece0b8d93dda 6 c
329 324 pick 803ef1c6fcfd 7 e
330 325 pick 9c863c565126 8 extra commit to c
331 326
332 327 # Edit history between ece0b8d93dda and 9c863c565126
333 328 #
334 329 # Commits are listed from least to most recent
335 330 #
336 331 # Commands:
337 332 # p, pick = use commit
338 333 # e, edit = use commit, but stop for amending
339 334 # f, fold = use commit, but combine it with the one above
340 335 # r, roll = like fold, but discard this commit's description
341 336 # d, drop = remove commit from history
342 337 # m, mess = edit commit message without changing commit content
343 338 #
344 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
345 339
346 340 should also work if a commit message is missing
347 341 $ BUNDLE="$TESTDIR/missing-comment.hg"
348 342 $ hg init missing
349 343 $ cd missing
350 344 $ hg unbundle $BUNDLE
351 345 adding changesets
352 346 adding manifests
353 347 adding file changes
354 348 added 3 changesets with 3 changes to 1 files
355 349 (run 'hg update' to get a working copy)
356 350 $ hg co tip
357 351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
358 352 $ hg log --graph
359 353 @ changeset: 2:bd22688093b3
360 354 | tag: tip
361 355 | user: Robert Altman <robert.altman@telventDTN.com>
362 356 | date: Mon Nov 28 16:40:04 2011 +0000
363 357 | summary: Update file.
364 358 |
365 359 o changeset: 1:3b3e956f9171
366 360 | user: Robert Altman <robert.altman@telventDTN.com>
367 361 | date: Mon Nov 28 16:37:57 2011 +0000
368 362 |
369 363 o changeset: 0:141947992243
370 364 user: Robert Altman <robert.altman@telventDTN.com>
371 365 date: Mon Nov 28 16:35:28 2011 +0000
372 366 summary: Checked in text file
373 367
374 368 $ hg histedit 0
375 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 369 $ cd ..
377 370
378 371 $ cd ..
379 372
380 373
381 374 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
382 375 $ hg init issue4251
383 376 $ cd issue4251
384 377
385 378 $ mkdir initial-dir
386 379 $ echo foo > initial-dir/initial-file
387 380 $ hg add initial-dir/initial-file
388 381 $ hg commit -m "initial commit"
389 382
390 383 Move the file to a new directory, and in the same commit, change its content:
391 384 $ mkdir another-dir
392 385 $ hg mv initial-dir/initial-file another-dir/
393 386 $ echo changed > another-dir/initial-file
394 387 $ hg commit -m "moved and changed"
395 388
396 389 Rename the file:
397 390 $ hg mv another-dir/initial-file another-dir/renamed-file
398 391 $ hg commit -m "renamed"
399 392
400 393 Now, let's try to fold the second commit into the first:
401 394 $ cat > editor.sh <<EOF
402 395 > #!/bin/sh
403 396 > cat > \$1 <<ENDOF
404 397 > pick b0f4233702ca 0 initial commit
405 398 > fold 5e8704a8f2d2 1 moved and changed
406 399 > pick 40e7299e8fa7 2 renamed
407 400 > ENDOF
408 401 > EOF
409 402
410 403 $ HGEDITOR="sh ./editor.sh" hg histedit 0
411 404 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
412 405 adding another-dir/initial-file (glob)
413 406 removing initial-dir/initial-file (glob)
414 407 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
415 408 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
417 409 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
418 410 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
419 411
420 412 $ hg --config diff.git=yes export 0
421 413 # HG changeset patch
422 414 # User test
423 415 # Date 0 0
424 416 # Thu Jan 01 00:00:00 1970 +0000
425 417 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
426 418 # Parent 0000000000000000000000000000000000000000
427 419 pick b0f4233702ca 0 initial commit
428 420 fold 5e8704a8f2d2 1 moved and changed
429 421 pick 40e7299e8fa7 2 renamed
430 422
431 423 diff --git a/another-dir/initial-file b/another-dir/initial-file
432 424 new file mode 100644
433 425 --- /dev/null
434 426 +++ b/another-dir/initial-file
435 427 @@ -0,0 +1,1 @@
436 428 +changed
437 429
438 430 $ hg --config diff.git=yes export 1
439 431 # HG changeset patch
440 432 # User test
441 433 # Date 0 0
442 434 # Thu Jan 01 00:00:00 1970 +0000
443 435 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
444 436 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
445 437 renamed
446 438
447 439 diff --git a/another-dir/initial-file b/another-dir/renamed-file
448 440 rename from another-dir/initial-file
449 441 rename to another-dir/renamed-file
450 442
451 443 $ cd ..
@@ -1,152 +1,151 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init r
11 11 > cd r
12 12 > for x in a b c d e f ; do
13 13 > echo $x > $x
14 14 > hg add $x
15 15 > hg ci -m $x
16 16 > done
17 17 > }
18 18
19 19 $ initrepo
20 20
21 21 log before edit
22 22 $ hg log --graph
23 23 @ changeset: 5:652413bf663e
24 24 | tag: tip
25 25 | user: test
26 26 | date: Thu Jan 01 00:00:00 1970 +0000
27 27 | summary: f
28 28 |
29 29 o changeset: 4:e860deea161a
30 30 | user: test
31 31 | date: Thu Jan 01 00:00:00 1970 +0000
32 32 | summary: e
33 33 |
34 34 o changeset: 3:055a42cdd887
35 35 | user: test
36 36 | date: Thu Jan 01 00:00:00 1970 +0000
37 37 | summary: d
38 38 |
39 39 o changeset: 2:177f92b77385
40 40 | user: test
41 41 | date: Thu Jan 01 00:00:00 1970 +0000
42 42 | summary: c
43 43 |
44 44 o changeset: 1:d2ae7f538514
45 45 | user: test
46 46 | date: Thu Jan 01 00:00:00 1970 +0000
47 47 | summary: b
48 48 |
49 49 o changeset: 0:cb9a9f314b8b
50 50 user: test
51 51 date: Thu Jan 01 00:00:00 1970 +0000
52 52 summary: a
53 53
54 54
55 55 edit the history
56 56 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
57 57 > drop 177f92b77385 c
58 58 > pick e860deea161a e
59 59 > pick 652413bf663e f
60 60 > pick 055a42cdd887 d
61 61 > EOF
62 62 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 63
65 64 log after edit
66 65 $ hg log --graph
67 66 @ changeset: 4:f518305ce889
68 67 | tag: tip
69 68 | user: test
70 69 | date: Thu Jan 01 00:00:00 1970 +0000
71 70 | summary: d
72 71 |
73 72 o changeset: 3:a4f7421b80f7
74 73 | user: test
75 74 | date: Thu Jan 01 00:00:00 1970 +0000
76 75 | summary: f
77 76 |
78 77 o changeset: 2:ee283cb5f2d5
79 78 | user: test
80 79 | date: Thu Jan 01 00:00:00 1970 +0000
81 80 | summary: e
82 81 |
83 82 o changeset: 1:d2ae7f538514
84 83 | user: test
85 84 | date: Thu Jan 01 00:00:00 1970 +0000
86 85 | summary: b
87 86 |
88 87 o changeset: 0:cb9a9f314b8b
89 88 user: test
90 89 date: Thu Jan 01 00:00:00 1970 +0000
91 90 summary: a
92 91
93 92
94 93 Check histedit_source
95 94
96 95 $ hg log --debug --rev f518305ce889
97 96 changeset: 4:f518305ce889c07cb5bd05522176d75590ef3324
98 97 tag: tip
99 98 phase: draft
100 99 parent: 3:a4f7421b80f79fcc59fff01bcbf4a53d127dd6d3
101 100 parent: -1:0000000000000000000000000000000000000000
102 101 manifest: 4:d3d4f51c157ff242c32ff745d4799aaa26ccda44
103 102 user: test
104 103 date: Thu Jan 01 00:00:00 1970 +0000
105 104 files+: d
106 105 extra: branch=default
107 106 extra: histedit_source=055a42cdd88768532f9cf79daa407fc8d138de9b
108 107 description:
109 108 d
110 109
111 110
112 111
113 112 manifest after edit
114 113 $ hg manifest
115 114 a
116 115 b
117 116 d
118 117 e
119 118 f
120 119
121 120 Drop the last changeset
122 121
123 122 $ hg histedit ee283cb5f2d5 --commands - 2>&1 << EOF | fixbundle
124 123 > pick ee283cb5f2d5 e
125 124 > pick a4f7421b80f7 f
126 125 > drop f518305ce889 d
127 126 > EOF
128 127 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
129 128 $ hg log --graph
130 129 @ changeset: 3:a4f7421b80f7
131 130 | tag: tip
132 131 | user: test
133 132 | date: Thu Jan 01 00:00:00 1970 +0000
134 133 | summary: f
135 134 |
136 135 o changeset: 2:ee283cb5f2d5
137 136 | user: test
138 137 | date: Thu Jan 01 00:00:00 1970 +0000
139 138 | summary: e
140 139 |
141 140 o changeset: 1:d2ae7f538514
142 141 | user: test
143 142 | date: Thu Jan 01 00:00:00 1970 +0000
144 143 | summary: b
145 144 |
146 145 o changeset: 0:cb9a9f314b8b
147 146 user: test
148 147 date: Thu Jan 01 00:00:00 1970 +0000
149 148 summary: a
150 149
151 150
152 151 $ cd ..
@@ -1,482 +1,477 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > strip=
7 7 > EOF
8 8
9 9 $ initrepo ()
10 10 > {
11 11 > hg init r
12 12 > cd r
13 13 > for x in a b c d e f g; do
14 14 > echo $x > $x
15 15 > hg add $x
16 16 > hg ci -m $x
17 17 > done
18 18 > }
19 19
20 20 $ initrepo
21 21
22 22 log before edit
23 23 $ hg log --graph
24 24 @ changeset: 6:3c6a8ed2ebe8
25 25 | tag: tip
26 26 | user: test
27 27 | date: Thu Jan 01 00:00:00 1970 +0000
28 28 | summary: g
29 29 |
30 30 o changeset: 5:652413bf663e
31 31 | user: test
32 32 | date: Thu Jan 01 00:00:00 1970 +0000
33 33 | summary: f
34 34 |
35 35 o changeset: 4:e860deea161a
36 36 | user: test
37 37 | date: Thu Jan 01 00:00:00 1970 +0000
38 38 | summary: e
39 39 |
40 40 o changeset: 3:055a42cdd887
41 41 | user: test
42 42 | date: Thu Jan 01 00:00:00 1970 +0000
43 43 | summary: d
44 44 |
45 45 o changeset: 2:177f92b77385
46 46 | user: test
47 47 | date: Thu Jan 01 00:00:00 1970 +0000
48 48 | summary: c
49 49 |
50 50 o changeset: 1:d2ae7f538514
51 51 | user: test
52 52 | date: Thu Jan 01 00:00:00 1970 +0000
53 53 | summary: b
54 54 |
55 55 o changeset: 0:cb9a9f314b8b
56 56 user: test
57 57 date: Thu Jan 01 00:00:00 1970 +0000
58 58 summary: a
59 59
60 60
61 61 edit the history
62 62 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
63 63 > pick 177f92b77385 c
64 64 > pick 055a42cdd887 d
65 65 > edit e860deea161a e
66 66 > pick 652413bf663e f
67 67 > pick 3c6a8ed2ebe8 g
68 68 > EOF
69 69 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
70 70 Make changes as needed, you may commit or record as needed now.
71 71 When you are finished, run hg histedit --continue to resume.
72 72
73 73 edit the plan via the editor
74 74 $ cat >> $TESTTMP/editplan.sh <<EOF
75 75 > cat > \$1 <<EOF2
76 76 > drop e860deea161a e
77 77 > drop 652413bf663e f
78 78 > drop 3c6a8ed2ebe8 g
79 79 > EOF2
80 80 > EOF
81 81 $ HGEDITOR="sh $TESTTMP/editplan.sh" hg histedit --edit-plan
82 82 $ cat .hg/histedit-state
83 83 v1
84 84 055a42cdd88768532f9cf79daa407fc8d138de9b
85 85 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
86 86 False
87 87 3
88 88 drop
89 89 e860deea161a2f77de56603b340ebbb4536308ae
90 90 drop
91 91 652413bf663ef2a641cab26574e46d5f5a64a55a
92 92 drop
93 93 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
94 94 0
95 95 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
96 96
97 97 edit the plan via --commands
98 98 $ hg histedit --edit-plan --commands - 2>&1 << EOF
99 99 > edit e860deea161a e
100 100 > pick 652413bf663e f
101 101 > drop 3c6a8ed2ebe8 g
102 102 > EOF
103 103 $ cat .hg/histedit-state
104 104 v1
105 105 055a42cdd88768532f9cf79daa407fc8d138de9b
106 106 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
107 107 False
108 108 3
109 109 edit
110 110 e860deea161a2f77de56603b340ebbb4536308ae
111 111 pick
112 112 652413bf663ef2a641cab26574e46d5f5a64a55a
113 113 drop
114 114 3c6a8ed2ebe862cc949d2caa30775dd6f16fb799
115 115 0
116 116 strip-backup/177f92b77385-0ebe6a8f-histedit.hg
117 117
118 118 Go at a random point and try to continue
119 119
120 120 $ hg id -n
121 121 3+
122 122 $ hg up 0
123 123 abort: histedit in progress
124 124 (use 'hg histedit --continue' or 'hg histedit --abort')
125 125 [255]
126 126
127 127 Try to delete necessary commit
128 128 $ hg strip -r 652413b
129 129 abort: histedit in progress, can't strip 652413bf663e
130 130 [255]
131 131
132 132 commit, then edit the revision
133 133 $ hg ci -m 'wat'
134 134 created new head
135 135 $ echo a > e
136 136
137 137 qnew should fail while we're in the middle of the edit step
138 138
139 139 $ hg --config extensions.mq= qnew please-fail
140 140 abort: histedit in progress
141 141 (use 'hg histedit --continue' or 'hg histedit --abort')
142 142 [255]
143 143 $ HGEDITOR='echo foobaz > ' hg histedit --continue 2>&1 | fixbundle
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 144
146 145 $ hg log --graph
147 146 @ changeset: 6:b5f70786f9b0
148 147 | tag: tip
149 148 | user: test
150 149 | date: Thu Jan 01 00:00:00 1970 +0000
151 150 | summary: f
152 151 |
153 152 o changeset: 5:a5e1ba2f7afb
154 153 | user: test
155 154 | date: Thu Jan 01 00:00:00 1970 +0000
156 155 | summary: foobaz
157 156 |
158 157 o changeset: 4:1a60820cd1f6
159 158 | user: test
160 159 | date: Thu Jan 01 00:00:00 1970 +0000
161 160 | summary: wat
162 161 |
163 162 o changeset: 3:055a42cdd887
164 163 | user: test
165 164 | date: Thu Jan 01 00:00:00 1970 +0000
166 165 | summary: d
167 166 |
168 167 o changeset: 2:177f92b77385
169 168 | user: test
170 169 | date: Thu Jan 01 00:00:00 1970 +0000
171 170 | summary: c
172 171 |
173 172 o changeset: 1:d2ae7f538514
174 173 | user: test
175 174 | date: Thu Jan 01 00:00:00 1970 +0000
176 175 | summary: b
177 176 |
178 177 o changeset: 0:cb9a9f314b8b
179 178 user: test
180 179 date: Thu Jan 01 00:00:00 1970 +0000
181 180 summary: a
182 181
183 182
184 183 $ hg cat e
185 184 a
186 185
187 186 Stripping necessary commits should not break --abort
188 187
189 188 $ hg histedit 1a60820cd1f6 --commands - 2>&1 << EOF| fixbundle
190 189 > edit 1a60820cd1f6 wat
191 190 > pick a5e1ba2f7afb foobaz
192 191 > pick b5f70786f9b0 g
193 192 > EOF
194 193 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
195 194 Make changes as needed, you may commit or record as needed now.
196 195 When you are finished, run hg histedit --continue to resume.
197 196
198 197 $ mv .hg/histedit-state .hg/histedit-state.bak
199 198 $ hg strip -q -r b5f70786f9b0
200 199 $ mv .hg/histedit-state.bak .hg/histedit-state
201 200 $ hg histedit --abort
202 201 adding changesets
203 202 adding manifests
204 203 adding file changes
205 204 added 1 changesets with 1 changes to 3 files
206 205 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 206 $ hg log -r .
208 207 changeset: 6:b5f70786f9b0
209 208 tag: tip
210 209 user: test
211 210 date: Thu Jan 01 00:00:00 1970 +0000
212 211 summary: f
213 212
214 213
215 214 check histedit_source
216 215
217 216 $ hg log --debug --rev 5
218 217 changeset: 5:a5e1ba2f7afb899ef1581cea528fd885d2fca70d
219 218 phase: draft
220 219 parent: 4:1a60820cd1f6004a362aa622ebc47d59bc48eb34
221 220 parent: -1:0000000000000000000000000000000000000000
222 221 manifest: 5:5ad3be8791f39117565557781f5464363b918a45
223 222 user: test
224 223 date: Thu Jan 01 00:00:00 1970 +0000
225 224 files: e
226 225 extra: branch=default
227 226 extra: histedit_source=e860deea161a2f77de56603b340ebbb4536308ae
228 227 description:
229 228 foobaz
230 229
231 230
232 231
233 232 $ hg histedit tip --commands - 2>&1 <<EOF| fixbundle
234 233 > edit b5f70786f9b0 f
235 234 > EOF
236 235 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
237 236 Make changes as needed, you may commit or record as needed now.
238 237 When you are finished, run hg histedit --continue to resume.
239 238 $ hg status
240 239 A f
241 240
242 241 $ hg summary
243 242 parent: 5:a5e1ba2f7afb
244 243 foobaz
245 244 branch: default
246 245 commit: 1 added (new branch head)
247 246 update: 1 new changesets (update)
248 247 phases: 7 draft
249 248 hist: 1 remaining (histedit --continue)
250 249
251 250 (test also that editor is invoked if histedit is continued for
252 251 "edit" action)
253 252
254 253 $ HGEDITOR='cat' hg histedit --continue
255 254 f
256 255
257 256
258 257 HG: Enter commit message. Lines beginning with 'HG:' are removed.
259 258 HG: Leave message empty to abort commit.
260 259 HG: --
261 260 HG: user: test
262 261 HG: branch 'default'
263 262 HG: added f
264 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 263 saved backup bundle to $TESTTMP/r/.hg/strip-backup/b5f70786f9b0-c28d9c86-backup.hg (glob)
266 264
267 265 $ hg status
268 266
269 267 log after edit
270 268 $ hg log --limit 1
271 269 changeset: 6:a107ee126658
272 270 tag: tip
273 271 user: test
274 272 date: Thu Jan 01 00:00:00 1970 +0000
275 273 summary: f
276 274
277 275
278 276 say we'll change the message, but don't.
279 277 $ cat > ../edit.sh <<EOF
280 278 > cat "\$1" | sed s/pick/mess/ > tmp
281 279 > mv tmp "\$1"
282 280 > EOF
283 281 $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
284 282 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 283 $ hg status
287 284 $ hg log --limit 1
288 285 changeset: 6:1fd3b2fe7754
289 286 tag: tip
290 287 user: test
291 288 date: Thu Jan 01 00:00:00 1970 +0000
292 289 summary: f
293 290
294 291
295 292 modify the message
296 293
297 294 check saving last-message.txt, at first
298 295
299 296 $ cat > $TESTTMP/commitfailure.py <<EOF
300 297 > from mercurial import error
301 298 > def reposetup(ui, repo):
302 299 > class commitfailure(repo.__class__):
303 300 > def commit(self, *args, **kwargs):
304 301 > raise error.Abort('emulating unexpected abort')
305 302 > repo.__class__ = commitfailure
306 303 > EOF
307 304 $ cat >> .hg/hgrc <<EOF
308 305 > [extensions]
309 306 > # this failure occurs before editor invocation
310 307 > commitfailure = $TESTTMP/commitfailure.py
311 308 > EOF
312 309
313 310 $ cat > $TESTTMP/editor.sh <<EOF
314 311 > echo "==== before editing"
315 312 > cat \$1
316 313 > echo "===="
317 314 > echo "check saving last-message.txt" >> \$1
318 315 > EOF
319 316
320 317 (test that editor is not invoked before transaction starting)
321 318
322 319 $ rm -f .hg/last-message.txt
323 320 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF | fixbundle
324 321 > mess 1fd3b2fe7754 f
325 322 > EOF
326 323 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
327 324 abort: emulating unexpected abort
328 325 $ test -f .hg/last-message.txt
329 326 [1]
330 327
331 328 $ cat >> .hg/hgrc <<EOF
332 329 > [extensions]
333 330 > commitfailure = !
334 331 > EOF
335 332 $ hg histedit --abort -q
336 333
337 334 (test that editor is invoked and commit message is saved into
338 335 "last-message.txt")
339 336
340 337 $ cat >> .hg/hgrc <<EOF
341 338 > [hooks]
342 339 > # this failure occurs after editor invocation
343 340 > pretxncommit.unexpectedabort = false
344 341 > EOF
345 342
346 343 $ hg status --rev '1fd3b2fe7754^1' --rev 1fd3b2fe7754
347 344 A f
348 345
349 346 $ rm -f .hg/last-message.txt
350 347 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
351 348 > mess 1fd3b2fe7754 f
352 349 > EOF
353 350 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
354 351 adding f
355 352 ==== before editing
356 353 f
357 354
358 355
359 356 HG: Enter commit message. Lines beginning with 'HG:' are removed.
360 357 HG: Leave message empty to abort commit.
361 358 HG: --
362 359 HG: user: test
363 360 HG: branch 'default'
364 361 HG: added f
365 362 ====
366 363 note: commit message saved in .hg/last-message.txt
367 364 transaction abort!
368 365 rollback completed
369 366 abort: pretxncommit.unexpectedabort hook exited with status 1
370 367 [255]
371 368 $ cat .hg/last-message.txt
372 369 f
373 370
374 371
375 372 check saving last-message.txt
376 373
377 374 (test also that editor is invoked if histedit is continued for "message"
378 375 action)
379 376
380 377 $ HGEDITOR=cat hg histedit --continue
381 378 f
382 379
383 380
384 381 HG: Enter commit message. Lines beginning with 'HG:' are removed.
385 382 HG: Leave message empty to abort commit.
386 383 HG: --
387 384 HG: user: test
388 385 HG: branch 'default'
389 386 HG: added f
390 387 note: commit message saved in .hg/last-message.txt
391 388 transaction abort!
392 389 rollback completed
393 390 abort: pretxncommit.unexpectedabort hook exited with status 1
394 391 [255]
395 392
396 393 $ cat >> .hg/hgrc <<EOF
397 394 > [hooks]
398 395 > pretxncommit.unexpectedabort =
399 396 > EOF
400 397 $ hg histedit --abort -q
401 398
402 399 then, check "modify the message" itself
403 400
404 401 $ hg histedit tip --commands - 2>&1 << EOF | fixbundle
405 402 > mess 1fd3b2fe7754 f
406 403 > EOF
407 404 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
408 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
409 405 $ hg status
410 406 $ hg log --limit 1
411 407 changeset: 6:62feedb1200e
412 408 tag: tip
413 409 user: test
414 410 date: Thu Jan 01 00:00:00 1970 +0000
415 411 summary: f
416 412
417 413
418 414 rollback should not work after a histedit
419 415 $ hg rollback
420 416 no rollback information available
421 417 [1]
422 418
423 419 $ cd ..
424 420 $ hg clone -qr0 r r0
425 421 $ cd r0
426 422 $ hg phase -fdr0
427 423 $ hg histedit --commands - 0 2>&1 << EOF
428 424 > edit cb9a9f314b8b a > $EDITED
429 425 > EOF
430 426 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
431 427 adding a
432 428 Make changes as needed, you may commit or record as needed now.
433 429 When you are finished, run hg histedit --continue to resume.
434 430 [1]
435 431 $ HGEDITOR=true hg histedit --continue
436 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 432 saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-backup.hg (glob)
438 433
439 434 $ hg log -G
440 435 @ changeset: 0:0efcea34f18a
441 436 tag: tip
442 437 user: test
443 438 date: Thu Jan 01 00:00:00 1970 +0000
444 439 summary: a
445 440
446 441 $ echo foo >> b
447 442 $ hg addr
448 443 adding b
449 444 $ hg ci -m 'add b'
450 445 $ echo foo >> a
451 446 $ hg ci -m 'extend a'
452 447 $ hg phase --public 1
453 448 Attempting to fold a change into a public change should not work:
454 449 $ cat > ../edit.sh <<EOF
455 450 > cat "\$1" | sed s/pick/fold/ > tmp
456 451 > mv tmp "\$1"
457 452 > EOF
458 453 $ HGEDITOR="sh ../edit.sh" hg histedit 2
459 454 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
460 455 reverting a
461 456 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
462 457 warning: histedit rules saved to: .hg/histedit-last-edit.txt
463 458 abort: cannot fold into public change 18aa70c8ad22
464 459 [255]
465 460 $ cat .hg/histedit-last-edit.txt
466 461 fold 0012be4a27ea 2 extend a
467 462
468 463 # Edit history between 0012be4a27ea and 0012be4a27ea
469 464 #
470 465 # Commits are listed from least to most recent
471 466 #
472 467 # Commands:
473 468 # p, fold = use commit
474 469 # e, edit = use commit, but stop for amending
475 470 # f, fold = use commit, but combine it with the one above
476 471 # r, roll = like fold, but discard this commit's description
477 472 # d, drop = remove commit from history
478 473 # m, mess = edit commit message without changing commit content
479 474 #
480 475 TODO: this abort shouldn't be required, but it is for now to leave the repo in
481 476 a clean state.
482 477 $ hg histedit --abort
@@ -1,341 +1,339 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init $1
11 11 > cd $1
12 12 > for x in a b c d e f ; do
13 13 > echo $x$x$x$x$x > $x
14 14 > hg add $x
15 15 > done
16 16 > hg ci -m 'Initial commit'
17 17 > for x in a b c d e f ; do
18 18 > echo $x > $x
19 19 > hg ci -m $x
20 20 > done
21 21 > echo 'I can haz no commute' > e
22 22 > hg ci -m 'does not commute with e'
23 23 > cd ..
24 24 > }
25 25
26 26 $ initrepo r
27 27 $ cd r
28 28 Initial generation of the command files
29 29
30 30 $ EDITED="$TESTTMP/editedhistory"
31 31 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
32 32 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
33 33 $ hg log --template 'fold {node|short} {rev} {desc}\n' -r 7 >> $EDITED
34 34 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
35 35 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
36 36 $ cat $EDITED
37 37 pick 65a9a84f33fd 3 c
38 38 pick 00f1c5383965 4 d
39 39 fold 39522b764e3d 7 does not commute with e
40 40 pick 7b4e2f4b7bcd 5 e
41 41 pick 500cac37a696 6 f
42 42
43 43 log before edit
44 44 $ hg log --graph
45 45 @ changeset: 7:39522b764e3d
46 46 | tag: tip
47 47 | user: test
48 48 | date: Thu Jan 01 00:00:00 1970 +0000
49 49 | summary: does not commute with e
50 50 |
51 51 o changeset: 6:500cac37a696
52 52 | user: test
53 53 | date: Thu Jan 01 00:00:00 1970 +0000
54 54 | summary: f
55 55 |
56 56 o changeset: 5:7b4e2f4b7bcd
57 57 | user: test
58 58 | date: Thu Jan 01 00:00:00 1970 +0000
59 59 | summary: e
60 60 |
61 61 o changeset: 4:00f1c5383965
62 62 | user: test
63 63 | date: Thu Jan 01 00:00:00 1970 +0000
64 64 | summary: d
65 65 |
66 66 o changeset: 3:65a9a84f33fd
67 67 | user: test
68 68 | date: Thu Jan 01 00:00:00 1970 +0000
69 69 | summary: c
70 70 |
71 71 o changeset: 2:da6535b52e45
72 72 | user: test
73 73 | date: Thu Jan 01 00:00:00 1970 +0000
74 74 | summary: b
75 75 |
76 76 o changeset: 1:c1f09da44841
77 77 | user: test
78 78 | date: Thu Jan 01 00:00:00 1970 +0000
79 79 | summary: a
80 80 |
81 81 o changeset: 0:1715188a53c7
82 82 user: test
83 83 date: Thu Jan 01 00:00:00 1970 +0000
84 84 summary: Initial commit
85 85
86 86
87 87 edit the history
88 88 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
89 89 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 90 merging e
91 91 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
92 92 Fix up the change and run hg histedit --continue
93 93
94 94 fix up
95 95 $ echo 'I can haz no commute' > e
96 96 $ hg resolve --mark e
97 97 (no more unresolved files)
98 98 $ cat > cat.py <<EOF
99 99 > import sys
100 100 > print open(sys.argv[1]).read()
101 101 > print
102 102 > print
103 103 > EOF
104 104 $ HGEDITOR="python cat.py" hg histedit --continue 2>&1 | fixbundle | grep -v '2 files removed'
105 105 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 106 d
107 107 ***
108 108 does not commute with e
109 109
110 110
111 111
112 112 HG: Enter commit message. Lines beginning with 'HG:' are removed.
113 113 HG: Leave message empty to abort commit.
114 114 HG: --
115 115 HG: user: test
116 116 HG: branch 'default'
117 117 HG: changed d
118 118 HG: changed e
119 119
120 120
121 121
122 122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 123 merging e
124 124 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
125 125 Fix up the change and run hg histedit --continue
126 126
127 127 just continue this time
128 128 $ hg revert -r 'p1()' e
129 129 $ hg resolve --mark e
130 130 (no more unresolved files)
131 131 $ hg histedit --continue 2>&1 | fixbundle
132 132 7b4e2f4b7bcd: empty changeset
133 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 133
135 134 log after edit
136 135 $ hg log --graph
137 136 @ changeset: 5:d9cf42e54966
138 137 | tag: tip
139 138 | user: test
140 139 | date: Thu Jan 01 00:00:00 1970 +0000
141 140 | summary: f
142 141 |
143 142 o changeset: 4:10486af2e984
144 143 | user: test
145 144 | date: Thu Jan 01 00:00:00 1970 +0000
146 145 | summary: d
147 146 |
148 147 o changeset: 3:65a9a84f33fd
149 148 | user: test
150 149 | date: Thu Jan 01 00:00:00 1970 +0000
151 150 | summary: c
152 151 |
153 152 o changeset: 2:da6535b52e45
154 153 | user: test
155 154 | date: Thu Jan 01 00:00:00 1970 +0000
156 155 | summary: b
157 156 |
158 157 o changeset: 1:c1f09da44841
159 158 | user: test
160 159 | date: Thu Jan 01 00:00:00 1970 +0000
161 160 | summary: a
162 161 |
163 162 o changeset: 0:1715188a53c7
164 163 user: test
165 164 date: Thu Jan 01 00:00:00 1970 +0000
166 165 summary: Initial commit
167 166
168 167
169 168 contents of e
170 169 $ hg cat e
171 170 I can haz no commute
172 171
173 172 manifest
174 173 $ hg manifest
175 174 a
176 175 b
177 176 c
178 177 d
179 178 e
180 179 f
181 180
182 181 $ cd ..
183 182
184 183 Repeat test using "roll", not "fold". "roll" folds in changes but drops message
185 184
186 185 $ initrepo r2
187 186 $ cd r2
188 187
189 188 Initial generation of the command files
190 189
191 190 $ EDITED="$TESTTMP/editedhistory.2"
192 191 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
193 192 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
194 193 $ hg log --template 'roll {node|short} {rev} {desc}\n' -r 7 >> $EDITED
195 194 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
196 195 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
197 196 $ cat $EDITED
198 197 pick 65a9a84f33fd 3 c
199 198 pick 00f1c5383965 4 d
200 199 roll 39522b764e3d 7 does not commute with e
201 200 pick 7b4e2f4b7bcd 5 e
202 201 pick 500cac37a696 6 f
203 202
204 203 log before edit
205 204 $ hg log --graph
206 205 @ changeset: 7:39522b764e3d
207 206 | tag: tip
208 207 | user: test
209 208 | date: Thu Jan 01 00:00:00 1970 +0000
210 209 | summary: does not commute with e
211 210 |
212 211 o changeset: 6:500cac37a696
213 212 | user: test
214 213 | date: Thu Jan 01 00:00:00 1970 +0000
215 214 | summary: f
216 215 |
217 216 o changeset: 5:7b4e2f4b7bcd
218 217 | user: test
219 218 | date: Thu Jan 01 00:00:00 1970 +0000
220 219 | summary: e
221 220 |
222 221 o changeset: 4:00f1c5383965
223 222 | user: test
224 223 | date: Thu Jan 01 00:00:00 1970 +0000
225 224 | summary: d
226 225 |
227 226 o changeset: 3:65a9a84f33fd
228 227 | user: test
229 228 | date: Thu Jan 01 00:00:00 1970 +0000
230 229 | summary: c
231 230 |
232 231 o changeset: 2:da6535b52e45
233 232 | user: test
234 233 | date: Thu Jan 01 00:00:00 1970 +0000
235 234 | summary: b
236 235 |
237 236 o changeset: 1:c1f09da44841
238 237 | user: test
239 238 | date: Thu Jan 01 00:00:00 1970 +0000
240 239 | summary: a
241 240 |
242 241 o changeset: 0:1715188a53c7
243 242 user: test
244 243 date: Thu Jan 01 00:00:00 1970 +0000
245 244 summary: Initial commit
246 245
247 246
248 247 edit the history
249 248 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
250 249 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 250 merging e
252 251 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
253 252 Fix up the change and run hg histedit --continue
254 253
255 254 fix up
256 255 $ echo 'I can haz no commute' > e
257 256 $ hg resolve --mark e
258 257 (no more unresolved files)
259 258 $ hg histedit --continue 2>&1 | fixbundle | grep -v '2 files removed'
260 259 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 260 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 261 merging e
263 262 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
264 263 Fix up the change and run hg histedit --continue
265 264
266 265 just continue this time
267 266 $ hg revert -r 'p1()' e
268 267 $ hg resolve --mark e
269 268 (no more unresolved files)
270 269 $ hg histedit --continue 2>&1 | fixbundle
271 270 7b4e2f4b7bcd: empty changeset
272 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
273 271
274 272 log after edit
275 273 $ hg log --graph
276 274 @ changeset: 5:e7c4f5d4eb75
277 275 | tag: tip
278 276 | user: test
279 277 | date: Thu Jan 01 00:00:00 1970 +0000
280 278 | summary: f
281 279 |
282 280 o changeset: 4:803d1bb561fc
283 281 | user: test
284 282 | date: Thu Jan 01 00:00:00 1970 +0000
285 283 | summary: d
286 284 |
287 285 o changeset: 3:65a9a84f33fd
288 286 | user: test
289 287 | date: Thu Jan 01 00:00:00 1970 +0000
290 288 | summary: c
291 289 |
292 290 o changeset: 2:da6535b52e45
293 291 | user: test
294 292 | date: Thu Jan 01 00:00:00 1970 +0000
295 293 | summary: b
296 294 |
297 295 o changeset: 1:c1f09da44841
298 296 | user: test
299 297 | date: Thu Jan 01 00:00:00 1970 +0000
300 298 | summary: a
301 299 |
302 300 o changeset: 0:1715188a53c7
303 301 user: test
304 302 date: Thu Jan 01 00:00:00 1970 +0000
305 303 summary: Initial commit
306 304
307 305
308 306 contents of e
309 307 $ hg cat e
310 308 I can haz no commute
311 309
312 310 manifest
313 311 $ hg manifest
314 312 a
315 313 b
316 314 c
317 315 d
318 316 e
319 317 f
320 318
321 319 description is taken from rollup target commit
322 320
323 321 $ hg log --debug --rev 4
324 322 changeset: 4:803d1bb561fceac3129ec778db9da249a3106fc3
325 323 phase: draft
326 324 parent: 3:65a9a84f33fdeb1ad5679b3941ec885d2b24027b
327 325 parent: -1:0000000000000000000000000000000000000000
328 326 manifest: 4:b068a323d969f22af1296ec6a5ea9384cef437ac
329 327 user: test
330 328 date: Thu Jan 01 00:00:00 1970 +0000
331 329 files: d e
332 330 extra: branch=default
333 331 extra: histedit_source=00f1c53839651fa5c76d423606811ea5455a79d0,39522b764e3d26103f08bd1fa2ccd3e3d7dbcf4e
334 332 description:
335 333 d
336 334
337 335
338 336
339 337 done with repo r2
340 338
341 339 $ cd ..
@@ -1,563 +1,555 b''
1 1 Test histedit extension: Fold commands
2 2 ======================================
3 3
4 4 This test file is dedicated to testing the fold command in non conflicting
5 5 case.
6 6
7 7 Initialization
8 8 ---------------
9 9
10 10
11 11 $ . "$TESTDIR/histedit-helpers.sh"
12 12
13 13 $ cat >> $HGRCPATH <<EOF
14 14 > [alias]
15 15 > logt = log --template '{rev}:{node|short} {desc|firstline}\n'
16 16 > [extensions]
17 17 > histedit=
18 18 > EOF
19 19
20 20
21 21 Simple folding
22 22 --------------------
23 23 $ initrepo ()
24 24 > {
25 25 > hg init r
26 26 > cd r
27 27 > for x in a b c d e f ; do
28 28 > echo $x > $x
29 29 > hg add $x
30 30 > hg ci -m $x
31 31 > done
32 32 > }
33 33
34 34 $ initrepo
35 35
36 36 log before edit
37 37 $ hg logt --graph
38 38 @ 5:652413bf663e f
39 39 |
40 40 o 4:e860deea161a e
41 41 |
42 42 o 3:055a42cdd887 d
43 43 |
44 44 o 2:177f92b77385 c
45 45 |
46 46 o 1:d2ae7f538514 b
47 47 |
48 48 o 0:cb9a9f314b8b a
49 49
50 50
51 51 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
52 52 > pick e860deea161a e
53 53 > pick 652413bf663e f
54 54 > fold 177f92b77385 c
55 55 > pick 055a42cdd887 d
56 56 > EOF
57 57 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
58 58 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
59 59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 60
62 61 log after edit
63 62 $ hg logt --graph
64 63 @ 4:9c277da72c9b d
65 64 |
66 65 o 3:6de59d13424a f
67 66 |
68 67 o 2:ee283cb5f2d5 e
69 68 |
70 69 o 1:d2ae7f538514 b
71 70 |
72 71 o 0:cb9a9f314b8b a
73 72
74 73
75 74 post-fold manifest
76 75 $ hg manifest
77 76 a
78 77 b
79 78 c
80 79 d
81 80 e
82 81 f
83 82
84 83
85 84 check histedit_source
86 85
87 86 $ hg log --debug --rev 3
88 87 changeset: 3:6de59d13424a8a13acd3e975514aed29dd0d9b2d
89 88 phase: draft
90 89 parent: 2:ee283cb5f2d5955443f23a27b697a04339e9a39a
91 90 parent: -1:0000000000000000000000000000000000000000
92 91 manifest: 3:81eede616954057198ead0b2c73b41d1f392829a
93 92 user: test
94 93 date: Thu Jan 01 00:00:00 1970 +0000
95 94 files+: c f
96 95 extra: branch=default
97 96 extra: histedit_source=a4f7421b80f79fcc59fff01bcbf4a53d127dd6d3,177f92b773850b59254aa5e923436f921b55483b
98 97 description:
99 98 f
100 99 ***
101 100 c
102 101
103 102
104 103
105 104 rollup will fold without preserving the folded commit's message
106 105
107 106 $ OLDHGEDITOR=$HGEDITOR
108 107 $ HGEDITOR=false
109 108 $ hg histedit d2ae7f538514 --commands - 2>&1 <<EOF | fixbundle
110 109 > pick d2ae7f538514 b
111 110 > roll ee283cb5f2d5 e
112 111 > pick 6de59d13424a f
113 112 > pick 9c277da72c9b d
114 113 > EOF
115 114 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
116 115 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
117 116 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 117
120 118 $ HGEDITOR=$OLDHGEDITOR
121 119
122 120 log after edit
123 121 $ hg logt --graph
124 122 @ 3:c4a9eb7989fc d
125 123 |
126 124 o 2:8e03a72b6f83 f
127 125 |
128 126 o 1:391ee782c689 b
129 127 |
130 128 o 0:cb9a9f314b8b a
131 129
132 130
133 131 description is taken from rollup target commit
134 132
135 133 $ hg log --debug --rev 1
136 134 changeset: 1:391ee782c68930be438ccf4c6a403daedbfbffa5
137 135 phase: draft
138 136 parent: 0:cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
139 137 parent: -1:0000000000000000000000000000000000000000
140 138 manifest: 1:b5e112a3a8354e269b1524729f0918662d847c38
141 139 user: test
142 140 date: Thu Jan 01 00:00:00 1970 +0000
143 141 files+: b e
144 142 extra: branch=default
145 143 extra: histedit_source=d2ae7f538514cd87c17547b0de4cea71fe1af9fb,ee283cb5f2d5955443f23a27b697a04339e9a39a
146 144 description:
147 145 b
148 146
149 147
150 148
151 149 check saving last-message.txt
152 150
153 151 $ cat > $TESTTMP/abortfolding.py <<EOF
154 152 > from mercurial import util
155 153 > def abortfolding(ui, repo, hooktype, **kwargs):
156 154 > ctx = repo[kwargs.get('node')]
157 155 > if set(ctx.files()) == set(['c', 'd', 'f']):
158 156 > return True # abort folding commit only
159 157 > ui.warn('allow non-folding commit\\n')
160 158 > EOF
161 159 $ cat > .hg/hgrc <<EOF
162 160 > [hooks]
163 161 > pretxncommit.abortfolding = python:$TESTTMP/abortfolding.py:abortfolding
164 162 > EOF
165 163
166 164 $ cat > $TESTTMP/editor.sh << EOF
167 165 > echo "==== before editing"
168 166 > cat \$1
169 167 > echo "===="
170 168 > echo "check saving last-message.txt" >> \$1
171 169 > EOF
172 170
173 171 $ rm -f .hg/last-message.txt
174 172 $ hg status --rev '8e03a72b6f83^1::c4a9eb7989fc'
175 173 A c
176 174 A d
177 175 A f
178 176 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 8e03a72b6f83 --commands - 2>&1 <<EOF
179 177 > pick 8e03a72b6f83 f
180 178 > fold c4a9eb7989fc d
181 179 > EOF
182 180 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
183 181 adding d
184 182 allow non-folding commit
185 183 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
186 184 ==== before editing
187 185 f
188 186 ***
189 187 c
190 188 ***
191 189 d
192 190
193 191
194 192
195 193 HG: Enter commit message. Lines beginning with 'HG:' are removed.
196 194 HG: Leave message empty to abort commit.
197 195 HG: --
198 196 HG: user: test
199 197 HG: branch 'default'
200 198 HG: added c
201 199 HG: added d
202 200 HG: added f
203 201 ====
204 202 transaction abort!
205 203 rollback completed
206 204 abort: pretxncommit.abortfolding hook failed
207 205 [255]
208 206
209 207 $ cat .hg/last-message.txt
210 208 f
211 209 ***
212 210 c
213 211 ***
214 212 d
215 213
216 214
217 215
218 216 check saving last-message.txt
219 217
220 218 $ cd ..
221 219 $ rm -r r
222 220
223 221 folding preserves initial author
224 222 --------------------------------
225 223
226 224 $ initrepo
227 225
228 226 $ hg ci --user "someone else" --amend --quiet
229 227
230 228 tip before edit
231 229 $ hg log --rev .
232 230 changeset: 5:a00ad806cb55
233 231 tag: tip
234 232 user: someone else
235 233 date: Thu Jan 01 00:00:00 1970 +0000
236 234 summary: f
237 235
238 236
239 237 $ hg histedit e860deea161a --commands - 2>&1 <<EOF | fixbundle
240 238 > pick e860deea161a e
241 239 > fold a00ad806cb55 f
242 240 > EOF
243 241 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
244 242 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
245 243 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 244
248 245 tip after edit
249 246 $ hg log --rev .
250 247 changeset: 4:698d4e8040a1
251 248 tag: tip
252 249 user: test
253 250 date: Thu Jan 01 00:00:00 1970 +0000
254 251 summary: e
255 252
256 253
257 254 $ cd ..
258 255 $ rm -r r
259 256
260 257 folding and creating no new change doesn't break:
261 258 -------------------------------------------------
262 259
263 260 folded content is dropped during a merge. The folded commit should properly disappear.
264 261
265 262 $ mkdir fold-to-empty-test
266 263 $ cd fold-to-empty-test
267 264 $ hg init
268 265 $ printf "1\n2\n3\n" > file
269 266 $ hg add file
270 267 $ hg commit -m '1+2+3'
271 268 $ echo 4 >> file
272 269 $ hg commit -m '+4'
273 270 $ echo 5 >> file
274 271 $ hg commit -m '+5'
275 272 $ echo 6 >> file
276 273 $ hg commit -m '+6'
277 274 $ hg logt --graph
278 275 @ 3:251d831eeec5 +6
279 276 |
280 277 o 2:888f9082bf99 +5
281 278 |
282 279 o 1:617f94f13c0f +4
283 280 |
284 281 o 0:0189ba417d34 1+2+3
285 282
286 283
287 284 $ hg histedit 1 --commands - << EOF
288 285 > pick 617f94f13c0f 1 +4
289 286 > drop 888f9082bf99 2 +5
290 287 > fold 251d831eeec5 3 +6
291 288 > EOF
292 289 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 290 merging file
294 291 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
295 292 Fix up the change and run hg histedit --continue
296 293 [1]
297 294 There were conflicts, we keep P1 content. This
298 295 should effectively drop the changes from +6.
299 296 $ hg status
300 297 M file
301 298 ? file.orig
302 299 $ hg resolve -l
303 300 U file
304 301 $ hg revert -r 'p1()' file
305 302 $ hg resolve --mark file
306 303 (no more unresolved files)
307 304 $ hg histedit --continue
308 305 251d831eeec5: empty changeset
309 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
310 306 saved backup bundle to $TESTTMP/*-backup.hg (glob)
311 307 $ hg logt --graph
312 308 @ 1:617f94f13c0f +4
313 309 |
314 310 o 0:0189ba417d34 1+2+3
315 311
316 312
317 313 $ cd ..
318 314
319 315
320 316 Test fold through dropped
321 317 -------------------------
322 318
323 319
324 320 Test corner case where folded revision is separated from its parent by a
325 321 dropped revision.
326 322
327 323
328 324 $ hg init fold-with-dropped
329 325 $ cd fold-with-dropped
330 326 $ printf "1\n2\n3\n" > file
331 327 $ hg commit -Am '1+2+3'
332 328 adding file
333 329 $ echo 4 >> file
334 330 $ hg commit -m '+4'
335 331 $ echo 5 >> file
336 332 $ hg commit -m '+5'
337 333 $ echo 6 >> file
338 334 $ hg commit -m '+6'
339 335 $ hg logt -G
340 336 @ 3:251d831eeec5 +6
341 337 |
342 338 o 2:888f9082bf99 +5
343 339 |
344 340 o 1:617f94f13c0f +4
345 341 |
346 342 o 0:0189ba417d34 1+2+3
347 343
348 344 $ hg histedit 1 --commands - << EOF
349 345 > pick 617f94f13c0f 1 +4
350 346 > drop 888f9082bf99 2 +5
351 347 > fold 251d831eeec5 3 +6
352 348 > EOF
353 349 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354 350 merging file
355 351 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
356 352 Fix up the change and run hg histedit --continue
357 353 [1]
358 354 $ cat > file << EOF
359 355 > 1
360 356 > 2
361 357 > 3
362 358 > 4
363 359 > 5
364 360 > EOF
365 361 $ hg resolve --mark file
366 362 (no more unresolved files)
367 363 $ hg commit -m '+5.2'
368 364 created new head
369 365 $ echo 6 >> file
370 366 $ HGEDITOR=cat hg histedit --continue
371 367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
372 368 +4
373 369 ***
374 370 +5.2
375 371 ***
376 372 +6
377 373
378 374
379 375
380 376 HG: Enter commit message. Lines beginning with 'HG:' are removed.
381 377 HG: Leave message empty to abort commit.
382 378 HG: --
383 379 HG: user: test
384 380 HG: branch 'default'
385 381 HG: changed file
386 382 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
387 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 383 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/55c8d8dc79ce-4066cd98-backup.hg (glob)
389 384 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/617f94f13c0f-a35700fc-backup.hg (glob)
390 385 $ hg logt -G
391 386 @ 1:10c647b2cdd5 +4
392 387 |
393 388 o 0:0189ba417d34 1+2+3
394 389
395 390 $ hg export tip
396 391 # HG changeset patch
397 392 # User test
398 393 # Date 0 0
399 394 # Thu Jan 01 00:00:00 1970 +0000
400 395 # Node ID 10c647b2cdd54db0603ecb99b2ff5ce66d5a5323
401 396 # Parent 0189ba417d34df9dda55f88b637dcae9917b5964
402 397 +4
403 398 ***
404 399 +5.2
405 400 ***
406 401 +6
407 402
408 403 diff -r 0189ba417d34 -r 10c647b2cdd5 file
409 404 --- a/file Thu Jan 01 00:00:00 1970 +0000
410 405 +++ b/file Thu Jan 01 00:00:00 1970 +0000
411 406 @@ -1,3 +1,6 @@
412 407 1
413 408 2
414 409 3
415 410 +4
416 411 +5
417 412 +6
418 413 $ cd ..
419 414
420 415
421 416 Folding with initial rename (issue3729)
422 417 ---------------------------------------
423 418
424 419 $ hg init fold-rename
425 420 $ cd fold-rename
426 421 $ echo a > a.txt
427 422 $ hg add a.txt
428 423 $ hg commit -m a
429 424 $ hg rename a.txt b.txt
430 425 $ hg commit -m rename
431 426 $ echo b >> b.txt
432 427 $ hg commit -m b
433 428
434 429 $ hg logt --follow b.txt
435 430 2:e0371e0426bc b
436 431 1:1c4f440a8085 rename
437 432 0:6c795aa153cb a
438 433
439 434 $ hg histedit 1c4f440a8085 --commands - 2>&1 << EOF | fixbundle
440 435 > pick 1c4f440a8085 rename
441 436 > fold e0371e0426bc b
442 437 > EOF
443 438 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 439 reverting b.txt
445 440 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
446 441 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
447 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
448 442
449 443 $ hg logt --follow b.txt
450 444 1:cf858d235c76 rename
451 445 0:6c795aa153cb a
452 446
453 447 $ cd ..
454 448
455 449 Folding with swapping
456 450 ---------------------
457 451
458 452 This is an excuse to test hook with histedit temporary commit (issue4422)
459 453
460 454
461 455 $ hg init issue4422
462 456 $ cd issue4422
463 457 $ echo a > a.txt
464 458 $ hg add a.txt
465 459 $ hg commit -m a
466 460 $ echo b > b.txt
467 461 $ hg add b.txt
468 462 $ hg commit -m b
469 463 $ echo c > c.txt
470 464 $ hg add c.txt
471 465 $ hg commit -m c
472 466
473 467 $ hg logt
474 468 2:a1a953ffb4b0 c
475 469 1:199b6bb90248 b
476 470 0:6c795aa153cb a
477 471
478 472 Setup the proper environment variable symbol for the platform, to be subbed
479 473 into the hook command.
480 474 #if windows
481 475 $ NODE="%HG_NODE%"
482 476 #else
483 477 $ NODE="\$HG_NODE"
484 478 #endif
485 479 $ hg histedit 6c795aa153cb --config hooks.commit="echo commit $NODE" --commands - 2>&1 << EOF | fixbundle
486 480 > pick 199b6bb90248 b
487 481 > fold a1a953ffb4b0 c
488 482 > pick 6c795aa153cb a
489 483 > EOF
490 484 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
491 485 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
492 486 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
493 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 487 commit 9599899f62c05f4377548c32bf1c9f1a39634b0c
495 488
496 489 $ hg logt
497 490 1:9599899f62c0 a
498 491 0:79b99e9c8e49 b
499 492
500 493 $ echo "foo" > amended.txt
501 494 $ hg add amended.txt
502 495 $ hg ci -q --config extensions.largefiles= --amend -I amended.txt
503 496
504 497 Test that folding multiple changes in a row doesn't show multiple
505 498 editors.
506 499
507 500 $ echo foo >> foo
508 501 $ hg add foo
509 502 $ hg ci -m foo1
510 503 $ echo foo >> foo
511 504 $ hg ci -m foo2
512 505 $ echo foo >> foo
513 506 $ hg ci -m foo3
514 507 $ hg logt
515 508 4:21679ff7675c foo3
516 509 3:b7389cc4d66e foo2
517 510 2:0e01aeef5fa8 foo1
518 511 1:578c7455730c a
519 512 0:79b99e9c8e49 b
520 513 $ cat > "$TESTTMP/editor.sh" <<EOF
521 514 > echo ran editor >> "$TESTTMP/editorlog.txt"
522 515 > cat \$1 >> "$TESTTMP/editorlog.txt"
523 516 > echo END >> "$TESTTMP/editorlog.txt"
524 517 > echo merged foos > \$1
525 518 > EOF
526 519 $ HGEDITOR="sh \"$TESTTMP/editor.sh\"" hg histedit 1 --commands - 2>&1 <<EOF | fixbundle
527 520 > pick 578c7455730c 1 a
528 521 > pick 0e01aeef5fa8 2 foo1
529 522 > fold b7389cc4d66e 3 foo2
530 523 > fold 21679ff7675c 4 foo3
531 524 > EOF
532 525 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
533 526 reverting foo
534 527 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
535 528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
536 529 merging foo
537 530 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
538 531 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 532 $ hg logt
541 533 2:e8bedbda72c1 merged foos
542 534 1:578c7455730c a
543 535 0:79b99e9c8e49 b
544 536 Editor should have run only once
545 537 $ cat $TESTTMP/editorlog.txt
546 538 ran editor
547 539 foo1
548 540 ***
549 541 foo2
550 542 ***
551 543 foo3
552 544
553 545
554 546
555 547 HG: Enter commit message. Lines beginning with 'HG:' are removed.
556 548 HG: Leave message empty to abort commit.
557 549 HG: --
558 550 HG: user: test
559 551 HG: branch 'default'
560 552 HG: added foo
561 553 END
562 554
563 555 $ cd ..
@@ -1,221 +1,220 b''
1 1 test for old histedit issue #6:
2 2 editing a changeset without any actual change would corrupt the repository
3 3
4 4 $ . "$TESTDIR/histedit-helpers.sh"
5 5
6 6 $ cat >> $HGRCPATH <<EOF
7 7 > [extensions]
8 8 > histedit=
9 9 > EOF
10 10
11 11 $ initrepo ()
12 12 > {
13 13 > dir="$1"
14 14 > comment="$2"
15 15 > if [ -n "${comment}" ]; then
16 16 > echo % ${comment}
17 17 > echo % ${comment} | sed 's:.:-:g'
18 18 > fi
19 19 > hg init ${dir}
20 20 > cd ${dir}
21 21 > for x in a b c d e f ; do
22 22 > echo $x > $x
23 23 > hg add $x
24 24 > hg ci -m $x
25 25 > done
26 26 > cd ..
27 27 > }
28 28
29 29 $ geneditor ()
30 30 > {
31 31 > # generate an editor script for selecting changesets to be edited
32 32 > choice=$1 # changesets that should be edited (using sed line ranges)
33 33 > cat <<EOF | sed 's:^....::'
34 34 > # editing the rules, replacing 'pick' with 'edit' for the chosen lines
35 35 > sed '${choice}s:^pick:edit:' "\$1" > "\${1}.tmp"
36 36 > mv "\${1}.tmp" "\$1"
37 37 > # displaying the resulting rules, minus comments and empty lines
38 38 > sed '/^#/d;/^$/d;s:^:| :' "\$1" >&2
39 39 > EOF
40 40 > }
41 41
42 42 $ startediting ()
43 43 > {
44 44 > # begin an editing session
45 45 > choice="$1" # changesets that should be edited
46 46 > number="$2" # number of changesets considered (from tip)
47 47 > comment="$3"
48 48 > geneditor "${choice}" > edit.sh
49 49 > echo % start editing the history ${comment}
50 50 > HGEDITOR="sh ./edit.sh" hg histedit -- -${number} 2>&1 | fixbundle
51 51 > }
52 52
53 53 $ continueediting ()
54 54 > {
55 55 > # continue an edit already in progress
56 56 > editor="$1" # message editor when finalizing editing
57 57 > comment="$2"
58 58 > echo % finalize changeset editing ${comment}
59 59 > HGEDITOR=${editor} hg histedit --continue 2>&1 | fixbundle
60 60 > }
61 61
62 62 $ graphlog ()
63 63 > {
64 64 > comment="${1:-log}"
65 65 > echo % "${comment}"
66 66 > hg log -G --template '{rev} {node} \"{desc|firstline}\"\n'
67 67 > }
68 68
69 69
70 70 $ initrepo r1 "test editing with no change"
71 71 % test editing with no change
72 72 -----------------------------
73 73 $ cd r1
74 74 $ graphlog "log before editing"
75 75 % log before editing
76 76 @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
77 77 |
78 78 o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
79 79 |
80 80 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
81 81 |
82 82 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
83 83 |
84 84 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
85 85 |
86 86 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
87 87
88 88 $ startediting 2 3 "(not changing anything)" # edit the 2nd of 3 changesets
89 89 % start editing the history (not changing anything)
90 90 | pick 055a42cdd887 3 d
91 91 | edit e860deea161a 4 e
92 92 | pick 652413bf663e 5 f
93 93 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
94 94 Make changes as needed, you may commit or record as needed now.
95 95 When you are finished, run hg histedit --continue to resume.
96 96 $ continueediting true "(leaving commit message unaltered)"
97 97 % finalize changeset editing (leaving commit message unaltered)
98 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 98
100 99
101 100 check state of working copy
102 101 $ hg id
103 102 794fe033d0a0 tip
104 103
105 104 $ graphlog "log after history editing"
106 105 % log after history editing
107 106 @ 5 794fe033d0a030f8df77c5de945fca35c9181c30 "f"
108 107 |
109 108 o 4 04d2fab980779f332dec458cc944f28de8b43435 "e"
110 109 |
111 110 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
112 111 |
113 112 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
114 113 |
115 114 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
116 115 |
117 116 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
118 117
119 118
120 119 $ cd ..
121 120
122 121 $ initrepo r2 "test editing with no change, then abort"
123 122 % test editing with no change, then abort
124 123 -----------------------------------------
125 124 $ cd r2
126 125 $ graphlog "log before editing"
127 126 % log before editing
128 127 @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
129 128 |
130 129 o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
131 130 |
132 131 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
133 132 |
134 133 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
135 134 |
136 135 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
137 136 |
138 137 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
139 138
140 139 $ startediting 1,2 3 "(not changing anything)" # edit the 1st two of 3 changesets
141 140 % start editing the history (not changing anything)
142 141 | edit 055a42cdd887 3 d
143 142 | edit e860deea161a 4 e
144 143 | pick 652413bf663e 5 f
145 144 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
146 145 Make changes as needed, you may commit or record as needed now.
147 146 When you are finished, run hg histedit --continue to resume.
148 147 $ continueediting true "(leaving commit message unaltered)"
149 148 % finalize changeset editing (leaving commit message unaltered)
150 149 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
151 150 Make changes as needed, you may commit or record as needed now.
152 151 When you are finished, run hg histedit --continue to resume.
153 152 $ graphlog "log after first edit"
154 153 % log after first edit
155 154 @ 6 e5ae3ca2f1ffdbd89ec41ebc273a231f7c3022f2 "d"
156 155 |
157 156 | o 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
158 157 | |
159 158 | o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
160 159 | |
161 160 | o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
162 161 |/
163 162 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
164 163 |
165 164 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
166 165 |
167 166 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
168 167
169 168
170 169 abort editing session, after first forcibly updating away
171 170 $ hg up 0
172 171 abort: histedit in progress
173 172 (use 'hg histedit --continue' or 'hg histedit --abort')
174 173 [255]
175 174 $ mv .hg/histedit-state .hg/histedit-state-ignore
176 175 $ hg up 0
177 176 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
178 177 $ mv .hg/histedit-state-ignore .hg/histedit-state
179 178 $ hg sum
180 179 parent: 0:cb9a9f314b8b
181 180 a
182 181 branch: default
183 182 commit: 1 added, 1 unknown (new branch head)
184 183 update: 6 new changesets (update)
185 184 phases: 7 draft
186 185 hist: 2 remaining (histedit --continue)
187 186
188 187 $ hg histedit --abort 2>&1 | fixbundle
189 188
190 189 modified files should survive the abort when we've moved away already
191 190 $ hg st
192 191 A e
193 192 ? edit.sh
194 193
195 194 $ graphlog "log after abort"
196 195 % log after abort
197 196 o 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
198 197 |
199 198 o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
200 199 |
201 200 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
202 201 |
203 202 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
204 203 |
205 204 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
206 205 |
207 206 @ 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
208 207
209 208 aborting and not changing files can skip mentioning updating (no) files
210 209 $ hg up
211 210 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 211 $ hg commit --close-branch -m 'closebranch'
213 212 $ startediting 1 1 "(not changing anything)" # edit the 3rd of 3 changesets
214 213 % start editing the history (not changing anything)
215 214 | edit 292aec348d9e 6 closebranch
216 215 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 216 Make changes as needed, you may commit or record as needed now.
218 217 When you are finished, run hg histedit --continue to resume.
219 218 $ hg histedit --abort
220 219
221 220 $ cd ..
@@ -1,291 +1,289 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ initrepo ()
9 9 > {
10 10 > hg init $1
11 11 > cd $1
12 12 > for x in a b c d e f ; do
13 13 > echo $x$x$x$x$x > $x
14 14 > hg add $x
15 15 > done
16 16 > hg ci -m 'Initial commit'
17 17 > for x in a b c d e f ; do
18 18 > echo $x > $x
19 19 > hg ci -m $x
20 20 > done
21 21 > echo 'I can haz no commute' > e
22 22 > hg ci -m 'does not commute with e'
23 23 > cd ..
24 24 > }
25 25
26 26 $ initrepo r1
27 27 $ cd r1
28 28
29 29 Initial generation of the command files
30 30
31 31 $ EDITED="$TESTTMP/editedhistory"
32 32 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
33 33 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
34 34 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 7 >> $EDITED
35 35 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
36 36 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
37 37 $ cat $EDITED
38 38 pick 65a9a84f33fd 3 c
39 39 pick 00f1c5383965 4 d
40 40 pick 39522b764e3d 7 does not commute with e
41 41 pick 7b4e2f4b7bcd 5 e
42 42 pick 500cac37a696 6 f
43 43
44 44 log before edit
45 45 $ hg log --graph
46 46 @ changeset: 7:39522b764e3d
47 47 | tag: tip
48 48 | user: test
49 49 | date: Thu Jan 01 00:00:00 1970 +0000
50 50 | summary: does not commute with e
51 51 |
52 52 o changeset: 6:500cac37a696
53 53 | user: test
54 54 | date: Thu Jan 01 00:00:00 1970 +0000
55 55 | summary: f
56 56 |
57 57 o changeset: 5:7b4e2f4b7bcd
58 58 | user: test
59 59 | date: Thu Jan 01 00:00:00 1970 +0000
60 60 | summary: e
61 61 |
62 62 o changeset: 4:00f1c5383965
63 63 | user: test
64 64 | date: Thu Jan 01 00:00:00 1970 +0000
65 65 | summary: d
66 66 |
67 67 o changeset: 3:65a9a84f33fd
68 68 | user: test
69 69 | date: Thu Jan 01 00:00:00 1970 +0000
70 70 | summary: c
71 71 |
72 72 o changeset: 2:da6535b52e45
73 73 | user: test
74 74 | date: Thu Jan 01 00:00:00 1970 +0000
75 75 | summary: b
76 76 |
77 77 o changeset: 1:c1f09da44841
78 78 | user: test
79 79 | date: Thu Jan 01 00:00:00 1970 +0000
80 80 | summary: a
81 81 |
82 82 o changeset: 0:1715188a53c7
83 83 user: test
84 84 date: Thu Jan 01 00:00:00 1970 +0000
85 85 summary: Initial commit
86 86
87 87
88 88 edit the history
89 89 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
90 90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 91 merging e
92 92 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
93 93 Fix up the change and run hg histedit --continue
94 94
95 95 abort the edit
96 96 $ hg histedit --abort 2>&1 | fixbundle
97 97 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 98
99 99
100 100 second edit set
101 101
102 102 $ hg log --graph
103 103 @ changeset: 7:39522b764e3d
104 104 | tag: tip
105 105 | user: test
106 106 | date: Thu Jan 01 00:00:00 1970 +0000
107 107 | summary: does not commute with e
108 108 |
109 109 o changeset: 6:500cac37a696
110 110 | user: test
111 111 | date: Thu Jan 01 00:00:00 1970 +0000
112 112 | summary: f
113 113 |
114 114 o changeset: 5:7b4e2f4b7bcd
115 115 | user: test
116 116 | date: Thu Jan 01 00:00:00 1970 +0000
117 117 | summary: e
118 118 |
119 119 o changeset: 4:00f1c5383965
120 120 | user: test
121 121 | date: Thu Jan 01 00:00:00 1970 +0000
122 122 | summary: d
123 123 |
124 124 o changeset: 3:65a9a84f33fd
125 125 | user: test
126 126 | date: Thu Jan 01 00:00:00 1970 +0000
127 127 | summary: c
128 128 |
129 129 o changeset: 2:da6535b52e45
130 130 | user: test
131 131 | date: Thu Jan 01 00:00:00 1970 +0000
132 132 | summary: b
133 133 |
134 134 o changeset: 1:c1f09da44841
135 135 | user: test
136 136 | date: Thu Jan 01 00:00:00 1970 +0000
137 137 | summary: a
138 138 |
139 139 o changeset: 0:1715188a53c7
140 140 user: test
141 141 date: Thu Jan 01 00:00:00 1970 +0000
142 142 summary: Initial commit
143 143
144 144
145 145 edit the history
146 146 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
147 147 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 148 merging e
149 149 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
150 150 Fix up the change and run hg histedit --continue
151 151
152 152 fix up
153 153 $ echo 'I can haz no commute' > e
154 154 $ hg resolve --mark e
155 155 (no more unresolved files)
156 156 $ hg histedit --continue 2>&1 | fixbundle
157 157 merging e
158 158 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
159 159 Fix up the change and run hg histedit --continue
160 160
161 161 This failure is caused by 7b4e2f4b7bcd "e" not rebasing the non commutative
162 162 former children.
163 163
164 164 just continue this time
165 165 $ hg revert -r 'p1()' e
166 166 $ hg resolve --mark e
167 167 (no more unresolved files)
168 168 $ hg histedit --continue 2>&1 | fixbundle
169 169 7b4e2f4b7bcd: empty changeset
170 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
171 170
172 171 log after edit
173 172 $ hg log --graph
174 173 @ changeset: 6:7efe1373e4bc
175 174 | tag: tip
176 175 | user: test
177 176 | date: Thu Jan 01 00:00:00 1970 +0000
178 177 | summary: f
179 178 |
180 179 o changeset: 5:e334d87a1e55
181 180 | user: test
182 181 | date: Thu Jan 01 00:00:00 1970 +0000
183 182 | summary: does not commute with e
184 183 |
185 184 o changeset: 4:00f1c5383965
186 185 | user: test
187 186 | date: Thu Jan 01 00:00:00 1970 +0000
188 187 | summary: d
189 188 |
190 189 o changeset: 3:65a9a84f33fd
191 190 | user: test
192 191 | date: Thu Jan 01 00:00:00 1970 +0000
193 192 | summary: c
194 193 |
195 194 o changeset: 2:da6535b52e45
196 195 | user: test
197 196 | date: Thu Jan 01 00:00:00 1970 +0000
198 197 | summary: b
199 198 |
200 199 o changeset: 1:c1f09da44841
201 200 | user: test
202 201 | date: Thu Jan 01 00:00:00 1970 +0000
203 202 | summary: a
204 203 |
205 204 o changeset: 0:1715188a53c7
206 205 user: test
207 206 date: Thu Jan 01 00:00:00 1970 +0000
208 207 summary: Initial commit
209 208
210 209
211 210 start over
212 211
213 212 $ cd ..
214 213
215 214 $ initrepo r2
216 215 $ cd r2
217 216 $ rm $EDITED
218 217 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
219 218 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
220 219 $ hg log --template 'mess {node|short} {rev} {desc}\n' -r 7 >> $EDITED
221 220 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
222 221 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
223 222 $ cat $EDITED
224 223 pick 65a9a84f33fd 3 c
225 224 pick 00f1c5383965 4 d
226 225 mess 39522b764e3d 7 does not commute with e
227 226 pick 7b4e2f4b7bcd 5 e
228 227 pick 500cac37a696 6 f
229 228
230 229 edit the history, this time with a fold action
231 230 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
232 231 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 232 merging e
234 233 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
235 234 Fix up the change and run hg histedit --continue
236 235
237 236 $ echo 'I can haz no commute' > e
238 237 $ hg resolve --mark e
239 238 (no more unresolved files)
240 239 $ hg histedit --continue 2>&1 | fixbundle
241 240 merging e
242 241 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
243 242 Fix up the change and run hg histedit --continue
244 243 second edit also fails, but just continue
245 244 $ hg revert -r 'p1()' e
246 245 $ hg resolve --mark e
247 246 (no more unresolved files)
248 247 $ hg histedit --continue 2>&1 | fixbundle
249 248 7b4e2f4b7bcd: empty changeset
250 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 249
252 250 post message fix
253 251 $ hg log --graph
254 252 @ changeset: 6:7efe1373e4bc
255 253 | tag: tip
256 254 | user: test
257 255 | date: Thu Jan 01 00:00:00 1970 +0000
258 256 | summary: f
259 257 |
260 258 o changeset: 5:e334d87a1e55
261 259 | user: test
262 260 | date: Thu Jan 01 00:00:00 1970 +0000
263 261 | summary: does not commute with e
264 262 |
265 263 o changeset: 4:00f1c5383965
266 264 | user: test
267 265 | date: Thu Jan 01 00:00:00 1970 +0000
268 266 | summary: d
269 267 |
270 268 o changeset: 3:65a9a84f33fd
271 269 | user: test
272 270 | date: Thu Jan 01 00:00:00 1970 +0000
273 271 | summary: c
274 272 |
275 273 o changeset: 2:da6535b52e45
276 274 | user: test
277 275 | date: Thu Jan 01 00:00:00 1970 +0000
278 276 | summary: b
279 277 |
280 278 o changeset: 1:c1f09da44841
281 279 | user: test
282 280 | date: Thu Jan 01 00:00:00 1970 +0000
283 281 | summary: a
284 282 |
285 283 o changeset: 0:1715188a53c7
286 284 user: test
287 285 date: Thu Jan 01 00:00:00 1970 +0000
288 286 summary: Initial commit
289 287
290 288
291 289 $ cd ..
@@ -1,451 +1,442 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 Enable obsolete
4 4
5 5 $ cat >> $HGRCPATH << EOF
6 6 > [ui]
7 7 > logtemplate= {rev}:{node|short} {desc|firstline}
8 8 > [phases]
9 9 > publish=False
10 10 > [experimental]
11 11 > evolution=createmarkers,allowunstable
12 12 > [extensions]
13 13 > histedit=
14 14 > rebase=
15 15 > EOF
16 16
17 17 $ hg init base
18 18 $ cd base
19 19
20 20 $ for x in a b c d e f ; do
21 21 > echo $x > $x
22 22 > hg add $x
23 23 > hg ci -m $x
24 24 > done
25 25
26 26 $ hg log --graph
27 27 @ 5:652413bf663e f
28 28 |
29 29 o 4:e860deea161a e
30 30 |
31 31 o 3:055a42cdd887 d
32 32 |
33 33 o 2:177f92b77385 c
34 34 |
35 35 o 1:d2ae7f538514 b
36 36 |
37 37 o 0:cb9a9f314b8b a
38 38
39 39
40 40 $ HGEDITOR=cat hg histedit 1
41 41 pick d2ae7f538514 1 b
42 42 pick 177f92b77385 2 c
43 43 pick 055a42cdd887 3 d
44 44 pick e860deea161a 4 e
45 45 pick 652413bf663e 5 f
46 46
47 47 # Edit history between d2ae7f538514 and 652413bf663e
48 48 #
49 49 # Commits are listed from least to most recent
50 50 #
51 51 # Commands:
52 52 # p, pick = use commit
53 53 # e, edit = use commit, but stop for amending
54 54 # f, fold = use commit, but combine it with the one above
55 55 # r, roll = like fold, but discard this commit's description
56 56 # d, drop = remove commit from history
57 57 # m, mess = edit commit message without changing commit content
58 58 #
59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 59 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
61 60 > pick 177f92b77385 2 c
62 61 > drop d2ae7f538514 1 b
63 62 > pick 055a42cdd887 3 d
64 63 > fold e860deea161a 4 e
65 64 > pick 652413bf663e 5 f
66 65 > EOF
67 66 [1]
68 67 $ hg log --graph --hidden
69 68 @ 10:cacdfd884a93 f
70 69 |
71 70 o 9:59d9f330561f d
72 71 |
73 72 | x 8:b558abc46d09 fold-temp-revision e860deea161a
74 73 | |
75 74 | x 7:96e494a2d553 d
76 75 |/
77 76 o 6:b346ab9a313d c
78 77 |
79 78 | x 5:652413bf663e f
80 79 | |
81 80 | x 4:e860deea161a e
82 81 | |
83 82 | x 3:055a42cdd887 d
84 83 | |
85 84 | x 2:177f92b77385 c
86 85 | |
87 86 | x 1:d2ae7f538514 b
88 87 |/
89 88 o 0:cb9a9f314b8b a
90 89
91 90 $ hg debugobsolete
92 91 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (*) {'user': 'test'} (glob)
93 92 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (*) {'user': 'test'} (glob)
94 93 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
95 94 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
96 95 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
97 96 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
98 97 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
99 98
100 99
101 100 Ensure hidden revision does not prevent histedit
102 101 -------------------------------------------------
103 102
104 103 create an hidden revision
105 104
106 105 $ hg histedit 6 --commands - << EOF
107 106 > pick b346ab9a313d 6 c
108 107 > drop 59d9f330561f 7 d
109 108 > pick cacdfd884a93 8 f
110 109 > EOF
111 110 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 111 $ hg log --graph
114 112 @ 11:c13eb81022ca f
115 113 |
116 114 o 6:b346ab9a313d c
117 115 |
118 116 o 0:cb9a9f314b8b a
119 117
120 118 check hidden revision are ignored (6 have hidden children 7 and 8)
121 119
122 120 $ hg histedit 6 --commands - << EOF
123 121 > pick b346ab9a313d 6 c
124 122 > pick c13eb81022ca 8 f
125 123 > EOF
126 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 124
128 125
129 126
130 127 Test that rewriting leaving instability behind is allowed
131 128 ---------------------------------------------------------------------
132 129
133 130 $ hg up '.^'
134 131 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
135 132 $ hg log -r 'children(.)'
136 133 11:c13eb81022ca f (no-eol)
137 134 $ hg histedit -r '.' --commands - <<EOF
138 135 > edit b346ab9a313d 6 c
139 136 > EOF
140 137 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
141 138 adding c
142 139 Make changes as needed, you may commit or record as needed now.
143 140 When you are finished, run hg histedit --continue to resume.
144 141 [1]
145 142 $ echo c >> c
146 143 $ hg histedit --continue
147 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 144
149 145 $ hg log -r 'unstable()'
150 146 11:c13eb81022ca f (no-eol)
151 147
152 148 stabilise
153 149
154 150 $ hg rebase -r 'unstable()' -d .
155 151 rebasing 11:c13eb81022ca "f"
156 152 $ hg up tip -q
157 153
158 154 check that extra has accumulated from histedit and rebase
159 155
160 156 $ hg log -T '{extras % "{key}={value}\n"}\n' -r tip
161 157 branch=default
162 158 histedit_source=cacdfd884a9321ec4e1de275ef3949fa953a1f83
163 159 rebase_source=c13eb81022caa686a369223fe7f926bc4f7db576
164 160
165 161
166 162 Test dropping of changeset on the top of the stack
167 163 -------------------------------------------------------
168 164
169 165 Nothing is rewritten below, the working directory parent must be change for the
170 166 dropped changeset to be hidden.
171 167
172 168 $ cd ..
173 169 $ hg clone base droplast
174 170 updating to branch default
175 171 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 172 $ cd droplast
177 173 $ hg histedit -r '40db8afa467b' --commands - << EOF
178 174 > pick 40db8afa467b 10 c
179 175 > drop 947ece25170f 11 f
180 176 > EOF
181 177 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
182 178 $ hg log -G
183 179 @ 12:40db8afa467b c
184 180 |
185 181 o 0:cb9a9f314b8b a
186 182
187 183
188 184 With rewritten ancestors
189 185
190 186 $ echo e > e
191 187 $ hg add e
192 188 $ hg commit -m g
193 189 $ echo f > f
194 190 $ hg add f
195 191 $ hg commit -m h
196 192 $ hg histedit -r '40db8afa467b' --commands - << EOF
197 193 > pick 47a8561c0449 12 g
198 194 > pick 40db8afa467b 10 c
199 195 > drop 1b3b05f35ff0 13 h
200 196 > EOF
201 197 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
202 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 198 $ hg log -G
204 199 @ 17:ee6544123ab8 c
205 200 |
206 201 o 16:269e713e9eae g
207 202 |
208 203 o 0:cb9a9f314b8b a
209 204
210 205 $ cd ../base
211 206
212 207
213 208
214 209 Test phases support
215 210 ===========================================
216 211
217 212 Check that histedit respect immutability
218 213 -------------------------------------------
219 214
220 215 $ cat >> $HGRCPATH << EOF
221 216 > [ui]
222 217 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
223 218 > EOF
224 219
225 220 $ hg ph -pv '.^'
226 221 phase changed for 2 changesets
227 222 $ hg log -G
228 223 @ 13:947ece25170f (draft) f
229 224 |
230 225 o 12:40db8afa467b (public) c
231 226 |
232 227 o 0:cb9a9f314b8b (public) a
233 228
234 229 $ hg histedit -r '.~2'
235 230 abort: cannot edit public changeset: cb9a9f314b8b
236 231 (see "hg help phases" for details)
237 232 [255]
238 233
239 234
240 235 Prepare further testing
241 236 -------------------------------------------
242 237
243 238 $ for x in g h i j k ; do
244 239 > echo $x > $x
245 240 > hg add $x
246 241 > hg ci -m $x
247 242 > done
248 243 $ hg phase --force --secret .~2
249 244 $ hg log -G
250 245 @ 18:14bda137d5b3 (secret) k
251 246 |
252 247 o 17:c62e7241a4f2 (secret) j
253 248 |
254 249 o 16:9cd3934e05af (secret) i
255 250 |
256 251 o 15:ee4a24fc4dfa (draft) h
257 252 |
258 253 o 14:d22905de3528 (draft) g
259 254 |
260 255 o 13:947ece25170f (draft) f
261 256 |
262 257 o 12:40db8afa467b (public) c
263 258 |
264 259 o 0:cb9a9f314b8b (public) a
265 260
266 261 $ cd ..
267 262
268 263 simple phase conservation
269 264 -------------------------------------------
270 265
271 266 Resulting changeset should conserve the phase of the original one whatever the
272 267 phases.new-commit option is.
273 268
274 269 New-commit as draft (default)
275 270
276 271 $ cp -r base simple-draft
277 272 $ cd simple-draft
278 273 $ hg histedit -r '947ece25170f' --commands - << EOF
279 274 > edit 947ece25170f 11 f
280 275 > pick d22905de3528 12 g
281 276 > pick ee4a24fc4dfa 13 h
282 277 > pick 9cd3934e05af 14 i
283 278 > pick c62e7241a4f2 15 j
284 279 > pick 14bda137d5b3 16 k
285 280 > EOF
286 281 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
287 282 adding f
288 283 Make changes as needed, you may commit or record as needed now.
289 284 When you are finished, run hg histedit --continue to resume.
290 285 [1]
291 286 $ echo f >> f
292 287 $ hg histedit --continue
293 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 288 $ hg log -G
295 289 @ 24:12925f763c90 (secret) k
296 290 |
297 291 o 23:4545a6e77442 (secret) j
298 292 |
299 293 o 22:d947a0798e76 (secret) i
300 294 |
301 295 o 21:28fb35ae4ebb (draft) h
302 296 |
303 297 o 20:10b22a5a9645 (draft) g
304 298 |
305 299 o 19:c5a1db4a69f5 (draft) f
306 300 |
307 301 o 12:40db8afa467b (public) c
308 302 |
309 303 o 0:cb9a9f314b8b (public) a
310 304
311 305 $ cd ..
312 306
313 307
314 308 New-commit as draft (default)
315 309
316 310 $ cp -r base simple-secret
317 311 $ cd simple-secret
318 312 $ cat >> .hg/hgrc << EOF
319 313 > [phases]
320 314 > new-commit=secret
321 315 > EOF
322 316 $ hg histedit -r '947ece25170f' --commands - << EOF
323 317 > edit 947ece25170f 11 f
324 318 > pick d22905de3528 12 g
325 319 > pick ee4a24fc4dfa 13 h
326 320 > pick 9cd3934e05af 14 i
327 321 > pick c62e7241a4f2 15 j
328 322 > pick 14bda137d5b3 16 k
329 323 > EOF
330 324 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
331 325 adding f
332 326 Make changes as needed, you may commit or record as needed now.
333 327 When you are finished, run hg histedit --continue to resume.
334 328 [1]
335 329 $ echo f >> f
336 330 $ hg histedit --continue
337 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 331 $ hg log -G
339 332 @ 24:12925f763c90 (secret) k
340 333 |
341 334 o 23:4545a6e77442 (secret) j
342 335 |
343 336 o 22:d947a0798e76 (secret) i
344 337 |
345 338 o 21:28fb35ae4ebb (draft) h
346 339 |
347 340 o 20:10b22a5a9645 (draft) g
348 341 |
349 342 o 19:c5a1db4a69f5 (draft) f
350 343 |
351 344 o 12:40db8afa467b (public) c
352 345 |
353 346 o 0:cb9a9f314b8b (public) a
354 347
355 348 $ cd ..
356 349
357 350
358 351 Changeset reordering
359 352 -------------------------------------------
360 353
361 354 If a secret changeset is put before a draft one, all descendant should be secret.
362 355 It seems more important to present the secret phase.
363 356
364 357 $ cp -r base reorder
365 358 $ cd reorder
366 359 $ hg histedit -r '947ece25170f' --commands - << EOF
367 360 > pick 947ece25170f 11 f
368 361 > pick c62e7241a4f2 15 j
369 362 > pick d22905de3528 12 g
370 363 > pick 9cd3934e05af 14 i
371 364 > pick ee4a24fc4dfa 13 h
372 365 > pick 14bda137d5b3 16 k
373 366 > EOF
374 367 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
375 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 368 $ hg log -G
377 369 @ 23:9e712162b2c1 (secret) k
378 370 |
379 371 o 22:490861543602 (secret) h
380 372 |
381 373 o 21:86aeda50b70d (secret) i
382 374 |
383 375 o 20:b2fa360bc090 (secret) g
384 376 |
385 377 o 19:e10fb4e3eb8e (secret) j
386 378 |
387 379 o 13:947ece25170f (draft) f
388 380 |
389 381 o 12:40db8afa467b (public) c
390 382 |
391 383 o 0:cb9a9f314b8b (public) a
392 384
393 385 $ cd ..
394 386
395 387 Changeset folding
396 388 -------------------------------------------
397 389
398 390 Folding a secret changeset with a draft one turn the result secret (again,
399 391 better safe than sorry). Folding between same phase changeset still works
400 392
401 393 Note that there is a few reordering in this series for more extensive test
402 394
403 395 $ cp -r base folding
404 396 $ cd folding
405 397 $ cat >> .hg/hgrc << EOF
406 398 > [phases]
407 399 > new-commit=secret
408 400 > EOF
409 401 $ hg histedit -r '947ece25170f' --commands - << EOF
410 402 > pick ee4a24fc4dfa 13 h
411 403 > fold 947ece25170f 11 f
412 404 > pick d22905de3528 12 g
413 405 > fold c62e7241a4f2 15 j
414 406 > pick 9cd3934e05af 14 i
415 407 > fold 14bda137d5b3 16 k
416 408 > EOF
417 409 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
418 410 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
419 411 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 412 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
421 413 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 414 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
423 415 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 416 $ hg log -G
426 417 @ 27:769e8ee8708e (secret) i
427 418 |
428 419 o 24:3de6dbab1b62 (secret) g
429 420 |
430 421 o 21:1d51647632b2 (draft) h
431 422 |
432 423 o 12:40db8afa467b (public) c
433 424 |
434 425 o 0:cb9a9f314b8b (public) a
435 426
436 427 $ hg co 3de6dbab1b62
437 428 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
438 429 $ echo wat >> wat
439 430 $ hg add wat
440 431 $ hg ci -m 'add wat'
441 432 created new head
442 433 $ hg merge 769e8ee8708e
443 434 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 435 (branch merge, don't forget to commit)
445 436 $ hg ci -m 'merge'
446 437 $ echo not wat > wat
447 438 $ hg ci -m 'modify wat'
448 439 $ hg histedit 1d51647632b2
449 440 abort: cannot edit history that contains merges
450 441 [255]
451 442 $ cd ..
@@ -1,147 +1,144 b''
1 1 $ cat >> $HGRCPATH <<EOF
2 2 > [extensions]
3 3 > histedit=
4 4 > EOF
5 5
6 6 $ initrepos ()
7 7 > {
8 8 > hg init r
9 9 > cd r
10 10 > for x in a b c ; do
11 11 > echo $x > $x
12 12 > hg add $x
13 13 > hg ci -m $x
14 14 > done
15 15 > cd ..
16 16 > hg clone r r2 | grep -v updating
17 17 > cd r2
18 18 > for x in d e f ; do
19 19 > echo $x > $x
20 20 > hg add $x
21 21 > hg ci -m $x
22 22 > done
23 23 > cd ..
24 24 > hg init r3
25 25 > cd r3
26 26 > for x in g h i ; do
27 27 > echo $x > $x
28 28 > hg add $x
29 29 > hg ci -m $x
30 30 > done
31 31 > cd ..
32 32 > }
33 33
34 34 $ initrepos
35 35 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 36
37 37 show the edit commands offered by outgoing
38 38 $ cd r2
39 39 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
40 40 pick 055a42cdd887 3 d
41 41 pick e860deea161a 4 e
42 42 pick 652413bf663e 5 f
43 43
44 44 # Edit history between 055a42cdd887 and 652413bf663e
45 45 #
46 46 # Commits are listed from least to most recent
47 47 #
48 48 # Commands:
49 49 # p, pick = use commit
50 50 # e, edit = use commit, but stop for amending
51 51 # f, fold = use commit, but combine it with the one above
52 52 # r, roll = like fold, but discard this commit's description
53 53 # d, drop = remove commit from history
54 54 # m, mess = edit commit message without changing commit content
55 55 #
56 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 56 $ cd ..
58 57
59 58 show the error from unrelated repos
60 59 $ cd r3
61 60 $ HGEDITOR=cat hg histedit --outgoing ../r | grep -v comparing | grep -v searching
62 61 abort: repository is unrelated
63 62 [1]
64 63 $ cd ..
65 64
66 65 show the error from unrelated repos
67 66 $ cd r3
68 67 $ HGEDITOR=cat hg histedit --force --outgoing ../r
69 68 comparing with ../r
70 69 searching for changes
71 70 warning: repository is unrelated
72 71 pick 2a4042b45417 0 g
73 72 pick 68c46b4927ce 1 h
74 73 pick 51281e65ba79 2 i
75 74
76 75 # Edit history between 2a4042b45417 and 51281e65ba79
77 76 #
78 77 # Commits are listed from least to most recent
79 78 #
80 79 # Commands:
81 80 # p, pick = use commit
82 81 # e, edit = use commit, but stop for amending
83 82 # f, fold = use commit, but combine it with the one above
84 83 # r, roll = like fold, but discard this commit's description
85 84 # d, drop = remove commit from history
86 85 # m, mess = edit commit message without changing commit content
87 86 #
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 87 $ cd ..
90 88
91 89 test sensitivity to branch in URL:
92 90
93 91 $ cd r2
94 92 $ hg -q update 2
95 93 $ hg -q branch foo
96 94 $ hg commit -m 'create foo branch'
97 95 $ HGEDITOR=cat hg histedit --outgoing '../r#foo' | grep -v comparing | grep -v searching
98 96 pick f26599ee3441 6 create foo branch
99 97
100 98 # Edit history between f26599ee3441 and f26599ee3441
101 99 #
102 100 # Commits are listed from least to most recent
103 101 #
104 102 # Commands:
105 103 # p, pick = use commit
106 104 # e, edit = use commit, but stop for amending
107 105 # f, fold = use commit, but combine it with the one above
108 106 # r, roll = like fold, but discard this commit's description
109 107 # d, drop = remove commit from history
110 108 # m, mess = edit commit message without changing commit content
111 109 #
112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 110
114 111 test to check number of roots in outgoing revisions
115 112
116 113 $ hg -q outgoing -G --template '{node|short}({branch})' '../r'
117 114 @ f26599ee3441(foo)
118 115
119 116 o 652413bf663e(default)
120 117 |
121 118 o e860deea161a(default)
122 119 |
123 120 o 055a42cdd887(default)
124 121
125 122 $ HGEDITOR=cat hg -q histedit --outgoing '../r'
126 123 abort: there are ambiguous outgoing revisions
127 124 (see "hg help histedit" for more detail)
128 125 [255]
129 126
130 127 $ hg -q update -C 2
131 128 $ echo aa >> a
132 129 $ hg -q commit -m 'another head on default'
133 130 $ hg -q outgoing -G --template '{node|short}({branch})' '../r#default'
134 131 @ 3879dc049647(default)
135 132
136 133 o 652413bf663e(default)
137 134 |
138 135 o e860deea161a(default)
139 136 |
140 137 o 055a42cdd887(default)
141 138
142 139 $ HGEDITOR=cat hg -q histedit --outgoing '../r#default'
143 140 abort: there are ambiguous outgoing revisions
144 141 (see "hg help histedit" for more detail)
145 142 [255]
146 143
147 144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now