##// END OF EJS Templates
histedit: omit useless message from update (histeditaction)...
timeless -
r27405:5837ca67 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 hg.update(repo, self.state.parentctxnode)
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 1084 hg.update(repo, state.parentctxnode)
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,273 +1,265 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 57 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 0 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 58
62 59 $ hg tglog
63 60 @ 7:0937e82309df47d14176ee15e45dbec5fbdef340:draft 'D'
64 61 |
65 62 o 6:f778d1cbddac4ab679d9983c9bb92e4c5e09e7fa:draft 'C'
66 63 |
67 64 o 5:3d41b7cc708545206213a842f96d812d2e73d818:draft 'B'
68 65 |
69 66 o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
70 67 |
71 68 | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
72 69 |/|
73 70 o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
74 71 | |
75 72 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
76 73 |/
77 74 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
78 75
79 76 Rebase back and drop something
80 77 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
81 78 > base cd010b8cd998
82 79 > pick 3d41b7cc7085 B
83 80 > drop f778d1cbddac C
84 81 > pick 0937e82309df D
85 82 > EOF
86 83 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 84
90 85 $ hg tglog
91 86 @ 6:476cc3e4168da2d036b141f7f7dcff7f8e3fe846:draft 'D'
92 87 |
93 88 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
94 89 |
95 90 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
96 91 | |
97 92 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
98 93 | |/|
99 94 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
100 95 |/ /
101 96 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
102 97 |/
103 98 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
104 99
105 100 Split stack
106 101 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
107 102 > base cd010b8cd998
108 103 > pick d273e35dcdf2 B
109 104 > base cd010b8cd998
110 105 > pick 476cc3e4168d D
111 106 > EOF
112 107 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 108
115 109 $ hg tglog
116 110 @ 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
117 111 |
118 112 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
119 113 |/
120 114 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
121 115 | |
122 116 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
123 117 | |/|
124 118 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
125 119 |/ /
126 120 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
127 121 |/
128 122 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
129 123
130 124 Abort
131 125 $ echo x > B
132 126 $ hg add B
133 127 $ hg commit -m "X"
134 128 $ hg tglog
135 129 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
136 130 |
137 131 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
138 132 |
139 133 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
140 134 |/
141 135 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
142 136 | |
143 137 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
144 138 | |/|
145 139 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
146 140 |/ /
147 141 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
148 142 |/
149 143 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
150 144
151 145 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
152 146 > base d273e35dcdf2 B
153 147 > drop d7a6f907a822 D
154 148 > pick 591369deedfd X
155 149 > EOF
156 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
157 150 merging B
158 151 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
159 152 Fix up the change and run hg histedit --continue
160 153 $ hg histedit --abort | fixbundle
161 154 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 155 $ hg tglog
163 156 @ 7:591369deedfdcbf57471e894999a70d7f676186d:draft 'X'
164 157 |
165 158 o 6:d7a6f907a822c4ce6f15662ae45a42aa46d3818a:draft 'D'
166 159 |
167 160 | o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
168 161 |/
169 162 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
170 163 | |
171 164 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
172 165 | |/|
173 166 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
174 167 |/ /
175 168 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
176 169 |/
177 170 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
178 171
179 172 Continue
180 173 $ hg histedit 6 --commands - 2>&1 << EOF | fixbundle
181 174 > base d273e35dcdf2 B
182 175 > drop d7a6f907a822 D
183 176 > pick 591369deedfd X
184 177 > EOF
185 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 178 merging B
187 179 warning: conflicts while merging B! (edit, then use 'hg resolve --mark')
188 180 Fix up the change and run hg histedit --continue
189 181 $ echo b2 > B
190 182 $ hg resolve --mark B
191 183 (no more unresolved files)
192 184 $ hg histedit --continue | fixbundle
193 185 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
194 186 $ hg tglog
195 187 @ 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
196 188 |
197 189 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
198 190 |
199 191 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
200 192 | |
201 193 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
202 194 | |/|
203 195 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
204 196 |/ /
205 197 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
206 198 |/
207 199 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
208 200
209 201
210 202 base on a previously picked changeset
211 203 $ echo i > i
212 204 $ hg add i
213 205 $ hg commit -m "I"
214 206 $ echo j > j
215 207 $ hg add j
216 208 $ hg commit -m "J"
217 209 $ hg tglog
218 210 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
219 211 |
220 212 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
221 213 |
222 214 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
223 215 |
224 216 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
225 217 |
226 218 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
227 219 | |
228 220 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
229 221 | |/|
230 222 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
231 223 |/ /
232 224 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
233 225 |/
234 226 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
235 227
236 228 $ hg histedit 5 --commands - 2>&1 << EOF | fixbundle
237 229 > pick d273e35dcdf2 B
238 230 > pick 03772da75548 X
239 231 > base d273e35dcdf2 B
240 232 > pick e8c55b19d366 J
241 233 > base d273e35dcdf2 B
242 234 > pick b2f90fd8aa85 I
243 235 > EOF
244 236 abort: may not use "base" with changesets within the edited list
245 237
246 238 $ hg --config experimental.histeditng=False histedit 5 --commands - 2>&1 << EOF | fixbundle
247 239 > base cd010b8cd998 A
248 240 > pick d273e35dcdf2 B
249 241 > pick 03772da75548 X
250 242 > pick b2f90fd8aa85 I
251 243 > pick e8c55b19d366 J
252 244 > EOF
253 245 abort: unknown action "base"
254 246
255 247 $ hg tglog
256 248 @ 8:e8c55b19d366b335626e805484110d1d5f6f2ea3:draft 'J'
257 249 |
258 250 o 7:b2f90fd8aa85db5569e3cfc30cd1d7739546368e:draft 'I'
259 251 |
260 252 o 6:03772da75548bb42a8f1eacd8c91d0717a147fcd:draft 'X'
261 253 |
262 254 o 5:d273e35dcdf21a7eb305192ef2e362887cd0a6f8:draft 'B'
263 255 |
264 256 | o 4:02de42196ebee42ef284b6780a87cdc96e8eaab6:draft 'H'
265 257 | |
266 258 | | o 3:eea13746799a9e0bfd88f29d3c2e9dc9389f524f:draft 'G'
267 259 | |/|
268 260 | o | 2:24b6387c8c8cae37178880f3fa95ded3cb1cf785:draft 'F'
269 261 |/ /
270 262 | o 1:9520eea781bcca16c1e15acc0ba14335a0e8e5ba:draft 'E'
271 263 |/
272 264 o 0:cd010b8cd998f3981a5a8115f94f8da4ab506089:draft 'A'
273 265
@@ -1,460 +1,451 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 74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 75
76 76 edit the history
77 77 (use a hacky editor to check histedit-last-edit.txt backup)
78 78
79 79 $ EDITED="$TESTTMP/editedhistory"
80 80 $ cat > $EDITED <<EOF
81 81 > pick 177f92b77385 c
82 82 > pick e860deea161a e
83 83 > pick 652413bf663e f
84 84 > pick 055a42cdd887 d
85 85 > EOF
86 86 $ HGEDITOR="cat \"$EDITED\" > " hg histedit 177f92b77385 2>&1 | fixbundle
87 87 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
88 88 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 89
92 90 rules should end up in .hg/histedit-last-edit.txt:
93 91 $ cat .hg/histedit-last-edit.txt
94 92 pick 177f92b77385 c
95 93 pick e860deea161a e
96 94 pick 652413bf663e f
97 95 pick 055a42cdd887 d
98 96
99 97 log after edit
100 98 $ hg log --graph
101 99 @ changeset: 5:07114f51870f
102 100 | tag: tip
103 101 | user: test
104 102 | date: Thu Jan 01 00:00:00 1970 +0000
105 103 | summary: d
106 104 |
107 105 o changeset: 4:8ade9693061e
108 106 | user: test
109 107 | date: Thu Jan 01 00:00:00 1970 +0000
110 108 | summary: f
111 109 |
112 110 o changeset: 3:d8249471110a
113 111 | user: test
114 112 | date: Thu Jan 01 00:00:00 1970 +0000
115 113 | summary: e
116 114 |
117 115 o changeset: 2:177f92b77385
118 116 | user: test
119 117 | date: Thu Jan 01 00:00:00 1970 +0000
120 118 | summary: c
121 119 |
122 120 o changeset: 1:d2ae7f538514
123 121 | user: test
124 122 | date: Thu Jan 01 00:00:00 1970 +0000
125 123 | summary: b
126 124 |
127 125 o changeset: 0:cb9a9f314b8b
128 126 user: test
129 127 date: Thu Jan 01 00:00:00 1970 +0000
130 128 summary: a
131 129
132 130
133 131 put things back
134 132
135 133 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
136 134 > pick 177f92b77385 c
137 135 > pick 07114f51870f d
138 136 > pick d8249471110a e
139 137 > pick 8ade9693061e f
140 138 > EOF
141 139 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
142 140 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 141
146 142 $ hg log --graph
147 143 @ changeset: 5:7eca9b5b1148
148 144 | tag: tip
149 145 | user: test
150 146 | date: Thu Jan 01 00:00:00 1970 +0000
151 147 | summary: f
152 148 |
153 149 o changeset: 4:915da888f2de
154 150 | user: test
155 151 | date: Thu Jan 01 00:00:00 1970 +0000
156 152 | summary: e
157 153 |
158 154 o changeset: 3:10517e47bbbb
159 155 | user: test
160 156 | date: Thu Jan 01 00:00:00 1970 +0000
161 157 | summary: d
162 158 |
163 159 o changeset: 2:177f92b77385
164 160 | user: test
165 161 | date: Thu Jan 01 00:00:00 1970 +0000
166 162 | summary: c
167 163 |
168 164 o changeset: 1:d2ae7f538514
169 165 | user: test
170 166 | date: Thu Jan 01 00:00:00 1970 +0000
171 167 | summary: b
172 168 |
173 169 o changeset: 0:cb9a9f314b8b
174 170 user: test
175 171 date: Thu Jan 01 00:00:00 1970 +0000
176 172 summary: a
177 173
178 174
179 175 slightly different this time
180 176
181 177 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
182 178 > pick 10517e47bbbb d
183 179 > pick 7eca9b5b1148 f
184 180 > pick 915da888f2de e
185 181 > pick 177f92b77385 c
186 182 > EOF
187 183 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
188 184 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 185 $ hg log --graph
193 186 @ changeset: 5:38b92f448761
194 187 | tag: tip
195 188 | user: test
196 189 | date: Thu Jan 01 00:00:00 1970 +0000
197 190 | summary: c
198 191 |
199 192 o changeset: 4:de71b079d9ce
200 193 | user: test
201 194 | date: Thu Jan 01 00:00:00 1970 +0000
202 195 | summary: e
203 196 |
204 197 o changeset: 3:be9ae3a309c6
205 198 | user: test
206 199 | date: Thu Jan 01 00:00:00 1970 +0000
207 200 | summary: f
208 201 |
209 202 o changeset: 2:799205341b6b
210 203 | user: test
211 204 | date: Thu Jan 01 00:00:00 1970 +0000
212 205 | summary: d
213 206 |
214 207 o changeset: 1:d2ae7f538514
215 208 | user: test
216 209 | date: Thu Jan 01 00:00:00 1970 +0000
217 210 | summary: b
218 211 |
219 212 o changeset: 0:cb9a9f314b8b
220 213 user: test
221 214 date: Thu Jan 01 00:00:00 1970 +0000
222 215 summary: a
223 216
224 217
225 218 keep prevents stripping dead revs
226 219 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
227 220 > pick 799205341b6b d
228 221 > pick be9ae3a309c6 f
229 222 > pick 38b92f448761 c
230 223 > pick de71b079d9ce e
231 224 > EOF
232 225 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
233 226 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 227 $ hg log --graph
236 228 @ changeset: 7:803ef1c6fcfd
237 229 | tag: tip
238 230 | user: test
239 231 | date: Thu Jan 01 00:00:00 1970 +0000
240 232 | summary: e
241 233 |
242 234 o changeset: 6:ece0b8d93dda
243 235 | parent: 3:be9ae3a309c6
244 236 | user: test
245 237 | date: Thu Jan 01 00:00:00 1970 +0000
246 238 | summary: c
247 239 |
248 240 | o changeset: 5:38b92f448761
249 241 | | user: test
250 242 | | date: Thu Jan 01 00:00:00 1970 +0000
251 243 | | summary: c
252 244 | |
253 245 | o changeset: 4:de71b079d9ce
254 246 |/ user: test
255 247 | date: Thu Jan 01 00:00:00 1970 +0000
256 248 | summary: e
257 249 |
258 250 o changeset: 3:be9ae3a309c6
259 251 | user: test
260 252 | date: Thu Jan 01 00:00:00 1970 +0000
261 253 | summary: f
262 254 |
263 255 o changeset: 2:799205341b6b
264 256 | user: test
265 257 | date: Thu Jan 01 00:00:00 1970 +0000
266 258 | summary: d
267 259 |
268 260 o changeset: 1:d2ae7f538514
269 261 | user: test
270 262 | date: Thu Jan 01 00:00:00 1970 +0000
271 263 | summary: b
272 264 |
273 265 o changeset: 0:cb9a9f314b8b
274 266 user: test
275 267 date: Thu Jan 01 00:00:00 1970 +0000
276 268 summary: a
277 269
278 270
279 271 try with --rev
280 272 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
281 273 > pick de71b079d9ce e
282 274 > pick 38b92f448761 c
283 275 > EOF
284 276 abort: may not use "pick" with changesets other than the ones listed
285 277 $ hg log --graph
286 278 @ changeset: 7:803ef1c6fcfd
287 279 | tag: tip
288 280 | user: test
289 281 | date: Thu Jan 01 00:00:00 1970 +0000
290 282 | summary: e
291 283 |
292 284 o changeset: 6:ece0b8d93dda
293 285 | parent: 3:be9ae3a309c6
294 286 | user: test
295 287 | date: Thu Jan 01 00:00:00 1970 +0000
296 288 | summary: c
297 289 |
298 290 | o changeset: 5:38b92f448761
299 291 | | user: test
300 292 | | date: Thu Jan 01 00:00:00 1970 +0000
301 293 | | summary: c
302 294 | |
303 295 | o changeset: 4:de71b079d9ce
304 296 |/ user: test
305 297 | date: Thu Jan 01 00:00:00 1970 +0000
306 298 | summary: e
307 299 |
308 300 o changeset: 3:be9ae3a309c6
309 301 | user: test
310 302 | date: Thu Jan 01 00:00:00 1970 +0000
311 303 | summary: f
312 304 |
313 305 o changeset: 2:799205341b6b
314 306 | user: test
315 307 | date: Thu Jan 01 00:00:00 1970 +0000
316 308 | summary: d
317 309 |
318 310 o changeset: 1:d2ae7f538514
319 311 | user: test
320 312 | date: Thu Jan 01 00:00:00 1970 +0000
321 313 | summary: b
322 314 |
323 315 o changeset: 0:cb9a9f314b8b
324 316 user: test
325 317 date: Thu Jan 01 00:00:00 1970 +0000
326 318 summary: a
327 319
328 320 Verify that revsetalias entries work with histedit:
329 321 $ cat >> $HGRCPATH <<EOF
330 322 > [revsetalias]
331 323 > grandparent(ARG) = p1(p1(ARG))
332 324 > EOF
333 325 $ echo extra commit >> c
334 326 $ hg ci -m 'extra commit to c'
335 327 $ HGEDITOR=cat hg histedit 'grandparent(.)'
336 328 pick ece0b8d93dda 6 c
337 329 pick 803ef1c6fcfd 7 e
338 330 pick 9c863c565126 8 extra commit to c
339 331
340 332 # Edit history between ece0b8d93dda and 9c863c565126
341 333 #
342 334 # Commits are listed from least to most recent
343 335 #
344 336 # Commands:
345 337 # p, pick = use commit
346 338 # e, edit = use commit, but stop for amending
347 339 # f, fold = use commit, but combine it with the one above
348 340 # r, roll = like fold, but discard this commit's description
349 341 # d, drop = remove commit from history
350 342 # m, mess = edit commit message without changing commit content
351 343 #
352 344 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 345
354 346 should also work if a commit message is missing
355 347 $ BUNDLE="$TESTDIR/missing-comment.hg"
356 348 $ hg init missing
357 349 $ cd missing
358 350 $ hg unbundle $BUNDLE
359 351 adding changesets
360 352 adding manifests
361 353 adding file changes
362 354 added 3 changesets with 3 changes to 1 files
363 355 (run 'hg update' to get a working copy)
364 356 $ hg co tip
365 357 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 358 $ hg log --graph
367 359 @ changeset: 2:bd22688093b3
368 360 | tag: tip
369 361 | user: Robert Altman <robert.altman@telventDTN.com>
370 362 | date: Mon Nov 28 16:40:04 2011 +0000
371 363 | summary: Update file.
372 364 |
373 365 o changeset: 1:3b3e956f9171
374 366 | user: Robert Altman <robert.altman@telventDTN.com>
375 367 | date: Mon Nov 28 16:37:57 2011 +0000
376 368 |
377 369 o changeset: 0:141947992243
378 370 user: Robert Altman <robert.altman@telventDTN.com>
379 371 date: Mon Nov 28 16:35:28 2011 +0000
380 372 summary: Checked in text file
381 373
382 374 $ hg histedit 0
383 375 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 376 $ cd ..
385 377
386 378 $ cd ..
387 379
388 380
389 381 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
390 382 $ hg init issue4251
391 383 $ cd issue4251
392 384
393 385 $ mkdir initial-dir
394 386 $ echo foo > initial-dir/initial-file
395 387 $ hg add initial-dir/initial-file
396 388 $ hg commit -m "initial commit"
397 389
398 390 Move the file to a new directory, and in the same commit, change its content:
399 391 $ mkdir another-dir
400 392 $ hg mv initial-dir/initial-file another-dir/
401 393 $ echo changed > another-dir/initial-file
402 394 $ hg commit -m "moved and changed"
403 395
404 396 Rename the file:
405 397 $ hg mv another-dir/initial-file another-dir/renamed-file
406 398 $ hg commit -m "renamed"
407 399
408 400 Now, let's try to fold the second commit into the first:
409 401 $ cat > editor.sh <<EOF
410 402 > #!/bin/sh
411 403 > cat > \$1 <<ENDOF
412 404 > pick b0f4233702ca 0 initial commit
413 405 > fold 5e8704a8f2d2 1 moved and changed
414 406 > pick 40e7299e8fa7 2 renamed
415 407 > ENDOF
416 408 > EOF
417 409
418 410 $ HGEDITOR="sh ./editor.sh" hg histedit 0
419 411 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 412 adding another-dir/initial-file (glob)
421 413 removing initial-dir/initial-file (glob)
422 414 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
423 415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 416 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 417 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
427 418 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
428 419
429 420 $ hg --config diff.git=yes export 0
430 421 # HG changeset patch
431 422 # User test
432 423 # Date 0 0
433 424 # Thu Jan 01 00:00:00 1970 +0000
434 425 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
435 426 # Parent 0000000000000000000000000000000000000000
436 427 pick b0f4233702ca 0 initial commit
437 428 fold 5e8704a8f2d2 1 moved and changed
438 429 pick 40e7299e8fa7 2 renamed
439 430
440 431 diff --git a/another-dir/initial-file b/another-dir/initial-file
441 432 new file mode 100644
442 433 --- /dev/null
443 434 +++ b/another-dir/initial-file
444 435 @@ -0,0 +1,1 @@
445 436 +changed
446 437
447 438 $ hg --config diff.git=yes export 1
448 439 # HG changeset patch
449 440 # User test
450 441 # Date 0 0
451 442 # Thu Jan 01 00:00:00 1970 +0000
452 443 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
453 444 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
454 445 renamed
455 446
456 447 diff --git a/another-dir/initial-file b/another-dir/renamed-file
457 448 rename from another-dir/initial-file
458 449 rename to another-dir/renamed-file
459 450
460 451 $ cd ..
@@ -1,154 +1,152 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 63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 64
67 65 log after edit
68 66 $ hg log --graph
69 67 @ changeset: 4:f518305ce889
70 68 | tag: tip
71 69 | user: test
72 70 | date: Thu Jan 01 00:00:00 1970 +0000
73 71 | summary: d
74 72 |
75 73 o changeset: 3:a4f7421b80f7
76 74 | user: test
77 75 | date: Thu Jan 01 00:00:00 1970 +0000
78 76 | summary: f
79 77 |
80 78 o changeset: 2:ee283cb5f2d5
81 79 | user: test
82 80 | date: Thu Jan 01 00:00:00 1970 +0000
83 81 | summary: e
84 82 |
85 83 o changeset: 1:d2ae7f538514
86 84 | user: test
87 85 | date: Thu Jan 01 00:00:00 1970 +0000
88 86 | summary: b
89 87 |
90 88 o changeset: 0:cb9a9f314b8b
91 89 user: test
92 90 date: Thu Jan 01 00:00:00 1970 +0000
93 91 summary: a
94 92
95 93
96 94 Check histedit_source
97 95
98 96 $ hg log --debug --rev f518305ce889
99 97 changeset: 4:f518305ce889c07cb5bd05522176d75590ef3324
100 98 tag: tip
101 99 phase: draft
102 100 parent: 3:a4f7421b80f79fcc59fff01bcbf4a53d127dd6d3
103 101 parent: -1:0000000000000000000000000000000000000000
104 102 manifest: 4:d3d4f51c157ff242c32ff745d4799aaa26ccda44
105 103 user: test
106 104 date: Thu Jan 01 00:00:00 1970 +0000
107 105 files+: d
108 106 extra: branch=default
109 107 extra: histedit_source=055a42cdd88768532f9cf79daa407fc8d138de9b
110 108 description:
111 109 d
112 110
113 111
114 112
115 113 manifest after edit
116 114 $ hg manifest
117 115 a
118 116 b
119 117 d
120 118 e
121 119 f
122 120
123 121 Drop the last changeset
124 122
125 123 $ hg histedit ee283cb5f2d5 --commands - 2>&1 << EOF | fixbundle
126 124 > pick ee283cb5f2d5 e
127 125 > pick a4f7421b80f7 f
128 126 > drop f518305ce889 d
129 127 > EOF
130 128 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
131 129 $ hg log --graph
132 130 @ changeset: 3:a4f7421b80f7
133 131 | tag: tip
134 132 | user: test
135 133 | date: Thu Jan 01 00:00:00 1970 +0000
136 134 | summary: f
137 135 |
138 136 o changeset: 2:ee283cb5f2d5
139 137 | user: test
140 138 | date: Thu Jan 01 00:00:00 1970 +0000
141 139 | summary: e
142 140 |
143 141 o changeset: 1:d2ae7f538514
144 142 | user: test
145 143 | date: Thu Jan 01 00:00:00 1970 +0000
146 144 | summary: b
147 145 |
148 146 o changeset: 0:cb9a9f314b8b
149 147 user: test
150 148 date: Thu Jan 01 00:00:00 1970 +0000
151 149 summary: a
152 150
153 151
154 152 $ cd ..
@@ -1,483 +1,482 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 144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 145
147 146 $ hg log --graph
148 147 @ changeset: 6:b5f70786f9b0
149 148 | tag: tip
150 149 | user: test
151 150 | date: Thu Jan 01 00:00:00 1970 +0000
152 151 | summary: f
153 152 |
154 153 o changeset: 5:a5e1ba2f7afb
155 154 | user: test
156 155 | date: Thu Jan 01 00:00:00 1970 +0000
157 156 | summary: foobaz
158 157 |
159 158 o changeset: 4:1a60820cd1f6
160 159 | user: test
161 160 | date: Thu Jan 01 00:00:00 1970 +0000
162 161 | summary: wat
163 162 |
164 163 o changeset: 3:055a42cdd887
165 164 | user: test
166 165 | date: Thu Jan 01 00:00:00 1970 +0000
167 166 | summary: d
168 167 |
169 168 o changeset: 2:177f92b77385
170 169 | user: test
171 170 | date: Thu Jan 01 00:00:00 1970 +0000
172 171 | summary: c
173 172 |
174 173 o changeset: 1:d2ae7f538514
175 174 | user: test
176 175 | date: Thu Jan 01 00:00:00 1970 +0000
177 176 | summary: b
178 177 |
179 178 o changeset: 0:cb9a9f314b8b
180 179 user: test
181 180 date: Thu Jan 01 00:00:00 1970 +0000
182 181 summary: a
183 182
184 183
185 184 $ hg cat e
186 185 a
187 186
188 187 Stripping necessary commits should not break --abort
189 188
190 189 $ hg histedit 1a60820cd1f6 --commands - 2>&1 << EOF| fixbundle
191 190 > edit 1a60820cd1f6 wat
192 191 > pick a5e1ba2f7afb foobaz
193 192 > pick b5f70786f9b0 g
194 193 > EOF
195 194 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
196 195 Make changes as needed, you may commit or record as needed now.
197 196 When you are finished, run hg histedit --continue to resume.
198 197
199 198 $ mv .hg/histedit-state .hg/histedit-state.bak
200 199 $ hg strip -q -r b5f70786f9b0
201 200 $ mv .hg/histedit-state.bak .hg/histedit-state
202 201 $ hg histedit --abort
203 202 adding changesets
204 203 adding manifests
205 204 adding file changes
206 205 added 1 changesets with 1 changes to 3 files
207 206 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 207 $ hg log -r .
209 208 changeset: 6:b5f70786f9b0
210 209 tag: tip
211 210 user: test
212 211 date: Thu Jan 01 00:00:00 1970 +0000
213 212 summary: f
214 213
215 214
216 215 check histedit_source
217 216
218 217 $ hg log --debug --rev 5
219 218 changeset: 5:a5e1ba2f7afb899ef1581cea528fd885d2fca70d
220 219 phase: draft
221 220 parent: 4:1a60820cd1f6004a362aa622ebc47d59bc48eb34
222 221 parent: -1:0000000000000000000000000000000000000000
223 222 manifest: 5:5ad3be8791f39117565557781f5464363b918a45
224 223 user: test
225 224 date: Thu Jan 01 00:00:00 1970 +0000
226 225 files: e
227 226 extra: branch=default
228 227 extra: histedit_source=e860deea161a2f77de56603b340ebbb4536308ae
229 228 description:
230 229 foobaz
231 230
232 231
233 232
234 233 $ hg histedit tip --commands - 2>&1 <<EOF| fixbundle
235 234 > edit b5f70786f9b0 f
236 235 > EOF
237 236 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
238 237 Make changes as needed, you may commit or record as needed now.
239 238 When you are finished, run hg histedit --continue to resume.
240 239 $ hg status
241 240 A f
242 241
243 242 $ hg summary
244 243 parent: 5:a5e1ba2f7afb
245 244 foobaz
246 245 branch: default
247 246 commit: 1 added (new branch head)
248 247 update: 1 new changesets (update)
249 248 phases: 7 draft
250 249 hist: 1 remaining (histedit --continue)
251 250
252 251 (test also that editor is invoked if histedit is continued for
253 252 "edit" action)
254 253
255 254 $ HGEDITOR='cat' hg histedit --continue
256 255 f
257 256
258 257
259 258 HG: Enter commit message. Lines beginning with 'HG:' are removed.
260 259 HG: Leave message empty to abort commit.
261 260 HG: --
262 261 HG: user: test
263 262 HG: branch 'default'
264 263 HG: added f
265 264 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 265 saved backup bundle to $TESTTMP/r/.hg/strip-backup/b5f70786f9b0-c28d9c86-backup.hg (glob)
267 266
268 267 $ hg status
269 268
270 269 log after edit
271 270 $ hg log --limit 1
272 271 changeset: 6:a107ee126658
273 272 tag: tip
274 273 user: test
275 274 date: Thu Jan 01 00:00:00 1970 +0000
276 275 summary: f
277 276
278 277
279 278 say we'll change the message, but don't.
280 279 $ cat > ../edit.sh <<EOF
281 280 > cat "\$1" | sed s/pick/mess/ > tmp
282 281 > mv tmp "\$1"
283 282 > EOF
284 283 $ HGEDITOR="sh ../edit.sh" hg histedit tip 2>&1 | fixbundle
285 284 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
286 285 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 286 $ hg status
288 287 $ hg log --limit 1
289 288 changeset: 6:1fd3b2fe7754
290 289 tag: tip
291 290 user: test
292 291 date: Thu Jan 01 00:00:00 1970 +0000
293 292 summary: f
294 293
295 294
296 295 modify the message
297 296
298 297 check saving last-message.txt, at first
299 298
300 299 $ cat > $TESTTMP/commitfailure.py <<EOF
301 300 > from mercurial import error
302 301 > def reposetup(ui, repo):
303 302 > class commitfailure(repo.__class__):
304 303 > def commit(self, *args, **kwargs):
305 304 > raise error.Abort('emulating unexpected abort')
306 305 > repo.__class__ = commitfailure
307 306 > EOF
308 307 $ cat >> .hg/hgrc <<EOF
309 308 > [extensions]
310 309 > # this failure occurs before editor invocation
311 310 > commitfailure = $TESTTMP/commitfailure.py
312 311 > EOF
313 312
314 313 $ cat > $TESTTMP/editor.sh <<EOF
315 314 > echo "==== before editing"
316 315 > cat \$1
317 316 > echo "===="
318 317 > echo "check saving last-message.txt" >> \$1
319 318 > EOF
320 319
321 320 (test that editor is not invoked before transaction starting)
322 321
323 322 $ rm -f .hg/last-message.txt
324 323 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF | fixbundle
325 324 > mess 1fd3b2fe7754 f
326 325 > EOF
327 326 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
328 327 abort: emulating unexpected abort
329 328 $ test -f .hg/last-message.txt
330 329 [1]
331 330
332 331 $ cat >> .hg/hgrc <<EOF
333 332 > [extensions]
334 333 > commitfailure = !
335 334 > EOF
336 335 $ hg histedit --abort -q
337 336
338 337 (test that editor is invoked and commit message is saved into
339 338 "last-message.txt")
340 339
341 340 $ cat >> .hg/hgrc <<EOF
342 341 > [hooks]
343 342 > # this failure occurs after editor invocation
344 343 > pretxncommit.unexpectedabort = false
345 344 > EOF
346 345
347 346 $ hg status --rev '1fd3b2fe7754^1' --rev 1fd3b2fe7754
348 347 A f
349 348
350 349 $ rm -f .hg/last-message.txt
351 350 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit tip --commands - 2>&1 << EOF
352 351 > mess 1fd3b2fe7754 f
353 352 > EOF
354 353 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
355 354 adding f
356 355 ==== before editing
357 356 f
358 357
359 358
360 359 HG: Enter commit message. Lines beginning with 'HG:' are removed.
361 360 HG: Leave message empty to abort commit.
362 361 HG: --
363 362 HG: user: test
364 363 HG: branch 'default'
365 364 HG: added f
366 365 ====
367 366 note: commit message saved in .hg/last-message.txt
368 367 transaction abort!
369 368 rollback completed
370 369 abort: pretxncommit.unexpectedabort hook exited with status 1
371 370 [255]
372 371 $ cat .hg/last-message.txt
373 372 f
374 373
375 374
376 375 check saving last-message.txt
377 376
378 377 (test also that editor is invoked if histedit is continued for "message"
379 378 action)
380 379
381 380 $ HGEDITOR=cat hg histedit --continue
382 381 f
383 382
384 383
385 384 HG: Enter commit message. Lines beginning with 'HG:' are removed.
386 385 HG: Leave message empty to abort commit.
387 386 HG: --
388 387 HG: user: test
389 388 HG: branch 'default'
390 389 HG: added f
391 390 note: commit message saved in .hg/last-message.txt
392 391 transaction abort!
393 392 rollback completed
394 393 abort: pretxncommit.unexpectedabort hook exited with status 1
395 394 [255]
396 395
397 396 $ cat >> .hg/hgrc <<EOF
398 397 > [hooks]
399 398 > pretxncommit.unexpectedabort =
400 399 > EOF
401 400 $ hg histedit --abort -q
402 401
403 402 then, check "modify the message" itself
404 403
405 404 $ hg histedit tip --commands - 2>&1 << EOF | fixbundle
406 405 > mess 1fd3b2fe7754 f
407 406 > EOF
408 407 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
409 408 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 409 $ hg status
411 410 $ hg log --limit 1
412 411 changeset: 6:62feedb1200e
413 412 tag: tip
414 413 user: test
415 414 date: Thu Jan 01 00:00:00 1970 +0000
416 415 summary: f
417 416
418 417
419 418 rollback should not work after a histedit
420 419 $ hg rollback
421 420 no rollback information available
422 421 [1]
423 422
424 423 $ cd ..
425 424 $ hg clone -qr0 r r0
426 425 $ cd r0
427 426 $ hg phase -fdr0
428 427 $ hg histedit --commands - 0 2>&1 << EOF
429 428 > edit cb9a9f314b8b a > $EDITED
430 429 > EOF
431 430 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
432 431 adding a
433 432 Make changes as needed, you may commit or record as needed now.
434 433 When you are finished, run hg histedit --continue to resume.
435 434 [1]
436 435 $ HGEDITOR=true hg histedit --continue
437 436 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 437 saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-backup.hg (glob)
439 438
440 439 $ hg log -G
441 440 @ changeset: 0:0efcea34f18a
442 441 tag: tip
443 442 user: test
444 443 date: Thu Jan 01 00:00:00 1970 +0000
445 444 summary: a
446 445
447 446 $ echo foo >> b
448 447 $ hg addr
449 448 adding b
450 449 $ hg ci -m 'add b'
451 450 $ echo foo >> a
452 451 $ hg ci -m 'extend a'
453 452 $ hg phase --public 1
454 453 Attempting to fold a change into a public change should not work:
455 454 $ cat > ../edit.sh <<EOF
456 455 > cat "\$1" | sed s/pick/fold/ > tmp
457 456 > mv tmp "\$1"
458 457 > EOF
459 458 $ HGEDITOR="sh ../edit.sh" hg histedit 2
460 459 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
461 460 reverting a
462 461 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
463 462 warning: histedit rules saved to: .hg/histedit-last-edit.txt
464 463 abort: cannot fold into public change 18aa70c8ad22
465 464 [255]
466 465 $ cat .hg/histedit-last-edit.txt
467 466 fold 0012be4a27ea 2 extend a
468 467
469 468 # Edit history between 0012be4a27ea and 0012be4a27ea
470 469 #
471 470 # Commits are listed from least to most recent
472 471 #
473 472 # Commands:
474 473 # p, fold = use commit
475 474 # e, edit = use commit, but stop for amending
476 475 # f, fold = use commit, but combine it with the one above
477 476 # r, roll = like fold, but discard this commit's description
478 477 # d, drop = remove commit from history
479 478 # m, mess = edit commit message without changing commit content
480 479 #
481 480 TODO: this abort shouldn't be required, but it is for now to leave the repo in
482 481 a clean state.
483 482 $ hg histedit --abort
@@ -1,345 +1,341 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 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 123 merging e
125 124 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
126 125 Fix up the change and run hg histedit --continue
127 126
128 127 just continue this time
129 128 $ hg revert -r 'p1()' e
130 129 $ hg resolve --mark e
131 130 (no more unresolved files)
132 131 $ hg histedit --continue 2>&1 | fixbundle
133 132 7b4e2f4b7bcd: empty changeset
134 133 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
135 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 134
137 135 log after edit
138 136 $ hg log --graph
139 137 @ changeset: 5:d9cf42e54966
140 138 | tag: tip
141 139 | user: test
142 140 | date: Thu Jan 01 00:00:00 1970 +0000
143 141 | summary: f
144 142 |
145 143 o changeset: 4:10486af2e984
146 144 | user: test
147 145 | date: Thu Jan 01 00:00:00 1970 +0000
148 146 | summary: d
149 147 |
150 148 o changeset: 3:65a9a84f33fd
151 149 | user: test
152 150 | date: Thu Jan 01 00:00:00 1970 +0000
153 151 | summary: c
154 152 |
155 153 o changeset: 2:da6535b52e45
156 154 | user: test
157 155 | date: Thu Jan 01 00:00:00 1970 +0000
158 156 | summary: b
159 157 |
160 158 o changeset: 1:c1f09da44841
161 159 | user: test
162 160 | date: Thu Jan 01 00:00:00 1970 +0000
163 161 | summary: a
164 162 |
165 163 o changeset: 0:1715188a53c7
166 164 user: test
167 165 date: Thu Jan 01 00:00:00 1970 +0000
168 166 summary: Initial commit
169 167
170 168
171 169 contents of e
172 170 $ hg cat e
173 171 I can haz no commute
174 172
175 173 manifest
176 174 $ hg manifest
177 175 a
178 176 b
179 177 c
180 178 d
181 179 e
182 180 f
183 181
184 182 $ cd ..
185 183
186 184 Repeat test using "roll", not "fold". "roll" folds in changes but drops message
187 185
188 186 $ initrepo r2
189 187 $ cd r2
190 188
191 189 Initial generation of the command files
192 190
193 191 $ EDITED="$TESTTMP/editedhistory.2"
194 192 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
195 193 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
196 194 $ hg log --template 'roll {node|short} {rev} {desc}\n' -r 7 >> $EDITED
197 195 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
198 196 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
199 197 $ cat $EDITED
200 198 pick 65a9a84f33fd 3 c
201 199 pick 00f1c5383965 4 d
202 200 roll 39522b764e3d 7 does not commute with e
203 201 pick 7b4e2f4b7bcd 5 e
204 202 pick 500cac37a696 6 f
205 203
206 204 log before edit
207 205 $ hg log --graph
208 206 @ changeset: 7:39522b764e3d
209 207 | tag: tip
210 208 | user: test
211 209 | date: Thu Jan 01 00:00:00 1970 +0000
212 210 | summary: does not commute with e
213 211 |
214 212 o changeset: 6:500cac37a696
215 213 | user: test
216 214 | date: Thu Jan 01 00:00:00 1970 +0000
217 215 | summary: f
218 216 |
219 217 o changeset: 5:7b4e2f4b7bcd
220 218 | user: test
221 219 | date: Thu Jan 01 00:00:00 1970 +0000
222 220 | summary: e
223 221 |
224 222 o changeset: 4:00f1c5383965
225 223 | user: test
226 224 | date: Thu Jan 01 00:00:00 1970 +0000
227 225 | summary: d
228 226 |
229 227 o changeset: 3:65a9a84f33fd
230 228 | user: test
231 229 | date: Thu Jan 01 00:00:00 1970 +0000
232 230 | summary: c
233 231 |
234 232 o changeset: 2:da6535b52e45
235 233 | user: test
236 234 | date: Thu Jan 01 00:00:00 1970 +0000
237 235 | summary: b
238 236 |
239 237 o changeset: 1:c1f09da44841
240 238 | user: test
241 239 | date: Thu Jan 01 00:00:00 1970 +0000
242 240 | summary: a
243 241 |
244 242 o changeset: 0:1715188a53c7
245 243 user: test
246 244 date: Thu Jan 01 00:00:00 1970 +0000
247 245 summary: Initial commit
248 246
249 247
250 248 edit the history
251 249 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
252 250 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 251 merging e
254 252 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
255 253 Fix up the change and run hg histedit --continue
256 254
257 255 fix up
258 256 $ echo 'I can haz no commute' > e
259 257 $ hg resolve --mark e
260 258 (no more unresolved files)
261 259 $ hg histedit --continue 2>&1 | fixbundle | grep -v '2 files removed'
262 260 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 261 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 262 merging e
266 263 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
267 264 Fix up the change and run hg histedit --continue
268 265
269 266 just continue this time
270 267 $ hg revert -r 'p1()' e
271 268 $ hg resolve --mark e
272 269 (no more unresolved files)
273 270 $ hg histedit --continue 2>&1 | fixbundle
274 271 7b4e2f4b7bcd: empty changeset
275 272 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
276 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
277 273
278 274 log after edit
279 275 $ hg log --graph
280 276 @ changeset: 5:e7c4f5d4eb75
281 277 | tag: tip
282 278 | user: test
283 279 | date: Thu Jan 01 00:00:00 1970 +0000
284 280 | summary: f
285 281 |
286 282 o changeset: 4:803d1bb561fc
287 283 | user: test
288 284 | date: Thu Jan 01 00:00:00 1970 +0000
289 285 | summary: d
290 286 |
291 287 o changeset: 3:65a9a84f33fd
292 288 | user: test
293 289 | date: Thu Jan 01 00:00:00 1970 +0000
294 290 | summary: c
295 291 |
296 292 o changeset: 2:da6535b52e45
297 293 | user: test
298 294 | date: Thu Jan 01 00:00:00 1970 +0000
299 295 | summary: b
300 296 |
301 297 o changeset: 1:c1f09da44841
302 298 | user: test
303 299 | date: Thu Jan 01 00:00:00 1970 +0000
304 300 | summary: a
305 301 |
306 302 o changeset: 0:1715188a53c7
307 303 user: test
308 304 date: Thu Jan 01 00:00:00 1970 +0000
309 305 summary: Initial commit
310 306
311 307
312 308 contents of e
313 309 $ hg cat e
314 310 I can haz no commute
315 311
316 312 manifest
317 313 $ hg manifest
318 314 a
319 315 b
320 316 c
321 317 d
322 318 e
323 319 f
324 320
325 321 description is taken from rollup target commit
326 322
327 323 $ hg log --debug --rev 4
328 324 changeset: 4:803d1bb561fceac3129ec778db9da249a3106fc3
329 325 phase: draft
330 326 parent: 3:65a9a84f33fdeb1ad5679b3941ec885d2b24027b
331 327 parent: -1:0000000000000000000000000000000000000000
332 328 manifest: 4:b068a323d969f22af1296ec6a5ea9384cef437ac
333 329 user: test
334 330 date: Thu Jan 01 00:00:00 1970 +0000
335 331 files: d e
336 332 extra: branch=default
337 333 extra: histedit_source=00f1c53839651fa5c76d423606811ea5455a79d0,39522b764e3d26103f08bd1fa2ccd3e3d7dbcf4e
338 334 description:
339 335 d
340 336
341 337
342 338
343 339 done with repo r2
344 340
345 341 $ cd ..
@@ -1,571 +1,563 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 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 58 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
61 59 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 60 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 61
65 62 log after edit
66 63 $ hg logt --graph
67 64 @ 4:9c277da72c9b d
68 65 |
69 66 o 3:6de59d13424a f
70 67 |
71 68 o 2:ee283cb5f2d5 e
72 69 |
73 70 o 1:d2ae7f538514 b
74 71 |
75 72 o 0:cb9a9f314b8b a
76 73
77 74
78 75 post-fold manifest
79 76 $ hg manifest
80 77 a
81 78 b
82 79 c
83 80 d
84 81 e
85 82 f
86 83
87 84
88 85 check histedit_source
89 86
90 87 $ hg log --debug --rev 3
91 88 changeset: 3:6de59d13424a8a13acd3e975514aed29dd0d9b2d
92 89 phase: draft
93 90 parent: 2:ee283cb5f2d5955443f23a27b697a04339e9a39a
94 91 parent: -1:0000000000000000000000000000000000000000
95 92 manifest: 3:81eede616954057198ead0b2c73b41d1f392829a
96 93 user: test
97 94 date: Thu Jan 01 00:00:00 1970 +0000
98 95 files+: c f
99 96 extra: branch=default
100 97 extra: histedit_source=a4f7421b80f79fcc59fff01bcbf4a53d127dd6d3,177f92b773850b59254aa5e923436f921b55483b
101 98 description:
102 99 f
103 100 ***
104 101 c
105 102
106 103
107 104
108 105 rollup will fold without preserving the folded commit's message
109 106
110 107 $ OLDHGEDITOR=$HGEDITOR
111 108 $ HGEDITOR=false
112 109 $ hg histedit d2ae7f538514 --commands - 2>&1 <<EOF | fixbundle
113 110 > pick d2ae7f538514 b
114 111 > roll ee283cb5f2d5 e
115 112 > pick 6de59d13424a f
116 113 > pick 9c277da72c9b d
117 114 > EOF
118 115 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
119 116 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
120 117 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 118 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 119
125 120 $ HGEDITOR=$OLDHGEDITOR
126 121
127 122 log after edit
128 123 $ hg logt --graph
129 124 @ 3:c4a9eb7989fc d
130 125 |
131 126 o 2:8e03a72b6f83 f
132 127 |
133 128 o 1:391ee782c689 b
134 129 |
135 130 o 0:cb9a9f314b8b a
136 131
137 132
138 133 description is taken from rollup target commit
139 134
140 135 $ hg log --debug --rev 1
141 136 changeset: 1:391ee782c68930be438ccf4c6a403daedbfbffa5
142 137 phase: draft
143 138 parent: 0:cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
144 139 parent: -1:0000000000000000000000000000000000000000
145 140 manifest: 1:b5e112a3a8354e269b1524729f0918662d847c38
146 141 user: test
147 142 date: Thu Jan 01 00:00:00 1970 +0000
148 143 files+: b e
149 144 extra: branch=default
150 145 extra: histedit_source=d2ae7f538514cd87c17547b0de4cea71fe1af9fb,ee283cb5f2d5955443f23a27b697a04339e9a39a
151 146 description:
152 147 b
153 148
154 149
155 150
156 151 check saving last-message.txt
157 152
158 153 $ cat > $TESTTMP/abortfolding.py <<EOF
159 154 > from mercurial import util
160 155 > def abortfolding(ui, repo, hooktype, **kwargs):
161 156 > ctx = repo[kwargs.get('node')]
162 157 > if set(ctx.files()) == set(['c', 'd', 'f']):
163 158 > return True # abort folding commit only
164 159 > ui.warn('allow non-folding commit\\n')
165 160 > EOF
166 161 $ cat > .hg/hgrc <<EOF
167 162 > [hooks]
168 163 > pretxncommit.abortfolding = python:$TESTTMP/abortfolding.py:abortfolding
169 164 > EOF
170 165
171 166 $ cat > $TESTTMP/editor.sh << EOF
172 167 > echo "==== before editing"
173 168 > cat \$1
174 169 > echo "===="
175 170 > echo "check saving last-message.txt" >> \$1
176 171 > EOF
177 172
178 173 $ rm -f .hg/last-message.txt
179 174 $ hg status --rev '8e03a72b6f83^1::c4a9eb7989fc'
180 175 A c
181 176 A d
182 177 A f
183 178 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 8e03a72b6f83 --commands - 2>&1 <<EOF
184 179 > pick 8e03a72b6f83 f
185 180 > fold c4a9eb7989fc d
186 181 > EOF
187 182 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
188 183 adding d
189 184 allow non-folding commit
190 185 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
191 186 ==== before editing
192 187 f
193 188 ***
194 189 c
195 190 ***
196 191 d
197 192
198 193
199 194
200 195 HG: Enter commit message. Lines beginning with 'HG:' are removed.
201 196 HG: Leave message empty to abort commit.
202 197 HG: --
203 198 HG: user: test
204 199 HG: branch 'default'
205 200 HG: added c
206 201 HG: added d
207 202 HG: added f
208 203 ====
209 204 transaction abort!
210 205 rollback completed
211 206 abort: pretxncommit.abortfolding hook failed
212 207 [255]
213 208
214 209 $ cat .hg/last-message.txt
215 210 f
216 211 ***
217 212 c
218 213 ***
219 214 d
220 215
221 216
222 217
223 218 check saving last-message.txt
224 219
225 220 $ cd ..
226 221 $ rm -r r
227 222
228 223 folding preserves initial author
229 224 --------------------------------
230 225
231 226 $ initrepo
232 227
233 228 $ hg ci --user "someone else" --amend --quiet
234 229
235 230 tip before edit
236 231 $ hg log --rev .
237 232 changeset: 5:a00ad806cb55
238 233 tag: tip
239 234 user: someone else
240 235 date: Thu Jan 01 00:00:00 1970 +0000
241 236 summary: f
242 237
243 238
244 239 $ hg histedit e860deea161a --commands - 2>&1 <<EOF | fixbundle
245 240 > pick e860deea161a e
246 241 > fold a00ad806cb55 f
247 242 > EOF
248 243 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
249 244 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
250 245 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 246 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 247
253 248 tip after edit
254 249 $ hg log --rev .
255 250 changeset: 4:698d4e8040a1
256 251 tag: tip
257 252 user: test
258 253 date: Thu Jan 01 00:00:00 1970 +0000
259 254 summary: e
260 255
261 256
262 257 $ cd ..
263 258 $ rm -r r
264 259
265 260 folding and creating no new change doesn't break:
266 261 -------------------------------------------------
267 262
268 263 folded content is dropped during a merge. The folded commit should properly disappear.
269 264
270 265 $ mkdir fold-to-empty-test
271 266 $ cd fold-to-empty-test
272 267 $ hg init
273 268 $ printf "1\n2\n3\n" > file
274 269 $ hg add file
275 270 $ hg commit -m '1+2+3'
276 271 $ echo 4 >> file
277 272 $ hg commit -m '+4'
278 273 $ echo 5 >> file
279 274 $ hg commit -m '+5'
280 275 $ echo 6 >> file
281 276 $ hg commit -m '+6'
282 277 $ hg logt --graph
283 278 @ 3:251d831eeec5 +6
284 279 |
285 280 o 2:888f9082bf99 +5
286 281 |
287 282 o 1:617f94f13c0f +4
288 283 |
289 284 o 0:0189ba417d34 1+2+3
290 285
291 286
292 287 $ hg histedit 1 --commands - << EOF
293 288 > pick 617f94f13c0f 1 +4
294 289 > drop 888f9082bf99 2 +5
295 290 > fold 251d831eeec5 3 +6
296 291 > EOF
297 292 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 293 merging file
299 294 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
300 295 Fix up the change and run hg histedit --continue
301 296 [1]
302 297 There were conflicts, we keep P1 content. This
303 298 should effectively drop the changes from +6.
304 299 $ hg status
305 300 M file
306 301 ? file.orig
307 302 $ hg resolve -l
308 303 U file
309 304 $ hg revert -r 'p1()' file
310 305 $ hg resolve --mark file
311 306 (no more unresolved files)
312 307 $ hg histedit --continue
313 308 251d831eeec5: empty changeset
314 309 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 310 saved backup bundle to $TESTTMP/*-backup.hg (glob)
316 311 $ hg logt --graph
317 312 @ 1:617f94f13c0f +4
318 313 |
319 314 o 0:0189ba417d34 1+2+3
320 315
321 316
322 317 $ cd ..
323 318
324 319
325 320 Test fold through dropped
326 321 -------------------------
327 322
328 323
329 324 Test corner case where folded revision is separated from its parent by a
330 325 dropped revision.
331 326
332 327
333 328 $ hg init fold-with-dropped
334 329 $ cd fold-with-dropped
335 330 $ printf "1\n2\n3\n" > file
336 331 $ hg commit -Am '1+2+3'
337 332 adding file
338 333 $ echo 4 >> file
339 334 $ hg commit -m '+4'
340 335 $ echo 5 >> file
341 336 $ hg commit -m '+5'
342 337 $ echo 6 >> file
343 338 $ hg commit -m '+6'
344 339 $ hg logt -G
345 340 @ 3:251d831eeec5 +6
346 341 |
347 342 o 2:888f9082bf99 +5
348 343 |
349 344 o 1:617f94f13c0f +4
350 345 |
351 346 o 0:0189ba417d34 1+2+3
352 347
353 348 $ hg histedit 1 --commands - << EOF
354 349 > pick 617f94f13c0f 1 +4
355 350 > drop 888f9082bf99 2 +5
356 351 > fold 251d831eeec5 3 +6
357 352 > EOF
358 353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 354 merging file
360 355 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
361 356 Fix up the change and run hg histedit --continue
362 357 [1]
363 358 $ cat > file << EOF
364 359 > 1
365 360 > 2
366 361 > 3
367 362 > 4
368 363 > 5
369 364 > EOF
370 365 $ hg resolve --mark file
371 366 (no more unresolved files)
372 367 $ hg commit -m '+5.2'
373 368 created new head
374 369 $ echo 6 >> file
375 370 $ HGEDITOR=cat hg histedit --continue
376 371 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 372 +4
378 373 ***
379 374 +5.2
380 375 ***
381 376 +6
382 377
383 378
384 379
385 380 HG: Enter commit message. Lines beginning with 'HG:' are removed.
386 381 HG: Leave message empty to abort commit.
387 382 HG: --
388 383 HG: user: test
389 384 HG: branch 'default'
390 385 HG: changed file
391 386 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 387 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 388 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/55c8d8dc79ce-4066cd98-backup.hg (glob)
394 389 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/617f94f13c0f-a35700fc-backup.hg (glob)
395 390 $ hg logt -G
396 391 @ 1:10c647b2cdd5 +4
397 392 |
398 393 o 0:0189ba417d34 1+2+3
399 394
400 395 $ hg export tip
401 396 # HG changeset patch
402 397 # User test
403 398 # Date 0 0
404 399 # Thu Jan 01 00:00:00 1970 +0000
405 400 # Node ID 10c647b2cdd54db0603ecb99b2ff5ce66d5a5323
406 401 # Parent 0189ba417d34df9dda55f88b637dcae9917b5964
407 402 +4
408 403 ***
409 404 +5.2
410 405 ***
411 406 +6
412 407
413 408 diff -r 0189ba417d34 -r 10c647b2cdd5 file
414 409 --- a/file Thu Jan 01 00:00:00 1970 +0000
415 410 +++ b/file Thu Jan 01 00:00:00 1970 +0000
416 411 @@ -1,3 +1,6 @@
417 412 1
418 413 2
419 414 3
420 415 +4
421 416 +5
422 417 +6
423 418 $ cd ..
424 419
425 420
426 421 Folding with initial rename (issue3729)
427 422 ---------------------------------------
428 423
429 424 $ hg init fold-rename
430 425 $ cd fold-rename
431 426 $ echo a > a.txt
432 427 $ hg add a.txt
433 428 $ hg commit -m a
434 429 $ hg rename a.txt b.txt
435 430 $ hg commit -m rename
436 431 $ echo b >> b.txt
437 432 $ hg commit -m b
438 433
439 434 $ hg logt --follow b.txt
440 435 2:e0371e0426bc b
441 436 1:1c4f440a8085 rename
442 437 0:6c795aa153cb a
443 438
444 439 $ hg histedit 1c4f440a8085 --commands - 2>&1 << EOF | fixbundle
445 440 > pick 1c4f440a8085 rename
446 441 > fold e0371e0426bc b
447 442 > EOF
448 443 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
449 444 reverting b.txt
450 445 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
451 446 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
452 447 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 448
454 449 $ hg logt --follow b.txt
455 450 1:cf858d235c76 rename
456 451 0:6c795aa153cb a
457 452
458 453 $ cd ..
459 454
460 455 Folding with swapping
461 456 ---------------------
462 457
463 458 This is an excuse to test hook with histedit temporary commit (issue4422)
464 459
465 460
466 461 $ hg init issue4422
467 462 $ cd issue4422
468 463 $ echo a > a.txt
469 464 $ hg add a.txt
470 465 $ hg commit -m a
471 466 $ echo b > b.txt
472 467 $ hg add b.txt
473 468 $ hg commit -m b
474 469 $ echo c > c.txt
475 470 $ hg add c.txt
476 471 $ hg commit -m c
477 472
478 473 $ hg logt
479 474 2:a1a953ffb4b0 c
480 475 1:199b6bb90248 b
481 476 0:6c795aa153cb a
482 477
483 478 Setup the proper environment variable symbol for the platform, to be subbed
484 479 into the hook command.
485 480 #if windows
486 481 $ NODE="%HG_NODE%"
487 482 #else
488 483 $ NODE="\$HG_NODE"
489 484 #endif
490 485 $ hg histedit 6c795aa153cb --config hooks.commit="echo commit $NODE" --commands - 2>&1 << EOF | fixbundle
491 486 > pick 199b6bb90248 b
492 487 > fold a1a953ffb4b0 c
493 488 > pick 6c795aa153cb a
494 489 > EOF
495 490 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
496 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
497 491 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
498 492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 493 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
500 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
501 494 commit 9599899f62c05f4377548c32bf1c9f1a39634b0c
502 495
503 496 $ hg logt
504 497 1:9599899f62c0 a
505 498 0:79b99e9c8e49 b
506 499
507 500 $ echo "foo" > amended.txt
508 501 $ hg add amended.txt
509 502 $ hg ci -q --config extensions.largefiles= --amend -I amended.txt
510 503
511 504 Test that folding multiple changes in a row doesn't show multiple
512 505 editors.
513 506
514 507 $ echo foo >> foo
515 508 $ hg add foo
516 509 $ hg ci -m foo1
517 510 $ echo foo >> foo
518 511 $ hg ci -m foo2
519 512 $ echo foo >> foo
520 513 $ hg ci -m foo3
521 514 $ hg logt
522 515 4:21679ff7675c foo3
523 516 3:b7389cc4d66e foo2
524 517 2:0e01aeef5fa8 foo1
525 518 1:578c7455730c a
526 519 0:79b99e9c8e49 b
527 520 $ cat > "$TESTTMP/editor.sh" <<EOF
528 521 > echo ran editor >> "$TESTTMP/editorlog.txt"
529 522 > cat \$1 >> "$TESTTMP/editorlog.txt"
530 523 > echo END >> "$TESTTMP/editorlog.txt"
531 524 > echo merged foos > \$1
532 525 > EOF
533 526 $ HGEDITOR="sh \"$TESTTMP/editor.sh\"" hg histedit 1 --commands - 2>&1 <<EOF | fixbundle
534 527 > pick 578c7455730c 1 a
535 528 > pick 0e01aeef5fa8 2 foo1
536 529 > fold b7389cc4d66e 3 foo2
537 530 > fold 21679ff7675c 4 foo3
538 531 > EOF
539 532 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 533 reverting foo
541 534 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
542 535 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
543 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 536 merging foo
545 537 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
546 538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
547 539 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
548 540 $ hg logt
549 541 2:e8bedbda72c1 merged foos
550 542 1:578c7455730c a
551 543 0:79b99e9c8e49 b
552 544 Editor should have run only once
553 545 $ cat $TESTTMP/editorlog.txt
554 546 ran editor
555 547 foo1
556 548 ***
557 549 foo2
558 550 ***
559 551 foo3
560 552
561 553
562 554
563 555 HG: Enter commit message. Lines beginning with 'HG:' are removed.
564 556 HG: Leave message empty to abort commit.
565 557 HG: --
566 558 HG: user: test
567 559 HG: branch 'default'
568 560 HG: added foo
569 561 END
570 562
571 563 $ cd ..
@@ -1,222 +1,221 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 98 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 99
101 100
102 101 check state of working copy
103 102 $ hg id
104 103 794fe033d0a0 tip
105 104
106 105 $ graphlog "log after history editing"
107 106 % log after history editing
108 107 @ 5 794fe033d0a030f8df77c5de945fca35c9181c30 "f"
109 108 |
110 109 o 4 04d2fab980779f332dec458cc944f28de8b43435 "e"
111 110 |
112 111 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
113 112 |
114 113 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
115 114 |
116 115 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
117 116 |
118 117 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
119 118
120 119
121 120 $ cd ..
122 121
123 122 $ initrepo r2 "test editing with no change, then abort"
124 123 % test editing with no change, then abort
125 124 -----------------------------------------
126 125 $ cd r2
127 126 $ graphlog "log before editing"
128 127 % log before editing
129 128 @ 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
130 129 |
131 130 o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
132 131 |
133 132 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
134 133 |
135 134 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
136 135 |
137 136 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
138 137 |
139 138 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
140 139
141 140 $ startediting 1,2 3 "(not changing anything)" # edit the 1st two of 3 changesets
142 141 % start editing the history (not changing anything)
143 142 | edit 055a42cdd887 3 d
144 143 | edit e860deea161a 4 e
145 144 | pick 652413bf663e 5 f
146 145 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
147 146 Make changes as needed, you may commit or record as needed now.
148 147 When you are finished, run hg histedit --continue to resume.
149 148 $ continueediting true "(leaving commit message unaltered)"
150 149 % finalize changeset editing (leaving commit message unaltered)
151 150 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
152 151 Make changes as needed, you may commit or record as needed now.
153 152 When you are finished, run hg histedit --continue to resume.
154 153 $ graphlog "log after first edit"
155 154 % log after first edit
156 155 @ 6 e5ae3ca2f1ffdbd89ec41ebc273a231f7c3022f2 "d"
157 156 |
158 157 | o 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
159 158 | |
160 159 | o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
161 160 | |
162 161 | o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
163 162 |/
164 163 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
165 164 |
166 165 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
167 166 |
168 167 o 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
169 168
170 169
171 170 abort editing session, after first forcibly updating away
172 171 $ hg up 0
173 172 abort: histedit in progress
174 173 (use 'hg histedit --continue' or 'hg histedit --abort')
175 174 [255]
176 175 $ mv .hg/histedit-state .hg/histedit-state-ignore
177 176 $ hg up 0
178 177 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
179 178 $ mv .hg/histedit-state-ignore .hg/histedit-state
180 179 $ hg sum
181 180 parent: 0:cb9a9f314b8b
182 181 a
183 182 branch: default
184 183 commit: 1 added, 1 unknown (new branch head)
185 184 update: 6 new changesets (update)
186 185 phases: 7 draft
187 186 hist: 2 remaining (histedit --continue)
188 187
189 188 $ hg histedit --abort 2>&1 | fixbundle
190 189
191 190 modified files should survive the abort when we've moved away already
192 191 $ hg st
193 192 A e
194 193 ? edit.sh
195 194
196 195 $ graphlog "log after abort"
197 196 % log after abort
198 197 o 5 652413bf663ef2a641cab26574e46d5f5a64a55a "f"
199 198 |
200 199 o 4 e860deea161a2f77de56603b340ebbb4536308ae "e"
201 200 |
202 201 o 3 055a42cdd88768532f9cf79daa407fc8d138de9b "d"
203 202 |
204 203 o 2 177f92b773850b59254aa5e923436f921b55483b "c"
205 204 |
206 205 o 1 d2ae7f538514cd87c17547b0de4cea71fe1af9fb "b"
207 206 |
208 207 @ 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b "a"
209 208
210 209 aborting and not changing files can skip mentioning updating (no) files
211 210 $ hg up
212 211 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 212 $ hg commit --close-branch -m 'closebranch'
214 213 $ startediting 1 1 "(not changing anything)" # edit the 3rd of 3 changesets
215 214 % start editing the history (not changing anything)
216 215 | edit 292aec348d9e 6 closebranch
217 216 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
218 217 Make changes as needed, you may commit or record as needed now.
219 218 When you are finished, run hg histedit --continue to resume.
220 219 $ hg histedit --abort
221 220
222 221 $ cd ..
@@ -1,158 +1,157 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 > echo a >> e
18 18 > hg ci -m 'does not commute with e'
19 19 > cd ..
20 20 > }
21 21
22 22 $ initrepo
23 23 $ cd r
24 24
25 25 log before edit
26 26 $ hg log --graph
27 27 @ changeset: 6:bfa474341cc9
28 28 | tag: tip
29 29 | user: test
30 30 | date: Thu Jan 01 00:00:00 1970 +0000
31 31 | summary: does not commute with e
32 32 |
33 33 o changeset: 5:652413bf663e
34 34 | user: test
35 35 | date: Thu Jan 01 00:00:00 1970 +0000
36 36 | summary: f
37 37 |
38 38 o changeset: 4:e860deea161a
39 39 | user: test
40 40 | date: Thu Jan 01 00:00:00 1970 +0000
41 41 | summary: e
42 42 |
43 43 o changeset: 3:055a42cdd887
44 44 | user: test
45 45 | date: Thu Jan 01 00:00:00 1970 +0000
46 46 | summary: d
47 47 |
48 48 o changeset: 2:177f92b77385
49 49 | user: test
50 50 | date: Thu Jan 01 00:00:00 1970 +0000
51 51 | summary: c
52 52 |
53 53 o changeset: 1:d2ae7f538514
54 54 | user: test
55 55 | date: Thu Jan 01 00:00:00 1970 +0000
56 56 | summary: b
57 57 |
58 58 o changeset: 0:cb9a9f314b8b
59 59 user: test
60 60 date: Thu Jan 01 00:00:00 1970 +0000
61 61 summary: a
62 62
63 63
64 64 edit the history
65 65 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
66 66 > pick 177f92b77385 c
67 67 > pick 055a42cdd887 d
68 68 > pick bfa474341cc9 does not commute with e
69 69 > pick e860deea161a e
70 70 > pick 652413bf663e f
71 71 > EOF
72 72 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
73 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 73 merging e
75 74 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
76 75 Fix up the change and run hg histedit --continue
77 76
78 77 insert unsupported advisory merge record
79 78 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -x
80 79 $ hg debugmergestate
81 80 * version 2 records
82 81 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
83 82 other: e860deea161a2f77de56603b340ebbb4536308ae
84 83 unrecognized entry: x advisory record
85 84 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
86 85 local path: e (flags "")
87 86 ancestor path: e (node null)
88 87 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
89 88 $ hg resolve -l
90 89 U e
91 90
92 91 insert unsupported mandatory merge record
93 92 $ hg --config extensions.fakemergerecord=$TESTDIR/fakemergerecord.py fakemergerecord -X
94 93 $ hg debugmergestate
95 94 * version 2 records
96 95 local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
97 96 other: e860deea161a2f77de56603b340ebbb4536308ae
98 97 file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
99 98 local path: e (flags "")
100 99 ancestor path: e (node null)
101 100 other path: e (node 6b67ccefd5ce6de77e7ead4f5292843a0255329f)
102 101 unrecognized entry: X mandatory record
103 102 $ hg resolve -l
104 103 abort: unsupported merge state records: X
105 104 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
106 105 [255]
107 106 $ hg resolve -ma
108 107 abort: unsupported merge state records: X
109 108 (see https://mercurial-scm.org/wiki/MergeStateRecords for more information)
110 109 [255]
111 110
112 111 abort the edit (should clear out merge state)
113 112 $ hg histedit --abort 2>&1 | fixbundle
114 113 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 114 $ hg debugmergestate
116 115 no merge state found
117 116
118 117 log after abort
119 118 $ hg resolve -l
120 119 $ hg log --graph
121 120 @ changeset: 6:bfa474341cc9
122 121 | tag: tip
123 122 | user: test
124 123 | date: Thu Jan 01 00:00:00 1970 +0000
125 124 | summary: does not commute with e
126 125 |
127 126 o changeset: 5:652413bf663e
128 127 | user: test
129 128 | date: Thu Jan 01 00:00:00 1970 +0000
130 129 | summary: f
131 130 |
132 131 o changeset: 4:e860deea161a
133 132 | user: test
134 133 | date: Thu Jan 01 00:00:00 1970 +0000
135 134 | summary: e
136 135 |
137 136 o changeset: 3:055a42cdd887
138 137 | user: test
139 138 | date: Thu Jan 01 00:00:00 1970 +0000
140 139 | summary: d
141 140 |
142 141 o changeset: 2:177f92b77385
143 142 | user: test
144 143 | date: Thu Jan 01 00:00:00 1970 +0000
145 144 | summary: c
146 145 |
147 146 o changeset: 1:d2ae7f538514
148 147 | user: test
149 148 | date: Thu Jan 01 00:00:00 1970 +0000
150 149 | summary: b
151 150 |
152 151 o changeset: 0:cb9a9f314b8b
153 152 user: test
154 153 date: Thu Jan 01 00:00:00 1970 +0000
155 154 summary: a
156 155
157 156
158 157 $ cd ..
@@ -1,295 +1,291 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 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
158 157 merging e
159 158 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
160 159 Fix up the change and run hg histedit --continue
161 160
162 161 This failure is caused by 7b4e2f4b7bcd "e" not rebasing the non commutative
163 162 former children.
164 163
165 164 just continue this time
166 165 $ hg revert -r 'p1()' e
167 166 $ hg resolve --mark e
168 167 (no more unresolved files)
169 168 $ hg histedit --continue 2>&1 | fixbundle
170 169 7b4e2f4b7bcd: empty changeset
171 170 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
173 171
174 172 log after edit
175 173 $ hg log --graph
176 174 @ changeset: 6:7efe1373e4bc
177 175 | tag: tip
178 176 | user: test
179 177 | date: Thu Jan 01 00:00:00 1970 +0000
180 178 | summary: f
181 179 |
182 180 o changeset: 5:e334d87a1e55
183 181 | user: test
184 182 | date: Thu Jan 01 00:00:00 1970 +0000
185 183 | summary: does not commute with e
186 184 |
187 185 o changeset: 4:00f1c5383965
188 186 | user: test
189 187 | date: Thu Jan 01 00:00:00 1970 +0000
190 188 | summary: d
191 189 |
192 190 o changeset: 3:65a9a84f33fd
193 191 | user: test
194 192 | date: Thu Jan 01 00:00:00 1970 +0000
195 193 | summary: c
196 194 |
197 195 o changeset: 2:da6535b52e45
198 196 | user: test
199 197 | date: Thu Jan 01 00:00:00 1970 +0000
200 198 | summary: b
201 199 |
202 200 o changeset: 1:c1f09da44841
203 201 | user: test
204 202 | date: Thu Jan 01 00:00:00 1970 +0000
205 203 | summary: a
206 204 |
207 205 o changeset: 0:1715188a53c7
208 206 user: test
209 207 date: Thu Jan 01 00:00:00 1970 +0000
210 208 summary: Initial commit
211 209
212 210
213 211 start over
214 212
215 213 $ cd ..
216 214
217 215 $ initrepo r2
218 216 $ cd r2
219 217 $ rm $EDITED
220 218 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED
221 219 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED
222 220 $ hg log --template 'mess {node|short} {rev} {desc}\n' -r 7 >> $EDITED
223 221 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED
224 222 $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED
225 223 $ cat $EDITED
226 224 pick 65a9a84f33fd 3 c
227 225 pick 00f1c5383965 4 d
228 226 mess 39522b764e3d 7 does not commute with e
229 227 pick 7b4e2f4b7bcd 5 e
230 228 pick 500cac37a696 6 f
231 229
232 230 edit the history, this time with a fold action
233 231 $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle
234 232 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 233 merging e
236 234 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
237 235 Fix up the change and run hg histedit --continue
238 236
239 237 $ echo 'I can haz no commute' > e
240 238 $ hg resolve --mark e
241 239 (no more unresolved files)
242 240 $ hg histedit --continue 2>&1 | fixbundle
243 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 241 merging e
245 242 warning: conflicts while merging e! (edit, then use 'hg resolve --mark')
246 243 Fix up the change and run hg histedit --continue
247 244 second edit also fails, but just continue
248 245 $ hg revert -r 'p1()' e
249 246 $ hg resolve --mark e
250 247 (no more unresolved files)
251 248 $ hg histedit --continue 2>&1 | fixbundle
252 249 7b4e2f4b7bcd: empty changeset
253 250 0 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 251
256 252 post message fix
257 253 $ hg log --graph
258 254 @ changeset: 6:7efe1373e4bc
259 255 | tag: tip
260 256 | user: test
261 257 | date: Thu Jan 01 00:00:00 1970 +0000
262 258 | summary: f
263 259 |
264 260 o changeset: 5:e334d87a1e55
265 261 | user: test
266 262 | date: Thu Jan 01 00:00:00 1970 +0000
267 263 | summary: does not commute with e
268 264 |
269 265 o changeset: 4:00f1c5383965
270 266 | user: test
271 267 | date: Thu Jan 01 00:00:00 1970 +0000
272 268 | summary: d
273 269 |
274 270 o changeset: 3:65a9a84f33fd
275 271 | user: test
276 272 | date: Thu Jan 01 00:00:00 1970 +0000
277 273 | summary: c
278 274 |
279 275 o changeset: 2:da6535b52e45
280 276 | user: test
281 277 | date: Thu Jan 01 00:00:00 1970 +0000
282 278 | summary: b
283 279 |
284 280 o changeset: 1:c1f09da44841
285 281 | user: test
286 282 | date: Thu Jan 01 00:00:00 1970 +0000
287 283 | summary: a
288 284 |
289 285 o changeset: 0:1715188a53c7
290 286 user: test
291 287 date: Thu Jan 01 00:00:00 1970 +0000
292 288 summary: Initial commit
293 289
294 290
295 291 $ cd ..
@@ -1,471 +1,451 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 59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 60 $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
61 61 > pick 177f92b77385 2 c
62 62 > drop d2ae7f538514 1 b
63 63 > pick 055a42cdd887 3 d
64 64 > fold e860deea161a 4 e
65 65 > pick 652413bf663e 5 f
66 66 > EOF
67 67 [1]
68 68 $ hg log --graph --hidden
69 69 @ 10:cacdfd884a93 f
70 70 |
71 71 o 9:59d9f330561f d
72 72 |
73 73 | x 8:b558abc46d09 fold-temp-revision e860deea161a
74 74 | |
75 75 | x 7:96e494a2d553 d
76 76 |/
77 77 o 6:b346ab9a313d c
78 78 |
79 79 | x 5:652413bf663e f
80 80 | |
81 81 | x 4:e860deea161a e
82 82 | |
83 83 | x 3:055a42cdd887 d
84 84 | |
85 85 | x 2:177f92b77385 c
86 86 | |
87 87 | x 1:d2ae7f538514 b
88 88 |/
89 89 o 0:cb9a9f314b8b a
90 90
91 91 $ hg debugobsolete
92 92 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (*) {'user': 'test'} (glob)
93 93 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (*) {'user': 'test'} (glob)
94 94 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
95 95 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
96 96 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
97 97 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
98 98 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
99 99
100 100
101 101 Ensure hidden revision does not prevent histedit
102 102 -------------------------------------------------
103 103
104 104 create an hidden revision
105 105
106 106 $ hg histedit 6 --commands - << EOF
107 107 > pick b346ab9a313d 6 c
108 108 > drop 59d9f330561f 7 d
109 109 > pick cacdfd884a93 8 f
110 110 > EOF
111 111 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
112 112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 113 $ hg log --graph
114 114 @ 11:c13eb81022ca f
115 115 |
116 116 o 6:b346ab9a313d c
117 117 |
118 118 o 0:cb9a9f314b8b a
119 119
120 120 check hidden revision are ignored (6 have hidden children 7 and 8)
121 121
122 122 $ hg histedit 6 --commands - << EOF
123 123 > pick b346ab9a313d 6 c
124 124 > pick c13eb81022ca 8 f
125 125 > EOF
126 126 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
127 127
128 128
129 129
130 130 Test that rewriting leaving instability behind is allowed
131 131 ---------------------------------------------------------------------
132 132
133 133 $ hg up '.^'
134 134 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
135 135 $ hg log -r 'children(.)'
136 136 11:c13eb81022ca f (no-eol)
137 137 $ hg histedit -r '.' --commands - <<EOF
138 138 > edit b346ab9a313d 6 c
139 139 > EOF
140 140 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
141 141 adding c
142 142 Make changes as needed, you may commit or record as needed now.
143 143 When you are finished, run hg histedit --continue to resume.
144 144 [1]
145 145 $ echo c >> c
146 146 $ hg histedit --continue
147 147 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 148
149 149 $ hg log -r 'unstable()'
150 150 11:c13eb81022ca f (no-eol)
151 151
152 152 stabilise
153 153
154 154 $ hg rebase -r 'unstable()' -d .
155 155 rebasing 11:c13eb81022ca "f"
156 156 $ hg up tip -q
157 157
158 158 check that extra has accumulated from histedit and rebase
159 159
160 160 $ hg log -T '{extras % "{key}={value}\n"}\n' -r tip
161 161 branch=default
162 162 histedit_source=cacdfd884a9321ec4e1de275ef3949fa953a1f83
163 163 rebase_source=c13eb81022caa686a369223fe7f926bc4f7db576
164 164
165 165
166 166 Test dropping of changeset on the top of the stack
167 167 -------------------------------------------------------
168 168
169 169 Nothing is rewritten below, the working directory parent must be change for the
170 170 dropped changeset to be hidden.
171 171
172 172 $ cd ..
173 173 $ hg clone base droplast
174 174 updating to branch default
175 175 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 176 $ cd droplast
177 177 $ hg histedit -r '40db8afa467b' --commands - << EOF
178 178 > pick 40db8afa467b 10 c
179 179 > drop 947ece25170f 11 f
180 180 > EOF
181 181 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
182 182 $ hg log -G
183 183 @ 12:40db8afa467b c
184 184 |
185 185 o 0:cb9a9f314b8b a
186 186
187 187
188 188 With rewritten ancestors
189 189
190 190 $ echo e > e
191 191 $ hg add e
192 192 $ hg commit -m g
193 193 $ echo f > f
194 194 $ hg add f
195 195 $ hg commit -m h
196 196 $ hg histedit -r '40db8afa467b' --commands - << EOF
197 197 > pick 47a8561c0449 12 g
198 198 > pick 40db8afa467b 10 c
199 199 > drop 1b3b05f35ff0 13 h
200 200 > EOF
201 201 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
202 202 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
204 203 $ hg log -G
205 204 @ 17:ee6544123ab8 c
206 205 |
207 206 o 16:269e713e9eae g
208 207 |
209 208 o 0:cb9a9f314b8b a
210 209
211 210 $ cd ../base
212 211
213 212
214 213
215 214 Test phases support
216 215 ===========================================
217 216
218 217 Check that histedit respect immutability
219 218 -------------------------------------------
220 219
221 220 $ cat >> $HGRCPATH << EOF
222 221 > [ui]
223 222 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
224 223 > EOF
225 224
226 225 $ hg ph -pv '.^'
227 226 phase changed for 2 changesets
228 227 $ hg log -G
229 228 @ 13:947ece25170f (draft) f
230 229 |
231 230 o 12:40db8afa467b (public) c
232 231 |
233 232 o 0:cb9a9f314b8b (public) a
234 233
235 234 $ hg histedit -r '.~2'
236 235 abort: cannot edit public changeset: cb9a9f314b8b
237 236 (see "hg help phases" for details)
238 237 [255]
239 238
240 239
241 240 Prepare further testing
242 241 -------------------------------------------
243 242
244 243 $ for x in g h i j k ; do
245 244 > echo $x > $x
246 245 > hg add $x
247 246 > hg ci -m $x
248 247 > done
249 248 $ hg phase --force --secret .~2
250 249 $ hg log -G
251 250 @ 18:14bda137d5b3 (secret) k
252 251 |
253 252 o 17:c62e7241a4f2 (secret) j
254 253 |
255 254 o 16:9cd3934e05af (secret) i
256 255 |
257 256 o 15:ee4a24fc4dfa (draft) h
258 257 |
259 258 o 14:d22905de3528 (draft) g
260 259 |
261 260 o 13:947ece25170f (draft) f
262 261 |
263 262 o 12:40db8afa467b (public) c
264 263 |
265 264 o 0:cb9a9f314b8b (public) a
266 265
267 266 $ cd ..
268 267
269 268 simple phase conservation
270 269 -------------------------------------------
271 270
272 271 Resulting changeset should conserve the phase of the original one whatever the
273 272 phases.new-commit option is.
274 273
275 274 New-commit as draft (default)
276 275
277 276 $ cp -r base simple-draft
278 277 $ cd simple-draft
279 278 $ hg histedit -r '947ece25170f' --commands - << EOF
280 279 > edit 947ece25170f 11 f
281 280 > pick d22905de3528 12 g
282 281 > pick ee4a24fc4dfa 13 h
283 282 > pick 9cd3934e05af 14 i
284 283 > pick c62e7241a4f2 15 j
285 284 > pick 14bda137d5b3 16 k
286 285 > EOF
287 286 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
288 287 adding f
289 288 Make changes as needed, you may commit or record as needed now.
290 289 When you are finished, run hg histedit --continue to resume.
291 290 [1]
292 291 $ echo f >> f
293 292 $ hg histedit --continue
294 293 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
299 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
300 294 $ hg log -G
301 295 @ 24:12925f763c90 (secret) k
302 296 |
303 297 o 23:4545a6e77442 (secret) j
304 298 |
305 299 o 22:d947a0798e76 (secret) i
306 300 |
307 301 o 21:28fb35ae4ebb (draft) h
308 302 |
309 303 o 20:10b22a5a9645 (draft) g
310 304 |
311 305 o 19:c5a1db4a69f5 (draft) f
312 306 |
313 307 o 12:40db8afa467b (public) c
314 308 |
315 309 o 0:cb9a9f314b8b (public) a
316 310
317 311 $ cd ..
318 312
319 313
320 314 New-commit as draft (default)
321 315
322 316 $ cp -r base simple-secret
323 317 $ cd simple-secret
324 318 $ cat >> .hg/hgrc << EOF
325 319 > [phases]
326 320 > new-commit=secret
327 321 > EOF
328 322 $ hg histedit -r '947ece25170f' --commands - << EOF
329 323 > edit 947ece25170f 11 f
330 324 > pick d22905de3528 12 g
331 325 > pick ee4a24fc4dfa 13 h
332 326 > pick 9cd3934e05af 14 i
333 327 > pick c62e7241a4f2 15 j
334 328 > pick 14bda137d5b3 16 k
335 329 > EOF
336 330 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
337 331 adding f
338 332 Make changes as needed, you may commit or record as needed now.
339 333 When you are finished, run hg histedit --continue to resume.
340 334 [1]
341 335 $ echo f >> f
342 336 $ hg histedit --continue
343 337 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
344 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
345 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
346 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
347 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
348 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
349 338 $ hg log -G
350 339 @ 24:12925f763c90 (secret) k
351 340 |
352 341 o 23:4545a6e77442 (secret) j
353 342 |
354 343 o 22:d947a0798e76 (secret) i
355 344 |
356 345 o 21:28fb35ae4ebb (draft) h
357 346 |
358 347 o 20:10b22a5a9645 (draft) g
359 348 |
360 349 o 19:c5a1db4a69f5 (draft) f
361 350 |
362 351 o 12:40db8afa467b (public) c
363 352 |
364 353 o 0:cb9a9f314b8b (public) a
365 354
366 355 $ cd ..
367 356
368 357
369 358 Changeset reordering
370 359 -------------------------------------------
371 360
372 361 If a secret changeset is put before a draft one, all descendant should be secret.
373 362 It seems more important to present the secret phase.
374 363
375 364 $ cp -r base reorder
376 365 $ cd reorder
377 366 $ hg histedit -r '947ece25170f' --commands - << EOF
378 367 > pick 947ece25170f 11 f
379 368 > pick c62e7241a4f2 15 j
380 369 > pick d22905de3528 12 g
381 370 > pick 9cd3934e05af 14 i
382 371 > pick ee4a24fc4dfa 13 h
383 372 > pick 14bda137d5b3 16 k
384 373 > EOF
385 374 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
386 375 0 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 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
389 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
390 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 376 $ hg log -G
392 377 @ 23:9e712162b2c1 (secret) k
393 378 |
394 379 o 22:490861543602 (secret) h
395 380 |
396 381 o 21:86aeda50b70d (secret) i
397 382 |
398 383 o 20:b2fa360bc090 (secret) g
399 384 |
400 385 o 19:e10fb4e3eb8e (secret) j
401 386 |
402 387 o 13:947ece25170f (draft) f
403 388 |
404 389 o 12:40db8afa467b (public) c
405 390 |
406 391 o 0:cb9a9f314b8b (public) a
407 392
408 393 $ cd ..
409 394
410 395 Changeset folding
411 396 -------------------------------------------
412 397
413 398 Folding a secret changeset with a draft one turn the result secret (again,
414 399 better safe than sorry). Folding between same phase changeset still works
415 400
416 401 Note that there is a few reordering in this series for more extensive test
417 402
418 403 $ cp -r base folding
419 404 $ cd folding
420 405 $ cat >> .hg/hgrc << EOF
421 406 > [phases]
422 407 > new-commit=secret
423 408 > EOF
424 409 $ hg histedit -r '947ece25170f' --commands - << EOF
425 410 > pick ee4a24fc4dfa 13 h
426 411 > fold 947ece25170f 11 f
427 412 > pick d22905de3528 12 g
428 413 > fold c62e7241a4f2 15 j
429 414 > pick 9cd3934e05af 14 i
430 415 > fold 14bda137d5b3 16 k
431 416 > EOF
432 417 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
433 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
434 418 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
435 419 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
436 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
437 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
438 420 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
439 421 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
440 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
441 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
442 422 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
443 423 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 424 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
445 425 $ hg log -G
446 426 @ 27:769e8ee8708e (secret) i
447 427 |
448 428 o 24:3de6dbab1b62 (secret) g
449 429 |
450 430 o 21:1d51647632b2 (draft) h
451 431 |
452 432 o 12:40db8afa467b (public) c
453 433 |
454 434 o 0:cb9a9f314b8b (public) a
455 435
456 436 $ hg co 3de6dbab1b62
457 437 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
458 438 $ echo wat >> wat
459 439 $ hg add wat
460 440 $ hg ci -m 'add wat'
461 441 created new head
462 442 $ hg merge 769e8ee8708e
463 443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
464 444 (branch merge, don't forget to commit)
465 445 $ hg ci -m 'merge'
466 446 $ echo not wat > wat
467 447 $ hg ci -m 'modify wat'
468 448 $ hg histedit 1d51647632b2
469 449 abort: cannot edit history that contains merges
470 450 [255]
471 451 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now