##// END OF EJS Templates
histedit: make histedit prune when obsolete is enabled...
Durham Goode -
r26763:50fc80e4 default
parent child Browse files
Show More
@@ -1,1230 +1,1236 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
154 154 try:
155 155 import cPickle as pickle
156 156 pickle.dump # import now
157 157 except ImportError:
158 158 import pickle
159 159 import errno
160 160 import os
161 161 import sys
162 162
163 163 from mercurial import cmdutil
164 164 from mercurial import discovery
165 165 from mercurial import error
166 166 from mercurial import copies
167 167 from mercurial import context
168 168 from mercurial import exchange
169 169 from mercurial import extensions
170 170 from mercurial import hg
171 171 from mercurial import node
172 172 from mercurial import repair
173 173 from mercurial import scmutil
174 174 from mercurial import util
175 175 from mercurial import obsolete
176 176 from mercurial import merge as mergemod
177 177 from mercurial.lock import release
178 178 from mercurial.i18n import _
179 179
180 180 cmdtable = {}
181 181 command = cmdutil.command(cmdtable)
182 182
183 183 # Note for extension authors: ONLY specify testedwith = 'internal' for
184 184 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
185 185 # be specifying the version(s) of Mercurial they are tested with, or
186 186 # leave the attribute unspecified.
187 187 testedwith = 'internal'
188 188
189 189 # i18n: command names and abbreviations must remain untranslated
190 190 editcomment = _("""# Edit history between %s and %s
191 191 #
192 192 # Commits are listed from least to most recent
193 193 #
194 194 # Commands:
195 195 # p, pick = use commit
196 196 # e, edit = use commit, but stop for amending
197 197 # f, fold = use commit, but combine it with the one above
198 198 # r, roll = like fold, but discard this commit's description
199 199 # d, drop = remove commit from history
200 200 # m, mess = edit commit message without changing commit content
201 201 #
202 202 """)
203 203
204 204 class histeditstate(object):
205 205 def __init__(self, repo, parentctxnode=None, rules=None, keep=None,
206 206 topmost=None, replacements=None, lock=None, wlock=None):
207 207 self.repo = repo
208 208 self.rules = rules
209 209 self.keep = keep
210 210 self.topmost = topmost
211 211 self.parentctxnode = parentctxnode
212 212 self.lock = lock
213 213 self.wlock = wlock
214 214 self.backupfile = None
215 215 if replacements is None:
216 216 self.replacements = []
217 217 else:
218 218 self.replacements = replacements
219 219
220 220 def read(self):
221 221 """Load histedit state from disk and set fields appropriately."""
222 222 try:
223 223 fp = self.repo.vfs('histedit-state', 'r')
224 224 except IOError as err:
225 225 if err.errno != errno.ENOENT:
226 226 raise
227 227 raise error.Abort(_('no histedit in progress'))
228 228
229 229 try:
230 230 data = pickle.load(fp)
231 231 parentctxnode, rules, keep, topmost, replacements = data
232 232 backupfile = None
233 233 except pickle.UnpicklingError:
234 234 data = self._load()
235 235 parentctxnode, rules, keep, topmost, replacements, backupfile = data
236 236
237 237 self.parentctxnode = parentctxnode
238 238 self.rules = rules
239 239 self.keep = keep
240 240 self.topmost = topmost
241 241 self.replacements = replacements
242 242 self.backupfile = backupfile
243 243
244 244 def write(self):
245 245 fp = self.repo.vfs('histedit-state', 'w')
246 246 fp.write('v1\n')
247 247 fp.write('%s\n' % node.hex(self.parentctxnode))
248 248 fp.write('%s\n' % node.hex(self.topmost))
249 249 fp.write('%s\n' % self.keep)
250 250 fp.write('%d\n' % len(self.rules))
251 251 for rule in self.rules:
252 252 fp.write('%s\n' % rule[0]) # action
253 253 fp.write('%s\n' % rule[1]) # remainder
254 254 fp.write('%d\n' % len(self.replacements))
255 255 for replacement in self.replacements:
256 256 fp.write('%s%s\n' % (node.hex(replacement[0]), ''.join(node.hex(r)
257 257 for r in replacement[1])))
258 258 backupfile = self.backupfile
259 259 if not backupfile:
260 260 backupfile = ''
261 261 fp.write('%s\n' % backupfile)
262 262 fp.close()
263 263
264 264 def _load(self):
265 265 fp = self.repo.vfs('histedit-state', 'r')
266 266 lines = [l[:-1] for l in fp.readlines()]
267 267
268 268 index = 0
269 269 lines[index] # version number
270 270 index += 1
271 271
272 272 parentctxnode = node.bin(lines[index])
273 273 index += 1
274 274
275 275 topmost = node.bin(lines[index])
276 276 index += 1
277 277
278 278 keep = lines[index] == 'True'
279 279 index += 1
280 280
281 281 # Rules
282 282 rules = []
283 283 rulelen = int(lines[index])
284 284 index += 1
285 285 for i in xrange(rulelen):
286 286 ruleaction = lines[index]
287 287 index += 1
288 288 rule = lines[index]
289 289 index += 1
290 290 rules.append((ruleaction, rule))
291 291
292 292 # Replacements
293 293 replacements = []
294 294 replacementlen = int(lines[index])
295 295 index += 1
296 296 for i in xrange(replacementlen):
297 297 replacement = lines[index]
298 298 original = node.bin(replacement[:40])
299 299 succ = [node.bin(replacement[i:i + 40]) for i in
300 300 range(40, len(replacement), 40)]
301 301 replacements.append((original, succ))
302 302 index += 1
303 303
304 304 backupfile = lines[index]
305 305 index += 1
306 306
307 307 fp.close()
308 308
309 309 return parentctxnode, rules, keep, topmost, replacements, backupfile
310 310
311 311 def clear(self):
312 312 if self.inprogress():
313 313 self.repo.vfs.unlink('histedit-state')
314 314
315 315 def inprogress(self):
316 316 return self.repo.vfs.exists('histedit-state')
317 317
318 318 class histeditaction(object):
319 319 def __init__(self, state, node):
320 320 self.state = state
321 321 self.repo = state.repo
322 322 self.node = node
323 323
324 324 @classmethod
325 325 def fromrule(cls, state, rule):
326 326 """Parses the given rule, returning an instance of the histeditaction.
327 327 """
328 328 repo = state.repo
329 329 rulehash = rule.strip().split(' ', 1)[0]
330 330 try:
331 331 node = repo[rulehash].node()
332 332 except error.RepoError:
333 333 raise error.Abort(_('unknown changeset %s listed') % rulehash[:12])
334 334 return cls(state, node)
335 335
336 336 def run(self):
337 337 """Runs the action. The default behavior is simply apply the action's
338 338 rulectx onto the current parentctx."""
339 339 self.applychange()
340 340 self.continuedirty()
341 341 return self.continueclean()
342 342
343 343 def applychange(self):
344 344 """Applies the changes from this action's rulectx onto the current
345 345 parentctx, but does not commit them."""
346 346 repo = self.repo
347 347 rulectx = repo[self.node]
348 348 hg.update(repo, self.state.parentctxnode)
349 349 stats = applychanges(repo.ui, repo, rulectx, {})
350 350 if stats and stats[3] > 0:
351 351 raise error.InterventionRequired(_('Fix up the change and run '
352 352 'hg histedit --continue'))
353 353
354 354 def continuedirty(self):
355 355 """Continues the action when changes have been applied to the working
356 356 copy. The default behavior is to commit the dirty changes."""
357 357 repo = self.repo
358 358 rulectx = repo[self.node]
359 359
360 360 editor = self.commiteditor()
361 361 commit = commitfuncfor(repo, rulectx)
362 362
363 363 commit(text=rulectx.description(), user=rulectx.user(),
364 364 date=rulectx.date(), extra=rulectx.extra(), editor=editor)
365 365
366 366 def commiteditor(self):
367 367 """The editor to be used to edit the commit message."""
368 368 return False
369 369
370 370 def continueclean(self):
371 371 """Continues the action when the working copy is clean. The default
372 372 behavior is to accept the current commit as the new version of the
373 373 rulectx."""
374 374 ctx = self.repo['.']
375 375 if ctx.node() == self.state.parentctxnode:
376 376 self.repo.ui.warn(_('%s: empty changeset\n') %
377 377 node.short(self.node))
378 378 return ctx, [(self.node, tuple())]
379 379 if ctx.node() == self.node:
380 380 # Nothing changed
381 381 return ctx, []
382 382 return ctx, [(self.node, (ctx.node(),))]
383 383
384 384 def commitfuncfor(repo, src):
385 385 """Build a commit function for the replacement of <src>
386 386
387 387 This function ensure we apply the same treatment to all changesets.
388 388
389 389 - Add a 'histedit_source' entry in extra.
390 390
391 391 Note that fold has its own separated logic because its handling is a bit
392 392 different and not easily factored out of the fold method.
393 393 """
394 394 phasemin = src.phase()
395 395 def commitfunc(**kwargs):
396 396 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
397 397 try:
398 398 repo.ui.setconfig('phases', 'new-commit', phasemin,
399 399 'histedit')
400 400 extra = kwargs.get('extra', {}).copy()
401 401 extra['histedit_source'] = src.hex()
402 402 kwargs['extra'] = extra
403 403 return repo.commit(**kwargs)
404 404 finally:
405 405 repo.ui.restoreconfig(phasebackup)
406 406 return commitfunc
407 407
408 408 def applychanges(ui, repo, ctx, opts):
409 409 """Merge changeset from ctx (only) in the current working directory"""
410 410 wcpar = repo.dirstate.parents()[0]
411 411 if ctx.p1().node() == wcpar:
412 412 # edits are "in place" we do not need to make any merge,
413 413 # just applies changes on parent for edition
414 414 cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True)
415 415 stats = None
416 416 else:
417 417 try:
418 418 # ui.forcemerge is an internal variable, do not document
419 419 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
420 420 'histedit')
421 421 stats = mergemod.graft(repo, ctx, ctx.p1(), ['local', 'histedit'])
422 422 finally:
423 423 repo.ui.setconfig('ui', 'forcemerge', '', 'histedit')
424 424 return stats
425 425
426 426 def collapse(repo, first, last, commitopts, skipprompt=False):
427 427 """collapse the set of revisions from first to last as new one.
428 428
429 429 Expected commit options are:
430 430 - message
431 431 - date
432 432 - username
433 433 Commit message is edited in all cases.
434 434
435 435 This function works in memory."""
436 436 ctxs = list(repo.set('%d::%d', first, last))
437 437 if not ctxs:
438 438 return None
439 439 for c in ctxs:
440 440 if not c.mutable():
441 441 raise error.Abort(
442 442 _("cannot fold into public change %s") % node.short(c.node()))
443 443 base = first.parents()[0]
444 444
445 445 # commit a new version of the old changeset, including the update
446 446 # collect all files which might be affected
447 447 files = set()
448 448 for ctx in ctxs:
449 449 files.update(ctx.files())
450 450
451 451 # Recompute copies (avoid recording a -> b -> a)
452 452 copied = copies.pathcopies(base, last)
453 453
454 454 # prune files which were reverted by the updates
455 455 def samefile(f):
456 456 if f in last.manifest():
457 457 a = last.filectx(f)
458 458 if f in base.manifest():
459 459 b = base.filectx(f)
460 460 return (a.data() == b.data()
461 461 and a.flags() == b.flags())
462 462 else:
463 463 return False
464 464 else:
465 465 return f not in base.manifest()
466 466 files = [f for f in files if not samefile(f)]
467 467 # commit version of these files as defined by head
468 468 headmf = last.manifest()
469 469 def filectxfn(repo, ctx, path):
470 470 if path in headmf:
471 471 fctx = last[path]
472 472 flags = fctx.flags()
473 473 mctx = context.memfilectx(repo,
474 474 fctx.path(), fctx.data(),
475 475 islink='l' in flags,
476 476 isexec='x' in flags,
477 477 copied=copied.get(path))
478 478 return mctx
479 479 return None
480 480
481 481 if commitopts.get('message'):
482 482 message = commitopts['message']
483 483 else:
484 484 message = first.description()
485 485 user = commitopts.get('user')
486 486 date = commitopts.get('date')
487 487 extra = commitopts.get('extra')
488 488
489 489 parents = (first.p1().node(), first.p2().node())
490 490 editor = None
491 491 if not skipprompt:
492 492 editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold')
493 493 new = context.memctx(repo,
494 494 parents=parents,
495 495 text=message,
496 496 files=files,
497 497 filectxfn=filectxfn,
498 498 user=user,
499 499 date=date,
500 500 extra=extra,
501 501 editor=editor)
502 502 return repo.commitctx(new)
503 503
504 504 class pick(histeditaction):
505 505 def run(self):
506 506 rulectx = self.repo[self.node]
507 507 if rulectx.parents()[0].node() == self.state.parentctxnode:
508 508 self.repo.ui.debug('node %s unchanged\n' % node.short(self.node))
509 509 return rulectx, []
510 510
511 511 return super(pick, self).run()
512 512
513 513 class edit(histeditaction):
514 514 def run(self):
515 515 repo = self.repo
516 516 rulectx = repo[self.node]
517 517 hg.update(repo, self.state.parentctxnode)
518 518 applychanges(repo.ui, repo, rulectx, {})
519 519 raise error.InterventionRequired(
520 520 _('Make changes as needed, you may commit or record as needed '
521 521 'now.\nWhen you are finished, run hg histedit --continue to '
522 522 'resume.'))
523 523
524 524 def commiteditor(self):
525 525 return cmdutil.getcommiteditor(edit=True, editform='histedit.edit')
526 526
527 527 class fold(histeditaction):
528 528 def continuedirty(self):
529 529 repo = self.repo
530 530 rulectx = repo[self.node]
531 531
532 532 commit = commitfuncfor(repo, rulectx)
533 533 commit(text='fold-temp-revision %s' % node.short(self.node),
534 534 user=rulectx.user(), date=rulectx.date(),
535 535 extra=rulectx.extra())
536 536
537 537 def continueclean(self):
538 538 repo = self.repo
539 539 ctx = repo['.']
540 540 rulectx = repo[self.node]
541 541 parentctxnode = self.state.parentctxnode
542 542 if ctx.node() == parentctxnode:
543 543 repo.ui.warn(_('%s: empty changeset\n') %
544 544 node.short(self.node))
545 545 return ctx, [(self.node, (parentctxnode,))]
546 546
547 547 parentctx = repo[parentctxnode]
548 548 newcommits = set(c.node() for c in repo.set('(%d::. - %d)', parentctx,
549 549 parentctx))
550 550 if not newcommits:
551 551 repo.ui.warn(_('%s: cannot fold - working copy is not a '
552 552 'descendant of previous commit %s\n') %
553 553 (node.short(self.node), node.short(parentctxnode)))
554 554 return ctx, [(self.node, (ctx.node(),))]
555 555
556 556 middlecommits = newcommits.copy()
557 557 middlecommits.discard(ctx.node())
558 558
559 559 return self.finishfold(repo.ui, repo, parentctx, rulectx, ctx.node(),
560 560 middlecommits)
561 561
562 562 def skipprompt(self):
563 563 """Returns true if the rule should skip the message editor.
564 564
565 565 For example, 'fold' wants to show an editor, but 'rollup'
566 566 doesn't want to.
567 567 """
568 568 return False
569 569
570 570 def mergedescs(self):
571 571 """Returns true if the rule should merge messages of multiple changes.
572 572
573 573 This exists mainly so that 'rollup' rules can be a subclass of
574 574 'fold'.
575 575 """
576 576 return True
577 577
578 578 def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges):
579 579 parent = ctx.parents()[0].node()
580 580 hg.update(repo, parent)
581 581 ### prepare new commit data
582 582 commitopts = {}
583 583 commitopts['user'] = ctx.user()
584 584 # commit message
585 585 if not self.mergedescs():
586 586 newmessage = ctx.description()
587 587 else:
588 588 newmessage = '\n***\n'.join(
589 589 [ctx.description()] +
590 590 [repo[r].description() for r in internalchanges] +
591 591 [oldctx.description()]) + '\n'
592 592 commitopts['message'] = newmessage
593 593 # date
594 594 commitopts['date'] = max(ctx.date(), oldctx.date())
595 595 extra = ctx.extra().copy()
596 596 # histedit_source
597 597 # note: ctx is likely a temporary commit but that the best we can do
598 598 # here. This is sufficient to solve issue3681 anyway.
599 599 extra['histedit_source'] = '%s,%s' % (ctx.hex(), oldctx.hex())
600 600 commitopts['extra'] = extra
601 601 phasebackup = repo.ui.backupconfig('phases', 'new-commit')
602 602 try:
603 603 phasemin = max(ctx.phase(), oldctx.phase())
604 604 repo.ui.setconfig('phases', 'new-commit', phasemin, 'histedit')
605 605 n = collapse(repo, ctx, repo[newnode], commitopts,
606 606 skipprompt=self.skipprompt())
607 607 finally:
608 608 repo.ui.restoreconfig(phasebackup)
609 609 if n is None:
610 610 return ctx, []
611 611 hg.update(repo, n)
612 612 replacements = [(oldctx.node(), (newnode,)),
613 613 (ctx.node(), (n,)),
614 614 (newnode, (n,)),
615 615 ]
616 616 for ich in internalchanges:
617 617 replacements.append((ich, (n,)))
618 618 return repo[n], replacements
619 619
620 620 class _multifold(fold):
621 621 """fold subclass used for when multiple folds happen in a row
622 622
623 623 We only want to fire the editor for the folded message once when
624 624 (say) four changes are folded down into a single change. This is
625 625 similar to rollup, but we should preserve both messages so that
626 626 when the last fold operation runs we can show the user all the
627 627 commit messages in their editor.
628 628 """
629 629 def skipprompt(self):
630 630 return True
631 631
632 632 class rollup(fold):
633 633 def mergedescs(self):
634 634 return False
635 635
636 636 def skipprompt(self):
637 637 return True
638 638
639 639 class drop(histeditaction):
640 640 def run(self):
641 641 parentctx = self.repo[self.state.parentctxnode]
642 642 return parentctx, [(self.node, tuple())]
643 643
644 644 class message(histeditaction):
645 645 def commiteditor(self):
646 646 return cmdutil.getcommiteditor(edit=True, editform='histedit.mess')
647 647
648 648 def findoutgoing(ui, repo, remote=None, force=False, opts=None):
649 649 """utility function to find the first outgoing changeset
650 650
651 651 Used by initialization code"""
652 652 if opts is None:
653 653 opts = {}
654 654 dest = ui.expandpath(remote or 'default-push', remote or 'default')
655 655 dest, revs = hg.parseurl(dest, None)[:2]
656 656 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
657 657
658 658 revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
659 659 other = hg.peer(repo, opts, dest)
660 660
661 661 if revs:
662 662 revs = [repo.lookup(rev) for rev in revs]
663 663
664 664 outgoing = discovery.findcommonoutgoing(repo, other, revs, force=force)
665 665 if not outgoing.missing:
666 666 raise error.Abort(_('no outgoing ancestors'))
667 667 roots = list(repo.revs("roots(%ln)", outgoing.missing))
668 668 if 1 < len(roots):
669 669 msg = _('there are ambiguous outgoing revisions')
670 670 hint = _('see "hg help histedit" for more detail')
671 671 raise error.Abort(msg, hint=hint)
672 672 return repo.lookup(roots[0])
673 673
674 674 actiontable = {'p': pick,
675 675 'pick': pick,
676 676 'e': edit,
677 677 'edit': edit,
678 678 'f': fold,
679 679 'fold': fold,
680 680 '_multifold': _multifold,
681 681 'r': rollup,
682 682 'roll': rollup,
683 683 'd': drop,
684 684 'drop': drop,
685 685 'm': message,
686 686 'mess': message,
687 687 }
688 688
689 689 @command('histedit',
690 690 [('', 'commands', '',
691 691 _('read history edits from the specified file'), _('FILE')),
692 692 ('c', 'continue', False, _('continue an edit already in progress')),
693 693 ('', 'edit-plan', False, _('edit remaining actions list')),
694 694 ('k', 'keep', False,
695 695 _("don't strip old nodes after edit is complete")),
696 696 ('', 'abort', False, _('abort an edit in progress')),
697 697 ('o', 'outgoing', False, _('changesets not found in destination')),
698 698 ('f', 'force', False,
699 699 _('force outgoing even for unrelated repositories')),
700 700 ('r', 'rev', [], _('first revision to be edited'), _('REV'))],
701 701 _("ANCESTOR | --outgoing [URL]"))
702 702 def histedit(ui, repo, *freeargs, **opts):
703 703 """interactively edit changeset history
704 704
705 705 This command edits changesets between ANCESTOR and the parent of
706 706 the working directory.
707 707
708 708 With --outgoing, this edits changesets not found in the
709 709 destination repository. If URL of the destination is omitted, the
710 710 'default-push' (or 'default') path will be used.
711 711
712 712 For safety, this command is also aborted if there are ambiguous
713 713 outgoing revisions which may confuse users: for example, if there
714 714 are multiple branches containing outgoing revisions.
715 715
716 716 Use "min(outgoing() and ::.)" or similar revset specification
717 717 instead of --outgoing to specify edit target revision exactly in
718 718 such ambiguous situation. See :hg:`help revsets` for detail about
719 719 selecting revisions.
720 720
721 721 Returns 0 on success, 1 if user intervention is required (not only
722 722 for intentional "edit" command, but also for resolving unexpected
723 723 conflicts).
724 724 """
725 725 state = histeditstate(repo)
726 726 try:
727 727 state.wlock = repo.wlock()
728 728 state.lock = repo.lock()
729 729 _histedit(ui, repo, state, *freeargs, **opts)
730 730 finally:
731 731 release(state.lock, state.wlock)
732 732
733 733 def _histedit(ui, repo, state, *freeargs, **opts):
734 734 # TODO only abort if we try and histedit mq patches, not just
735 735 # blanket if mq patches are applied somewhere
736 736 mq = getattr(repo, 'mq', None)
737 737 if mq and mq.applied:
738 738 raise error.Abort(_('source has mq patches applied'))
739 739
740 740 # basic argument incompatibility processing
741 741 outg = opts.get('outgoing')
742 742 cont = opts.get('continue')
743 743 editplan = opts.get('edit_plan')
744 744 abort = opts.get('abort')
745 745 force = opts.get('force')
746 746 rules = opts.get('commands', '')
747 747 revs = opts.get('rev', [])
748 748 goal = 'new' # This invocation goal, in new, continue, abort
749 749 if force and not outg:
750 750 raise error.Abort(_('--force only allowed with --outgoing'))
751 751 if cont:
752 752 if any((outg, abort, revs, freeargs, rules, editplan)):
753 753 raise error.Abort(_('no arguments allowed with --continue'))
754 754 goal = 'continue'
755 755 elif abort:
756 756 if any((outg, revs, freeargs, rules, editplan)):
757 757 raise error.Abort(_('no arguments allowed with --abort'))
758 758 goal = 'abort'
759 759 elif editplan:
760 760 if any((outg, revs, freeargs)):
761 761 raise error.Abort(_('only --commands argument allowed with '
762 762 '--edit-plan'))
763 763 goal = 'edit-plan'
764 764 else:
765 765 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
766 766 raise error.Abort(_('history edit already in progress, try '
767 767 '--continue or --abort'))
768 768 if outg:
769 769 if revs:
770 770 raise error.Abort(_('no revisions allowed with --outgoing'))
771 771 if len(freeargs) > 1:
772 772 raise error.Abort(
773 773 _('only one repo argument allowed with --outgoing'))
774 774 else:
775 775 revs.extend(freeargs)
776 776 if len(revs) == 0:
777 777 # experimental config: histedit.defaultrev
778 778 histeditdefault = ui.config('histedit', 'defaultrev')
779 779 if histeditdefault:
780 780 revs.append(histeditdefault)
781 781 if len(revs) != 1:
782 782 raise error.Abort(
783 783 _('histedit requires exactly one ancestor revision'))
784 784
785 785
786 786 replacements = []
787 787 state.keep = opts.get('keep', False)
788 788 supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)
789 789
790 790 # rebuild state
791 791 if goal == 'continue':
792 792 state.read()
793 793 state = bootstrapcontinue(ui, state, opts)
794 794 elif goal == 'edit-plan':
795 795 state.read()
796 796 if not rules:
797 797 comment = editcomment % (node.short(state.parentctxnode),
798 798 node.short(state.topmost))
799 799 rules = ruleeditor(repo, ui, state.rules, comment)
800 800 else:
801 801 if rules == '-':
802 802 f = sys.stdin
803 803 else:
804 804 f = open(rules)
805 805 rules = f.read()
806 806 f.close()
807 807 rules = [l for l in (r.strip() for r in rules.splitlines())
808 808 if l and not l.startswith('#')]
809 809 rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
810 810 state.rules = rules
811 811 state.write()
812 812 return
813 813 elif goal == 'abort':
814 814 try:
815 815 state.read()
816 816 tmpnodes, leafs = newnodestoabort(state)
817 817 ui.debug('restore wc to old parent %s\n'
818 818 % node.short(state.topmost))
819 819
820 820 # Recover our old commits if necessary
821 821 if not state.topmost in repo and state.backupfile:
822 822 backupfile = repo.join(state.backupfile)
823 823 f = hg.openpath(ui, backupfile)
824 824 gen = exchange.readbundle(ui, f, backupfile)
825 825 gen.apply(repo, 'histedit', 'bundle:' + backupfile)
826 826 os.remove(backupfile)
827 827
828 828 # check whether we should update away
829 829 if repo.unfiltered().revs('parents() and (%n or %ln::)',
830 830 state.parentctxnode, leafs | tmpnodes):
831 831 hg.clean(repo, state.topmost)
832 832 cleanupnode(ui, repo, 'created', tmpnodes)
833 833 cleanupnode(ui, repo, 'temp', leafs)
834 834 except Exception:
835 835 if state.inprogress():
836 836 ui.warn(_('warning: encountered an exception during histedit '
837 837 '--abort; the repository may not have been completely '
838 838 'cleaned up\n'))
839 839 raise
840 840 finally:
841 841 state.clear()
842 842 return
843 843 else:
844 844 cmdutil.checkunfinished(repo)
845 845 cmdutil.bailifchanged(repo)
846 846
847 847 topmost, empty = repo.dirstate.parents()
848 848 if outg:
849 849 if freeargs:
850 850 remote = freeargs[0]
851 851 else:
852 852 remote = None
853 853 root = findoutgoing(ui, repo, remote, force, opts)
854 854 else:
855 855 rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
856 856 if len(rr) != 1:
857 857 raise error.Abort(_('The specified revisions must have '
858 858 'exactly one common root'))
859 859 root = rr[0].node()
860 860
861 861 revs = between(repo, root, topmost, state.keep)
862 862 if not revs:
863 863 raise error.Abort(_('%s is not an ancestor of working directory') %
864 864 node.short(root))
865 865
866 866 ctxs = [repo[r] for r in revs]
867 867 if not rules:
868 868 comment = editcomment % (node.short(root), node.short(topmost))
869 869 rules = ruleeditor(repo, ui, [['pick', c] for c in ctxs], comment)
870 870 else:
871 871 if rules == '-':
872 872 f = sys.stdin
873 873 else:
874 874 f = open(rules)
875 875 rules = f.read()
876 876 f.close()
877 877 rules = [l for l in (r.strip() for r in rules.splitlines())
878 878 if l and not l.startswith('#')]
879 879 rules = verifyrules(rules, repo, ctxs)
880 880
881 881 parentctxnode = repo[root].parents()[0].node()
882 882
883 883 state.parentctxnode = parentctxnode
884 884 state.rules = rules
885 885 state.topmost = topmost
886 886 state.replacements = replacements
887 887
888 888 # Create a backup so we can always abort completely.
889 889 backupfile = None
890 890 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
891 891 backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
892 892 'histedit')
893 893 state.backupfile = backupfile
894 894
895 895 # preprocess rules so that we can hide inner folds from the user
896 896 # and only show one editor
897 897 rules = state.rules[:]
898 898 for idx, ((action, ha), (nextact, unused)) in enumerate(
899 899 zip(rules, rules[1:] + [(None, None)])):
900 900 if action == 'fold' and nextact == 'fold':
901 901 state.rules[idx] = '_multifold', ha
902 902
903 903 while state.rules:
904 904 state.write()
905 905 action, ha = state.rules.pop(0)
906 906 ui.debug('histedit: processing %s %s\n' % (action, ha[:12]))
907 907 actobj = actiontable[action].fromrule(state, ha)
908 908 parentctx, replacement_ = actobj.run()
909 909 state.parentctxnode = parentctx.node()
910 910 state.replacements.extend(replacement_)
911 911 state.write()
912 912
913 913 hg.update(repo, state.parentctxnode)
914 914
915 915 mapping, tmpnodes, created, ntm = processreplacement(state)
916 916 if mapping:
917 917 for prec, succs in mapping.iteritems():
918 918 if not succs:
919 919 ui.debug('histedit: %s is dropped\n' % node.short(prec))
920 920 else:
921 921 ui.debug('histedit: %s is replaced by %s\n' % (
922 922 node.short(prec), node.short(succs[0])))
923 923 if len(succs) > 1:
924 924 m = 'histedit: %s'
925 925 for n in succs[1:]:
926 926 ui.debug(m % node.short(n))
927 927
928 if supportsmarkers:
929 # Only create markers if the temp nodes weren't already removed.
930 obsolete.createmarkers(repo, ((repo[t],()) for t in sorted(tmpnodes)
931 if t in repo))
932 else:
933 cleanupnode(ui, repo, 'temp', tmpnodes)
934
928 935 if not state.keep:
929 936 if mapping:
930 937 movebookmarks(ui, repo, mapping, state.topmost, ntm)
931 938 # TODO update mq state
932 939 if supportsmarkers:
933 940 markers = []
934 941 # sort by revision number because it sound "right"
935 942 for prec in sorted(mapping, key=repo.changelog.rev):
936 943 succs = mapping[prec]
937 944 markers.append((repo[prec],
938 945 tuple(repo[s] for s in succs)))
939 946 if markers:
940 947 obsolete.createmarkers(repo, markers)
941 948 else:
942 949 cleanupnode(ui, repo, 'replaced', mapping)
943 950
944 cleanupnode(ui, repo, 'temp', tmpnodes)
945 951 state.clear()
946 952 if os.path.exists(repo.sjoin('undo')):
947 953 os.unlink(repo.sjoin('undo'))
948 954
949 955 def bootstrapcontinue(ui, state, opts):
950 956 repo = state.repo
951 957 if state.rules:
952 958 action, currentnode = state.rules.pop(0)
953 959
954 960 actobj = actiontable[action].fromrule(state, currentnode)
955 961
956 962 s = repo.status()
957 963 if s.modified or s.added or s.removed or s.deleted:
958 964 actobj.continuedirty()
959 965 s = repo.status()
960 966 if s.modified or s.added or s.removed or s.deleted:
961 967 raise error.Abort(_("working copy still dirty"))
962 968
963 969 parentctx, replacements = actobj.continueclean()
964 970
965 971 state.parentctxnode = parentctx.node()
966 972 state.replacements.extend(replacements)
967 973
968 974 return state
969 975
970 976 def between(repo, old, new, keep):
971 977 """select and validate the set of revision to edit
972 978
973 979 When keep is false, the specified set can't have children."""
974 980 ctxs = list(repo.set('%n::%n', old, new))
975 981 if ctxs and not keep:
976 982 if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
977 983 repo.revs('(%ld::) - (%ld)', ctxs, ctxs)):
978 984 raise error.Abort(_('cannot edit history that would orphan nodes'))
979 985 if repo.revs('(%ld) and merge()', ctxs):
980 986 raise error.Abort(_('cannot edit history that contains merges'))
981 987 root = ctxs[0] # list is already sorted by repo.set
982 988 if not root.mutable():
983 989 raise error.Abort(_('cannot edit public changeset: %s') % root,
984 990 hint=_('see "hg help phases" for details'))
985 991 return [c.node() for c in ctxs]
986 992
987 993 def makedesc(repo, action, rev):
988 994 """build a initial action line for a ctx
989 995
990 996 line are in the form:
991 997
992 998 <action> <hash> <rev> <summary>
993 999 """
994 1000 ctx = repo[rev]
995 1001 summary = ''
996 1002 if ctx.description():
997 1003 summary = ctx.description().splitlines()[0]
998 1004 line = '%s %s %d %s' % (action, ctx, ctx.rev(), summary)
999 1005 # trim to 80 columns so it's not stupidly wide in my editor
1000 1006 maxlen = repo.ui.configint('histedit', 'linelen', default=80)
1001 1007 maxlen = max(maxlen, 22) # avoid truncating hash
1002 1008 return util.ellipsis(line, maxlen)
1003 1009
1004 1010 def ruleeditor(repo, ui, rules, editcomment=""):
1005 1011 """open an editor to edit rules
1006 1012
1007 1013 rules are in the format [ [act, ctx], ...] like in state.rules
1008 1014 """
1009 1015 rules = '\n'.join([makedesc(repo, act, rev) for [act, rev] in rules])
1010 1016 rules += '\n\n'
1011 1017 rules += editcomment
1012 1018 rules = ui.edit(rules, ui.username())
1013 1019
1014 1020 # Save edit rules in .hg/histedit-last-edit.txt in case
1015 1021 # the user needs to ask for help after something
1016 1022 # surprising happens.
1017 1023 f = open(repo.join('histedit-last-edit.txt'), 'w')
1018 1024 f.write(rules)
1019 1025 f.close()
1020 1026
1021 1027 return rules
1022 1028
1023 1029 def verifyrules(rules, repo, ctxs):
1024 1030 """Verify that there exists exactly one edit rule per given changeset.
1025 1031
1026 1032 Will abort if there are to many or too few rules, a malformed rule,
1027 1033 or a rule on a changeset outside of the user-given range.
1028 1034 """
1029 1035 parsed = []
1030 1036 expected = set(c.hex() for c in ctxs)
1031 1037 seen = set()
1032 1038 for r in rules:
1033 1039 if ' ' not in r:
1034 1040 raise error.Abort(_('malformed line "%s"') % r)
1035 1041 action, rest = r.split(' ', 1)
1036 1042 ha = rest.strip().split(' ', 1)[0]
1037 1043 try:
1038 1044 ha = repo[ha].hex()
1039 1045 except error.RepoError:
1040 1046 raise error.Abort(_('unknown changeset %s listed') % ha[:12])
1041 1047 if ha not in expected:
1042 1048 raise error.Abort(
1043 1049 _('may not use changesets other than the ones listed'))
1044 1050 if ha in seen:
1045 1051 raise error.Abort(_('duplicated command for changeset %s') %
1046 1052 ha[:12])
1047 1053 seen.add(ha)
1048 1054 if action not in actiontable or action.startswith('_'):
1049 1055 raise error.Abort(_('unknown action "%s"') % action)
1050 1056 parsed.append([action, ha])
1051 1057 missing = sorted(expected - seen) # sort to stabilize output
1052 1058 if missing:
1053 1059 raise error.Abort(_('missing rules for changeset %s') %
1054 1060 missing[0][:12],
1055 1061 hint=_('do you want to use the drop action?'))
1056 1062 return parsed
1057 1063
1058 1064 def newnodestoabort(state):
1059 1065 """process the list of replacements to return
1060 1066
1061 1067 1) the list of final node
1062 1068 2) the list of temporary node
1063 1069
1064 1070 This meant to be used on abort as less data are required in this case.
1065 1071 """
1066 1072 replacements = state.replacements
1067 1073 allsuccs = set()
1068 1074 replaced = set()
1069 1075 for rep in replacements:
1070 1076 allsuccs.update(rep[1])
1071 1077 replaced.add(rep[0])
1072 1078 newnodes = allsuccs - replaced
1073 1079 tmpnodes = allsuccs & replaced
1074 1080 return newnodes, tmpnodes
1075 1081
1076 1082
1077 1083 def processreplacement(state):
1078 1084 """process the list of replacements to return
1079 1085
1080 1086 1) the final mapping between original and created nodes
1081 1087 2) the list of temporary node created by histedit
1082 1088 3) the list of new commit created by histedit"""
1083 1089 replacements = state.replacements
1084 1090 allsuccs = set()
1085 1091 replaced = set()
1086 1092 fullmapping = {}
1087 1093 # initialize basic set
1088 1094 # fullmapping records all operations recorded in replacement
1089 1095 for rep in replacements:
1090 1096 allsuccs.update(rep[1])
1091 1097 replaced.add(rep[0])
1092 1098 fullmapping.setdefault(rep[0], set()).update(rep[1])
1093 1099 new = allsuccs - replaced
1094 1100 tmpnodes = allsuccs & replaced
1095 1101 # Reduce content fullmapping into direct relation between original nodes
1096 1102 # and final node created during history edition
1097 1103 # Dropped changeset are replaced by an empty list
1098 1104 toproceed = set(fullmapping)
1099 1105 final = {}
1100 1106 while toproceed:
1101 1107 for x in list(toproceed):
1102 1108 succs = fullmapping[x]
1103 1109 for s in list(succs):
1104 1110 if s in toproceed:
1105 1111 # non final node with unknown closure
1106 1112 # We can't process this now
1107 1113 break
1108 1114 elif s in final:
1109 1115 # non final node, replace with closure
1110 1116 succs.remove(s)
1111 1117 succs.update(final[s])
1112 1118 else:
1113 1119 final[x] = succs
1114 1120 toproceed.remove(x)
1115 1121 # remove tmpnodes from final mapping
1116 1122 for n in tmpnodes:
1117 1123 del final[n]
1118 1124 # we expect all changes involved in final to exist in the repo
1119 1125 # turn `final` into list (topologically sorted)
1120 1126 nm = state.repo.changelog.nodemap
1121 1127 for prec, succs in final.items():
1122 1128 final[prec] = sorted(succs, key=nm.get)
1123 1129
1124 1130 # computed topmost element (necessary for bookmark)
1125 1131 if new:
1126 1132 newtopmost = sorted(new, key=state.repo.changelog.rev)[-1]
1127 1133 elif not final:
1128 1134 # Nothing rewritten at all. we won't need `newtopmost`
1129 1135 # It is the same as `oldtopmost` and `processreplacement` know it
1130 1136 newtopmost = None
1131 1137 else:
1132 1138 # every body died. The newtopmost is the parent of the root.
1133 1139 r = state.repo.changelog.rev
1134 1140 newtopmost = state.repo[sorted(final, key=r)[0]].p1().node()
1135 1141
1136 1142 return final, tmpnodes, new, newtopmost
1137 1143
1138 1144 def movebookmarks(ui, repo, mapping, oldtopmost, newtopmost):
1139 1145 """Move bookmark from old to newly created node"""
1140 1146 if not mapping:
1141 1147 # if nothing got rewritten there is not purpose for this function
1142 1148 return
1143 1149 moves = []
1144 1150 for bk, old in sorted(repo._bookmarks.iteritems()):
1145 1151 if old == oldtopmost:
1146 1152 # special case ensure bookmark stay on tip.
1147 1153 #
1148 1154 # This is arguably a feature and we may only want that for the
1149 1155 # active bookmark. But the behavior is kept compatible with the old
1150 1156 # version for now.
1151 1157 moves.append((bk, newtopmost))
1152 1158 continue
1153 1159 base = old
1154 1160 new = mapping.get(base, None)
1155 1161 if new is None:
1156 1162 continue
1157 1163 while not new:
1158 1164 # base is killed, trying with parent
1159 1165 base = repo[base].p1().node()
1160 1166 new = mapping.get(base, (base,))
1161 1167 # nothing to move
1162 1168 moves.append((bk, new[-1]))
1163 1169 if moves:
1164 1170 marks = repo._bookmarks
1165 1171 for mark, new in moves:
1166 1172 old = marks[mark]
1167 1173 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
1168 1174 % (mark, node.short(old), node.short(new)))
1169 1175 marks[mark] = new
1170 1176 marks.write()
1171 1177
1172 1178 def cleanupnode(ui, repo, name, nodes):
1173 1179 """strip a group of nodes from the repository
1174 1180
1175 1181 The set of node to strip may contains unknown nodes."""
1176 1182 ui.debug('should strip %s nodes %s\n' %
1177 1183 (name, ', '.join([node.short(n) for n in nodes])))
1178 1184 lock = None
1179 1185 try:
1180 1186 lock = repo.lock()
1181 1187 # do not let filtering get in the way of the cleanse
1182 1188 # we should probably get rid of obsolescence marker created during the
1183 1189 # histedit, but we currently do not have such information.
1184 1190 repo = repo.unfiltered()
1185 1191 # Find all nodes that need to be stripped
1186 1192 # (we use %lr instead of %ln to silently ignore unknown items)
1187 1193 nm = repo.changelog.nodemap
1188 1194 nodes = sorted(n for n in nodes if n in nm)
1189 1195 roots = [c.node() for c in repo.set("roots(%ln)", nodes)]
1190 1196 for c in roots:
1191 1197 # We should process node in reverse order to strip tip most first.
1192 1198 # but this trigger a bug in changegroup hook.
1193 1199 # This would reduce bundle overhead
1194 1200 repair.strip(ui, repo, c)
1195 1201 finally:
1196 1202 release(lock)
1197 1203
1198 1204 def stripwrapper(orig, ui, repo, nodelist, *args, **kwargs):
1199 1205 if isinstance(nodelist, str):
1200 1206 nodelist = [nodelist]
1201 1207 if os.path.exists(os.path.join(repo.path, 'histedit-state')):
1202 1208 state = histeditstate(repo)
1203 1209 state.read()
1204 1210 histedit_nodes = set([repo[rulehash].node() for (action, rulehash)
1205 1211 in state.rules if rulehash in repo])
1206 1212 strip_nodes = set([repo[n].node() for n in nodelist])
1207 1213 common_nodes = histedit_nodes & strip_nodes
1208 1214 if common_nodes:
1209 1215 raise error.Abort(_("histedit in progress, can't strip %s")
1210 1216 % ', '.join(node.short(x) for x in common_nodes))
1211 1217 return orig(ui, repo, nodelist, *args, **kwargs)
1212 1218
1213 1219 extensions.wrapfunction(repair, 'strip', stripwrapper)
1214 1220
1215 1221 def summaryhook(ui, repo):
1216 1222 if not os.path.exists(repo.join('histedit-state')):
1217 1223 return
1218 1224 state = histeditstate(repo)
1219 1225 state.read()
1220 1226 if state.rules:
1221 1227 # i18n: column positioning for "hg summary"
1222 1228 ui.write(_('hist: %s (histedit --continue)\n') %
1223 1229 (ui.label(_('%d remaining'), 'histedit.remaining') %
1224 1230 len(state.rules)))
1225 1231
1226 1232 def extsetup(ui):
1227 1233 cmdutil.summaryhooks.add('histedit', summaryhook)
1228 1234 cmdutil.unfinishedstates.append(
1229 1235 ['histedit-state', False, True, _('histedit in progress'),
1230 1236 _("use 'hg histedit --continue' or 'hg histedit --abort'")])
@@ -1,348 +1,349 b''
1 1 Test argument handling and various data parsing
2 2 ==================================================
3 3
4 4
5 5 Enable extensions used by this test.
6 6 $ cat >>$HGRCPATH <<EOF
7 7 > [extensions]
8 8 > histedit=
9 9 > EOF
10 10
11 11 Repo setup.
12 12 $ hg init foo
13 13 $ cd foo
14 14 $ echo alpha >> alpha
15 15 $ hg addr
16 16 adding alpha
17 17 $ hg ci -m one
18 18 $ echo alpha >> alpha
19 19 $ hg ci -m two
20 20 $ echo alpha >> alpha
21 21 $ hg ci -m three
22 22 $ echo alpha >> alpha
23 23 $ hg ci -m four
24 24 $ echo alpha >> alpha
25 25 $ hg ci -m five
26 26
27 27 $ hg log --style compact --graph
28 28 @ 4[tip] 08d98a8350f3 1970-01-01 00:00 +0000 test
29 29 | five
30 30 |
31 31 o 3 c8e68270e35a 1970-01-01 00:00 +0000 test
32 32 | four
33 33 |
34 34 o 2 eb57da33312f 1970-01-01 00:00 +0000 test
35 35 | three
36 36 |
37 37 o 1 579e40513370 1970-01-01 00:00 +0000 test
38 38 | two
39 39 |
40 40 o 0 6058cbb6cfd7 1970-01-01 00:00 +0000 test
41 41 one
42 42
43 43
44 44 histedit --continue/--abort with no existing state
45 45 --------------------------------------------------
46 46
47 47 $ hg histedit --continue
48 48 abort: no histedit in progress
49 49 [255]
50 50 $ hg histedit --abort
51 51 abort: no histedit in progress
52 52 [255]
53 53
54 54 Run a dummy edit to make sure we get tip^^ correctly via revsingle.
55 55 --------------------------------------------------------------------
56 56
57 57 $ HGEDITOR=cat hg histedit "tip^^"
58 58 pick eb57da33312f 2 three
59 59 pick c8e68270e35a 3 four
60 60 pick 08d98a8350f3 4 five
61 61
62 62 # Edit history between eb57da33312f and 08d98a8350f3
63 63 #
64 64 # Commits are listed from least to most recent
65 65 #
66 66 # Commands:
67 67 # p, pick = use commit
68 68 # e, edit = use commit, but stop for amending
69 69 # f, fold = use commit, but combine it with the one above
70 70 # r, roll = like fold, but discard this commit's description
71 71 # d, drop = remove commit from history
72 72 # m, mess = edit commit message without changing commit content
73 73 #
74 74 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 75
76 76 Run on a revision not ancestors of the current working directory.
77 77 --------------------------------------------------------------------
78 78
79 79 $ hg up 2
80 80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 81 $ hg histedit -r 4
82 82 abort: 08d98a8350f3 is not an ancestor of working directory
83 83 [255]
84 84 $ hg up --quiet
85 85
86 86
87 87 Test that we pick the minimum of a revrange
88 88 ---------------------------------------
89 89
90 90 $ HGEDITOR=cat hg histedit '2::' --commands - << EOF
91 91 > pick eb57da33312f 2 three
92 92 > pick c8e68270e35a 3 four
93 93 > pick 08d98a8350f3 4 five
94 94 > EOF
95 95 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 96 $ hg up --quiet
97 97
98 98 $ HGEDITOR=cat hg histedit 'tip:2' --commands - << EOF
99 99 > pick eb57da33312f 2 three
100 100 > pick c8e68270e35a 3 four
101 101 > pick 08d98a8350f3 4 five
102 102 > EOF
103 103 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 104 $ hg up --quiet
105 105
106 106 Test config specified default
107 107 -----------------------------
108 108
109 109 $ HGEDITOR=cat hg histedit --config "histedit.defaultrev=only(.) - ::eb57da33312f" --commands - << EOF
110 110 > pick c8e68270e35a 3 four
111 111 > pick 08d98a8350f3 4 five
112 112 > EOF
113 113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 114
115 115 Run on a revision not descendants of the initial parent
116 116 --------------------------------------------------------------------
117 117
118 118 Test the message shown for inconsistent histedit state, which may be
119 119 created (and forgotten) by Mercurial earlier than 2.7. This emulates
120 120 Mercurial earlier than 2.7 by renaming ".hg/histedit-state"
121 121 temporarily.
122 122
123 123 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
124 124 @ 4 08d9 five
125 125 |
126 126 o 3 c8e6 four
127 127 |
128 128 o 2 eb57 three
129 129 |
130 130 $ HGEDITOR=cat hg histedit -r 4 --commands - << EOF
131 131 > edit 08d98a8350f3 4 five
132 132 > EOF
133 133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 134 reverting alpha
135 135 Make changes as needed, you may commit or record as needed now.
136 136 When you are finished, run hg histedit --continue to resume.
137 137 [1]
138 138
139 139 $ mv .hg/histedit-state .hg/histedit-state.back
140 140 $ hg update --quiet --clean 2
141 141 $ echo alpha >> alpha
142 142 $ mv .hg/histedit-state.back .hg/histedit-state
143 143
144 144 $ hg histedit --continue
145 145 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
146 146 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg (glob)
147 147 $ hg log -G -T '{rev} {shortest(node)} {desc}\n' -r 2::
148 148 @ 4 f5ed five
149 149 |
150 150 | o 3 c8e6 four
151 151 |/
152 152 o 2 eb57 three
153 153 |
154 154
155 155 $ hg unbundle -q $TESTTMP/foo/.hg/strip-backup/08d98a8350f3-02594089-backup.hg
156 156 $ hg strip -q -r f5ed --config extensions.strip=
157 157 $ hg up -q 08d98a8350f3
158 158
159 159 Test that missing revisions are detected
160 160 ---------------------------------------
161 161
162 162 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
163 163 > pick eb57da33312f 2 three
164 164 > pick 08d98a8350f3 4 five
165 165 > EOF
166 166 abort: missing rules for changeset c8e68270e35a
167 167 (do you want to use the drop action?)
168 168 [255]
169 169
170 170 Test that extra revisions are detected
171 171 ---------------------------------------
172 172
173 173 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
174 174 > pick 6058cbb6cfd7 0 one
175 175 > pick c8e68270e35a 3 four
176 176 > pick 08d98a8350f3 4 five
177 177 > EOF
178 178 abort: may not use changesets other than the ones listed
179 179 [255]
180 180
181 181 Test malformed line
182 182 ---------------------------------------
183 183
184 184 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
185 185 > pickeb57da33312f2three
186 186 > pick c8e68270e35a 3 four
187 187 > pick 08d98a8350f3 4 five
188 188 > EOF
189 189 abort: malformed line "pickeb57da33312f2three"
190 190 [255]
191 191
192 192 Test unknown changeset
193 193 ---------------------------------------
194 194
195 195 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
196 196 > pick 0123456789ab 2 three
197 197 > pick c8e68270e35a 3 four
198 198 > pick 08d98a8350f3 4 five
199 199 > EOF
200 200 abort: unknown changeset 0123456789ab listed
201 201 [255]
202 202
203 203 Test unknown command
204 204 ---------------------------------------
205 205
206 206 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
207 207 > coin eb57da33312f 2 three
208 208 > pick c8e68270e35a 3 four
209 209 > pick 08d98a8350f3 4 five
210 210 > EOF
211 211 abort: unknown action "coin"
212 212 [255]
213 213
214 214 Test duplicated changeset
215 215 ---------------------------------------
216 216
217 217 So one is missing and one appear twice.
218 218
219 219 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
220 220 > pick eb57da33312f 2 three
221 221 > pick eb57da33312f 2 three
222 222 > pick 08d98a8350f3 4 five
223 223 > EOF
224 224 abort: duplicated command for changeset eb57da33312f
225 225 [255]
226 226
227 227 Test short version of command
228 228 ---------------------------------------
229 229
230 230 Note: we use varying amounts of white space between command name and changeset
231 231 short hash. This tests issue3893.
232 232
233 233 $ HGEDITOR=cat hg histedit "tip^^" --commands - << EOF
234 234 > pick eb57da33312f 2 three
235 235 > p c8e68270e35a 3 four
236 236 > f 08d98a8350f3 4 five
237 237 > EOF
238 238 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 239 reverting alpha
240 240 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 241 four
242 242 ***
243 243 five
244 244
245 245
246 246
247 247 HG: Enter commit message. Lines beginning with 'HG:' are removed.
248 248 HG: Leave message empty to abort commit.
249 249 HG: --
250 250 HG: user: test
251 251 HG: branch 'default'
252 252 HG: changed alpha
253 253 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 254 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
255 255 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/*-backup.hg (glob)
256 saved backup bundle to $TESTTMP/foo/.hg/strip-backup/c8e68270e35a-23a13bf9-backup.hg (glob)
256 257
257 258 $ hg update -q 2
258 259 $ echo x > x
259 260 $ hg add x
260 261 $ hg commit -m'x' x
261 262 created new head
262 263 $ hg histedit -r 'heads(all())'
263 264 abort: The specified revisions must have exactly one common root
264 265 [255]
265 266
266 267 Test that trimming description using multi-byte characters
267 268 --------------------------------------------------------------------
268 269
269 270 $ python <<EOF
270 271 > fp = open('logfile', 'w')
271 272 > fp.write('12345678901234567890123456789012345678901234567890' +
272 273 > '12345') # there are 5 more columns for 80 columns
273 274 >
274 275 > # 2 x 4 = 8 columns, but 3 x 4 = 12 bytes
275 276 > fp.write(u'\u3042\u3044\u3046\u3048'.encode('utf-8'))
276 277 >
277 278 > fp.close()
278 279 > EOF
279 280 $ echo xx >> x
280 281 $ hg --encoding utf-8 commit --logfile logfile
281 282
282 283 $ HGEDITOR=cat hg --encoding utf-8 histedit tip
283 284 pick 3d3ea1f3a10b 5 1234567890123456789012345678901234567890123456789012345\xe3\x81\x82... (esc)
284 285
285 286 # Edit history between 3d3ea1f3a10b and 3d3ea1f3a10b
286 287 #
287 288 # Commits are listed from least to most recent
288 289 #
289 290 # Commands:
290 291 # p, pick = use commit
291 292 # e, edit = use commit, but stop for amending
292 293 # f, fold = use commit, but combine it with the one above
293 294 # r, roll = like fold, but discard this commit's description
294 295 # d, drop = remove commit from history
295 296 # m, mess = edit commit message without changing commit content
296 297 #
297 298 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 299
299 300 Test --continue with --keep
300 301
301 302 $ hg strip -q -r . --config extensions.strip=
302 303 $ hg histedit '.^' -q --keep --commands - << EOF
303 304 > edit eb57da33312f 2 three
304 305 > pick f3cfcca30c44 4 x
305 306 > EOF
306 307 Make changes as needed, you may commit or record as needed now.
307 308 When you are finished, run hg histedit --continue to resume.
308 309 [1]
309 310 $ echo edit >> alpha
310 311 $ hg histedit -q --continue
311 312 $ hg log -G -T '{rev}:{node|short} {desc}'
312 313 @ 6:8fda0c726bf2 x
313 314 |
314 315 o 5:63379946892c three
315 316 |
316 317 | o 4:f3cfcca30c44 x
317 318 | |
318 319 | | o 3:2a30f3cfee78 four
319 320 | |/ ***
320 321 | | five
321 322 | o 2:eb57da33312f three
322 323 |/
323 324 o 1:579e40513370 two
324 325 |
325 326 o 0:6058cbb6cfd7 one
326 327
327 328
328 329 Test that abort fails gracefully on exception
329 330 ----------------------------------------------
330 331 $ hg histedit . -q --commands - << EOF
331 332 > edit 8fda0c726bf2 6 x
332 333 > EOF
333 334 Make changes as needed, you may commit or record as needed now.
334 335 When you are finished, run hg histedit --continue to resume.
335 336 [1]
336 337 Corrupt histedit state file
337 338 $ sed 's/8fda0c726bf2/123456789012/' .hg/histedit-state > ../corrupt-histedit
338 339 $ mv ../corrupt-histedit .hg/histedit-state
339 340 $ hg histedit --abort
340 341 warning: encountered an exception during histedit --abort; the repository may not have been completely cleaned up
341 342 abort: No such file or directory: * (glob)
342 343 [255]
343 344 Histedit state has been exited
344 345 $ hg summary -q
345 346 parent: 5:63379946892c
346 347 commit: 1 added, 1 unknown (new branch head)
347 348 update: 4 new changesets (update)
348 349
@@ -1,182 +1,182 b''
1 1 $ . "$TESTDIR/histedit-helpers.sh"
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > histedit=
6 6 > EOF
7 7
8 8 $ hg init r
9 9 $ cd r
10 10
11 11 $ for x in a b c d e f ; do
12 12 > echo $x > $x
13 13 > hg add $x
14 14 > hg ci -m $x
15 15 > done
16 16
17 17 $ hg book -r 1 will-move-backwards
18 18 $ hg book -r 2 two
19 19 $ hg book -r 2 also-two
20 20 $ hg book -r 3 three
21 21 $ hg book -r 4 four
22 22 $ hg book -r tip five
23 23 $ hg log --graph
24 24 @ changeset: 5:652413bf663e
25 25 | bookmark: five
26 26 | tag: tip
27 27 | user: test
28 28 | date: Thu Jan 01 00:00:00 1970 +0000
29 29 | summary: f
30 30 |
31 31 o changeset: 4:e860deea161a
32 32 | bookmark: four
33 33 | user: test
34 34 | date: Thu Jan 01 00:00:00 1970 +0000
35 35 | summary: e
36 36 |
37 37 o changeset: 3:055a42cdd887
38 38 | bookmark: three
39 39 | user: test
40 40 | date: Thu Jan 01 00:00:00 1970 +0000
41 41 | summary: d
42 42 |
43 43 o changeset: 2:177f92b77385
44 44 | bookmark: also-two
45 45 | bookmark: two
46 46 | user: test
47 47 | date: Thu Jan 01 00:00:00 1970 +0000
48 48 | summary: c
49 49 |
50 50 o changeset: 1:d2ae7f538514
51 51 | bookmark: will-move-backwards
52 52 | user: test
53 53 | date: Thu Jan 01 00:00:00 1970 +0000
54 54 | summary: b
55 55 |
56 56 o changeset: 0:cb9a9f314b8b
57 57 user: test
58 58 date: Thu Jan 01 00:00:00 1970 +0000
59 59 summary: a
60 60
61 61 $ HGEDITOR=cat hg histedit 1
62 62 pick d2ae7f538514 1 b
63 63 pick 177f92b77385 2 c
64 64 pick 055a42cdd887 3 d
65 65 pick e860deea161a 4 e
66 66 pick 652413bf663e 5 f
67 67
68 68 # Edit history between d2ae7f538514 and 652413bf663e
69 69 #
70 70 # Commits are listed from least to most recent
71 71 #
72 72 # Commands:
73 73 # p, pick = use commit
74 74 # e, edit = use commit, but stop for amending
75 75 # f, fold = use commit, but combine it with the one above
76 76 # r, roll = like fold, but discard this commit's description
77 77 # d, drop = remove commit from history
78 78 # m, mess = edit commit message without changing commit content
79 79 #
80 80 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 81 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
82 82 > pick 177f92b77385 2 c
83 83 > drop d2ae7f538514 1 b
84 84 > pick 055a42cdd887 3 d
85 85 > fold e860deea161a 4 e
86 86 > pick 652413bf663e 5 f
87 87 > EOF
88 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
88 89 histedit: moving bookmarks also-two from 177f92b77385 to b346ab9a313d
89 90 histedit: moving bookmarks five from 652413bf663e to cacdfd884a93
90 91 histedit: moving bookmarks four from e860deea161a to 59d9f330561f
91 92 histedit: moving bookmarks three from 055a42cdd887 to 59d9f330561f
92 93 histedit: moving bookmarks two from 177f92b77385 to b346ab9a313d
93 94 histedit: moving bookmarks will-move-backwards from d2ae7f538514 to cb9a9f314b8b
94 95 saved backup bundle to $TESTTMP/r/.hg/strip-backup/d2ae7f538514-48787b8d-backup.hg (glob)
95 saved backup bundle to $TESTTMP/r/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
96 96 $ hg log --graph
97 97 @ changeset: 3:cacdfd884a93
98 98 | bookmark: five
99 99 | tag: tip
100 100 | user: test
101 101 | date: Thu Jan 01 00:00:00 1970 +0000
102 102 | summary: f
103 103 |
104 104 o changeset: 2:59d9f330561f
105 105 | bookmark: four
106 106 | bookmark: three
107 107 | user: test
108 108 | date: Thu Jan 01 00:00:00 1970 +0000
109 109 | summary: d
110 110 |
111 111 o changeset: 1:b346ab9a313d
112 112 | bookmark: also-two
113 113 | bookmark: two
114 114 | user: test
115 115 | date: Thu Jan 01 00:00:00 1970 +0000
116 116 | summary: c
117 117 |
118 118 o changeset: 0:cb9a9f314b8b
119 119 bookmark: will-move-backwards
120 120 user: test
121 121 date: Thu Jan 01 00:00:00 1970 +0000
122 122 summary: a
123 123
124 124 $ HGEDITOR=cat hg histedit 1
125 125 pick b346ab9a313d 1 c
126 126 pick 59d9f330561f 2 d
127 127 pick cacdfd884a93 3 f
128 128
129 129 # Edit history between b346ab9a313d and cacdfd884a93
130 130 #
131 131 # Commits are listed from least to most recent
132 132 #
133 133 # Commands:
134 134 # p, pick = use commit
135 135 # e, edit = use commit, but stop for amending
136 136 # f, fold = use commit, but combine it with the one above
137 137 # r, roll = like fold, but discard this commit's description
138 138 # d, drop = remove commit from history
139 139 # m, mess = edit commit message without changing commit content
140 140 #
141 141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 142 $ hg histedit 1 --commands - --verbose << EOF | grep histedit
143 143 > pick b346ab9a313d 1 c
144 144 > pick cacdfd884a93 3 f
145 145 > pick 59d9f330561f 2 d
146 146 > EOF
147 147 histedit: moving bookmarks five from cacdfd884a93 to c04e50810e4b
148 148 histedit: moving bookmarks four from 59d9f330561f to c04e50810e4b
149 149 histedit: moving bookmarks three from 59d9f330561f to c04e50810e4b
150 150 saved backup bundle to $TESTTMP/r/.hg/strip-backup/59d9f330561f-073008af-backup.hg (glob)
151 151
152 152 We expect 'five' to stay at tip, since the tipmost bookmark is most
153 153 likely the useful signal.
154 154
155 155 $ hg log --graph
156 156 @ changeset: 3:c04e50810e4b
157 157 | bookmark: five
158 158 | bookmark: four
159 159 | bookmark: three
160 160 | tag: tip
161 161 | user: test
162 162 | date: Thu Jan 01 00:00:00 1970 +0000
163 163 | summary: d
164 164 |
165 165 o changeset: 2:c13eb81022ca
166 166 | user: test
167 167 | date: Thu Jan 01 00:00:00 1970 +0000
168 168 | summary: f
169 169 |
170 170 o changeset: 1:b346ab9a313d
171 171 | bookmark: also-two
172 172 | bookmark: two
173 173 | user: test
174 174 | date: Thu Jan 01 00:00:00 1970 +0000
175 175 | summary: c
176 176 |
177 177 o changeset: 0:cb9a9f314b8b
178 178 bookmark: will-move-backwards
179 179 user: test
180 180 date: Thu Jan 01 00:00:00 1970 +0000
181 181 summary: a
182 182
@@ -1,459 +1,460 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 89 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 90 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 91
92 92 rules should end up in .hg/histedit-last-edit.txt:
93 93 $ cat .hg/histedit-last-edit.txt
94 94 pick 177f92b77385 c
95 95 pick e860deea161a e
96 96 pick 652413bf663e f
97 97 pick 055a42cdd887 d
98 98
99 99 log after edit
100 100 $ hg log --graph
101 101 @ changeset: 5:07114f51870f
102 102 | tag: tip
103 103 | user: test
104 104 | date: Thu Jan 01 00:00:00 1970 +0000
105 105 | summary: d
106 106 |
107 107 o changeset: 4:8ade9693061e
108 108 | user: test
109 109 | date: Thu Jan 01 00:00:00 1970 +0000
110 110 | summary: f
111 111 |
112 112 o changeset: 3:d8249471110a
113 113 | user: test
114 114 | date: Thu Jan 01 00:00:00 1970 +0000
115 115 | summary: e
116 116 |
117 117 o changeset: 2:177f92b77385
118 118 | user: test
119 119 | date: Thu Jan 01 00:00:00 1970 +0000
120 120 | summary: c
121 121 |
122 122 o changeset: 1:d2ae7f538514
123 123 | user: test
124 124 | date: Thu Jan 01 00:00:00 1970 +0000
125 125 | summary: b
126 126 |
127 127 o changeset: 0:cb9a9f314b8b
128 128 user: test
129 129 date: Thu Jan 01 00:00:00 1970 +0000
130 130 summary: a
131 131
132 132
133 133 put things back
134 134
135 135 $ hg histedit 177f92b77385 --commands - 2>&1 << EOF | fixbundle
136 136 > pick 177f92b77385 c
137 137 > pick 07114f51870f d
138 138 > pick d8249471110a e
139 139 > pick 8ade9693061e f
140 140 > EOF
141 141 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
142 142 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 143 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 144 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 145
146 146 $ hg log --graph
147 147 @ changeset: 5:7eca9b5b1148
148 148 | tag: tip
149 149 | user: test
150 150 | date: Thu Jan 01 00:00:00 1970 +0000
151 151 | summary: f
152 152 |
153 153 o changeset: 4:915da888f2de
154 154 | user: test
155 155 | date: Thu Jan 01 00:00:00 1970 +0000
156 156 | summary: e
157 157 |
158 158 o changeset: 3:10517e47bbbb
159 159 | user: test
160 160 | date: Thu Jan 01 00:00:00 1970 +0000
161 161 | summary: d
162 162 |
163 163 o changeset: 2:177f92b77385
164 164 | user: test
165 165 | date: Thu Jan 01 00:00:00 1970 +0000
166 166 | summary: c
167 167 |
168 168 o changeset: 1:d2ae7f538514
169 169 | user: test
170 170 | date: Thu Jan 01 00:00:00 1970 +0000
171 171 | summary: b
172 172 |
173 173 o changeset: 0:cb9a9f314b8b
174 174 user: test
175 175 date: Thu Jan 01 00:00:00 1970 +0000
176 176 summary: a
177 177
178 178
179 179 slightly different this time
180 180
181 181 $ hg histedit 177f92b77385 --commands - << EOF 2>&1 | fixbundle
182 182 > pick 10517e47bbbb d
183 183 > pick 7eca9b5b1148 f
184 184 > pick 915da888f2de e
185 185 > pick 177f92b77385 c
186 186 > EOF
187 187 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
188 188 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 190 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 191 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 192 $ hg log --graph
193 193 @ changeset: 5:38b92f448761
194 194 | tag: tip
195 195 | user: test
196 196 | date: Thu Jan 01 00:00:00 1970 +0000
197 197 | summary: c
198 198 |
199 199 o changeset: 4:de71b079d9ce
200 200 | user: test
201 201 | date: Thu Jan 01 00:00:00 1970 +0000
202 202 | summary: e
203 203 |
204 204 o changeset: 3:be9ae3a309c6
205 205 | user: test
206 206 | date: Thu Jan 01 00:00:00 1970 +0000
207 207 | summary: f
208 208 |
209 209 o changeset: 2:799205341b6b
210 210 | user: test
211 211 | date: Thu Jan 01 00:00:00 1970 +0000
212 212 | summary: d
213 213 |
214 214 o changeset: 1:d2ae7f538514
215 215 | user: test
216 216 | date: Thu Jan 01 00:00:00 1970 +0000
217 217 | summary: b
218 218 |
219 219 o changeset: 0:cb9a9f314b8b
220 220 user: test
221 221 date: Thu Jan 01 00:00:00 1970 +0000
222 222 summary: a
223 223
224 224
225 225 keep prevents stripping dead revs
226 226 $ hg histedit 799205341b6b --keep --commands - 2>&1 << EOF | fixbundle
227 227 > pick 799205341b6b d
228 228 > pick be9ae3a309c6 f
229 229 > pick 38b92f448761 c
230 230 > pick de71b079d9ce e
231 231 > EOF
232 232 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
233 233 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
234 234 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 235 $ hg log --graph
236 236 @ changeset: 7:803ef1c6fcfd
237 237 | tag: tip
238 238 | user: test
239 239 | date: Thu Jan 01 00:00:00 1970 +0000
240 240 | summary: e
241 241 |
242 242 o changeset: 6:ece0b8d93dda
243 243 | parent: 3:be9ae3a309c6
244 244 | user: test
245 245 | date: Thu Jan 01 00:00:00 1970 +0000
246 246 | summary: c
247 247 |
248 248 | o changeset: 5:38b92f448761
249 249 | | user: test
250 250 | | date: Thu Jan 01 00:00:00 1970 +0000
251 251 | | summary: c
252 252 | |
253 253 | o changeset: 4:de71b079d9ce
254 254 |/ user: test
255 255 | date: Thu Jan 01 00:00:00 1970 +0000
256 256 | summary: e
257 257 |
258 258 o changeset: 3:be9ae3a309c6
259 259 | user: test
260 260 | date: Thu Jan 01 00:00:00 1970 +0000
261 261 | summary: f
262 262 |
263 263 o changeset: 2:799205341b6b
264 264 | user: test
265 265 | date: Thu Jan 01 00:00:00 1970 +0000
266 266 | summary: d
267 267 |
268 268 o changeset: 1:d2ae7f538514
269 269 | user: test
270 270 | date: Thu Jan 01 00:00:00 1970 +0000
271 271 | summary: b
272 272 |
273 273 o changeset: 0:cb9a9f314b8b
274 274 user: test
275 275 date: Thu Jan 01 00:00:00 1970 +0000
276 276 summary: a
277 277
278 278
279 279 try with --rev
280 280 $ hg histedit --commands - --rev -2 2>&1 <<EOF | fixbundle
281 281 > pick de71b079d9ce e
282 282 > pick 38b92f448761 c
283 283 > EOF
284 284 abort: may not use changesets other than the ones listed
285 285 $ hg log --graph
286 286 @ changeset: 7:803ef1c6fcfd
287 287 | tag: tip
288 288 | user: test
289 289 | date: Thu Jan 01 00:00:00 1970 +0000
290 290 | summary: e
291 291 |
292 292 o changeset: 6:ece0b8d93dda
293 293 | parent: 3:be9ae3a309c6
294 294 | user: test
295 295 | date: Thu Jan 01 00:00:00 1970 +0000
296 296 | summary: c
297 297 |
298 298 | o changeset: 5:38b92f448761
299 299 | | user: test
300 300 | | date: Thu Jan 01 00:00:00 1970 +0000
301 301 | | summary: c
302 302 | |
303 303 | o changeset: 4:de71b079d9ce
304 304 |/ user: test
305 305 | date: Thu Jan 01 00:00:00 1970 +0000
306 306 | summary: e
307 307 |
308 308 o changeset: 3:be9ae3a309c6
309 309 | user: test
310 310 | date: Thu Jan 01 00:00:00 1970 +0000
311 311 | summary: f
312 312 |
313 313 o changeset: 2:799205341b6b
314 314 | user: test
315 315 | date: Thu Jan 01 00:00:00 1970 +0000
316 316 | summary: d
317 317 |
318 318 o changeset: 1:d2ae7f538514
319 319 | user: test
320 320 | date: Thu Jan 01 00:00:00 1970 +0000
321 321 | summary: b
322 322 |
323 323 o changeset: 0:cb9a9f314b8b
324 324 user: test
325 325 date: Thu Jan 01 00:00:00 1970 +0000
326 326 summary: a
327 327
328 328 Verify that revsetalias entries work with histedit:
329 329 $ cat >> $HGRCPATH <<EOF
330 330 > [revsetalias]
331 331 > grandparent(ARG) = p1(p1(ARG))
332 332 > EOF
333 333 $ echo extra commit >> c
334 334 $ hg ci -m 'extra commit to c'
335 335 $ HGEDITOR=cat hg histedit 'grandparent(.)'
336 336 pick ece0b8d93dda 6 c
337 337 pick 803ef1c6fcfd 7 e
338 338 pick 9c863c565126 8 extra commit to c
339 339
340 340 # Edit history between ece0b8d93dda and 9c863c565126
341 341 #
342 342 # Commits are listed from least to most recent
343 343 #
344 344 # Commands:
345 345 # p, pick = use commit
346 346 # e, edit = use commit, but stop for amending
347 347 # f, fold = use commit, but combine it with the one above
348 348 # r, roll = like fold, but discard this commit's description
349 349 # d, drop = remove commit from history
350 350 # m, mess = edit commit message without changing commit content
351 351 #
352 352 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 353
354 354 should also work if a commit message is missing
355 355 $ BUNDLE="$TESTDIR/missing-comment.hg"
356 356 $ hg init missing
357 357 $ cd missing
358 358 $ hg unbundle $BUNDLE
359 359 adding changesets
360 360 adding manifests
361 361 adding file changes
362 362 added 3 changesets with 3 changes to 1 files
363 363 (run 'hg update' to get a working copy)
364 364 $ hg co tip
365 365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 366 $ hg log --graph
367 367 @ changeset: 2:bd22688093b3
368 368 | tag: tip
369 369 | user: Robert Altman <robert.altman@telventDTN.com>
370 370 | date: Mon Nov 28 16:40:04 2011 +0000
371 371 | summary: Update file.
372 372 |
373 373 o changeset: 1:3b3e956f9171
374 374 | user: Robert Altman <robert.altman@telventDTN.com>
375 375 | date: Mon Nov 28 16:37:57 2011 +0000
376 376 |
377 377 o changeset: 0:141947992243
378 378 user: Robert Altman <robert.altman@telventDTN.com>
379 379 date: Mon Nov 28 16:35:28 2011 +0000
380 380 summary: Checked in text file
381 381
382 382 $ hg histedit 0
383 383 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 384 $ cd ..
385 385
386 386 $ cd ..
387 387
388 388
389 389 Test to make sure folding renames doesn't cause bogus conflicts (issue4251):
390 390 $ hg init issue4251
391 391 $ cd issue4251
392 392
393 393 $ mkdir initial-dir
394 394 $ echo foo > initial-dir/initial-file
395 395 $ hg add initial-dir/initial-file
396 396 $ hg commit -m "initial commit"
397 397
398 398 Move the file to a new directory, and in the same commit, change its content:
399 399 $ mkdir another-dir
400 400 $ hg mv initial-dir/initial-file another-dir/
401 401 $ echo changed > another-dir/initial-file
402 402 $ hg commit -m "moved and changed"
403 403
404 404 Rename the file:
405 405 $ hg mv another-dir/initial-file another-dir/renamed-file
406 406 $ hg commit -m "renamed"
407 407
408 408 Now, let's try to fold the second commit into the first:
409 409 $ cat > editor.sh <<EOF
410 410 > #!/bin/sh
411 411 > cat > \$1 <<ENDOF
412 412 > pick b0f4233702ca 0 initial commit
413 413 > fold 5e8704a8f2d2 1 moved and changed
414 414 > pick 40e7299e8fa7 2 renamed
415 415 > ENDOF
416 416 > EOF
417 417
418 418 $ HGEDITOR="sh ./editor.sh" hg histedit 0
419 419 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 420 adding another-dir/initial-file (glob)
421 421 removing initial-dir/initial-file (glob)
422 422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
423 423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 424 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 426 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/*-backup.hg (glob)
427 saved backup bundle to $TESTTMP/issue4251/.hg/strip-backup/b0f4233702ca-d99e7186-backup.hg (glob)
427 428
428 429 $ hg --config diff.git=yes export 0
429 430 # HG changeset patch
430 431 # User test
431 432 # Date 0 0
432 433 # Thu Jan 01 00:00:00 1970 +0000
433 434 # Node ID fffadc26f8f85623ce60b028a3f1ccc3730f8530
434 435 # Parent 0000000000000000000000000000000000000000
435 436 pick b0f4233702ca 0 initial commit
436 437 fold 5e8704a8f2d2 1 moved and changed
437 438 pick 40e7299e8fa7 2 renamed
438 439
439 440 diff --git a/another-dir/initial-file b/another-dir/initial-file
440 441 new file mode 100644
441 442 --- /dev/null
442 443 +++ b/another-dir/initial-file
443 444 @@ -0,0 +1,1 @@
444 445 +changed
445 446
446 447 $ hg --config diff.git=yes export 1
447 448 # HG changeset patch
448 449 # User test
449 450 # Date 0 0
450 451 # Thu Jan 01 00:00:00 1970 +0000
451 452 # Node ID 9b730d82b00af8a2766facebfa47cc124405a118
452 453 # Parent fffadc26f8f85623ce60b028a3f1ccc3730f8530
453 454 renamed
454 455
455 456 diff --git a/another-dir/initial-file b/another-dir/renamed-file
456 457 rename from another-dir/initial-file
457 458 rename to another-dir/renamed-file
458 459
459 460 $ cd ..
@@ -1,570 +1,571 b''
1 1 Test histedit extension: Fold commands
2 2 ======================================
3 3
4 4 This test file is dedicated to testing the fold command in non conflicting
5 5 case.
6 6
7 7 Initialization
8 8 ---------------
9 9
10 10
11 11 $ . "$TESTDIR/histedit-helpers.sh"
12 12
13 13 $ cat >> $HGRCPATH <<EOF
14 14 > [alias]
15 15 > logt = log --template '{rev}:{node|short} {desc|firstline}\n'
16 16 > [extensions]
17 17 > histedit=
18 18 > EOF
19 19
20 20
21 21 Simple folding
22 22 --------------------
23 23 $ initrepo ()
24 24 > {
25 25 > hg init r
26 26 > cd r
27 27 > for x in a b c d e f ; do
28 28 > echo $x > $x
29 29 > hg add $x
30 30 > hg ci -m $x
31 31 > done
32 32 > }
33 33
34 34 $ initrepo
35 35
36 36 log before edit
37 37 $ hg logt --graph
38 38 @ 5:652413bf663e f
39 39 |
40 40 o 4:e860deea161a e
41 41 |
42 42 o 3:055a42cdd887 d
43 43 |
44 44 o 2:177f92b77385 c
45 45 |
46 46 o 1:d2ae7f538514 b
47 47 |
48 48 o 0:cb9a9f314b8b a
49 49
50 50
51 51 $ hg histedit 177f92b77385 --commands - 2>&1 <<EOF | fixbundle
52 52 > pick e860deea161a e
53 53 > pick 652413bf663e f
54 54 > fold 177f92b77385 c
55 55 > pick 055a42cdd887 d
56 56 > EOF
57 57 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
58 58 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 59 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 60 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
61 61 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 62 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 63 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
64 64
65 65 log after edit
66 66 $ hg logt --graph
67 67 @ 4:9c277da72c9b d
68 68 |
69 69 o 3:6de59d13424a f
70 70 |
71 71 o 2:ee283cb5f2d5 e
72 72 |
73 73 o 1:d2ae7f538514 b
74 74 |
75 75 o 0:cb9a9f314b8b a
76 76
77 77
78 78 post-fold manifest
79 79 $ hg manifest
80 80 a
81 81 b
82 82 c
83 83 d
84 84 e
85 85 f
86 86
87 87
88 88 check histedit_source
89 89
90 90 $ hg log --debug --rev 3
91 91 changeset: 3:6de59d13424a8a13acd3e975514aed29dd0d9b2d
92 92 phase: draft
93 93 parent: 2:ee283cb5f2d5955443f23a27b697a04339e9a39a
94 94 parent: -1:0000000000000000000000000000000000000000
95 95 manifest: 3:81eede616954057198ead0b2c73b41d1f392829a
96 96 user: test
97 97 date: Thu Jan 01 00:00:00 1970 +0000
98 98 files+: c f
99 99 extra: branch=default
100 100 extra: histedit_source=a4f7421b80f79fcc59fff01bcbf4a53d127dd6d3,177f92b773850b59254aa5e923436f921b55483b
101 101 description:
102 102 f
103 103 ***
104 104 c
105 105
106 106
107 107
108 108 rollup will fold without preserving the folded commit's message
109 109
110 110 $ OLDHGEDITOR=$HGEDITOR
111 111 $ HGEDITOR=false
112 112 $ hg histedit d2ae7f538514 --commands - 2>&1 <<EOF | fixbundle
113 113 > pick d2ae7f538514 b
114 114 > roll ee283cb5f2d5 e
115 115 > pick 6de59d13424a f
116 116 > pick 9c277da72c9b d
117 117 > EOF
118 118 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
119 119 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
120 120 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 121 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 122 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 123 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 124
125 125 $ HGEDITOR=$OLDHGEDITOR
126 126
127 127 log after edit
128 128 $ hg logt --graph
129 129 @ 3:c4a9eb7989fc d
130 130 |
131 131 o 2:8e03a72b6f83 f
132 132 |
133 133 o 1:391ee782c689 b
134 134 |
135 135 o 0:cb9a9f314b8b a
136 136
137 137
138 138 description is taken from rollup target commit
139 139
140 140 $ hg log --debug --rev 1
141 141 changeset: 1:391ee782c68930be438ccf4c6a403daedbfbffa5
142 142 phase: draft
143 143 parent: 0:cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
144 144 parent: -1:0000000000000000000000000000000000000000
145 145 manifest: 1:b5e112a3a8354e269b1524729f0918662d847c38
146 146 user: test
147 147 date: Thu Jan 01 00:00:00 1970 +0000
148 148 files+: b e
149 149 extra: branch=default
150 150 extra: histedit_source=d2ae7f538514cd87c17547b0de4cea71fe1af9fb,ee283cb5f2d5955443f23a27b697a04339e9a39a
151 151 description:
152 152 b
153 153
154 154
155 155
156 156 check saving last-message.txt
157 157
158 158 $ cat > $TESTTMP/abortfolding.py <<EOF
159 159 > from mercurial import util
160 160 > def abortfolding(ui, repo, hooktype, **kwargs):
161 161 > ctx = repo[kwargs.get('node')]
162 162 > if set(ctx.files()) == set(['c', 'd', 'f']):
163 163 > return True # abort folding commit only
164 164 > ui.warn('allow non-folding commit\\n')
165 165 > EOF
166 166 $ cat > .hg/hgrc <<EOF
167 167 > [hooks]
168 168 > pretxncommit.abortfolding = python:$TESTTMP/abortfolding.py:abortfolding
169 169 > EOF
170 170
171 171 $ cat > $TESTTMP/editor.sh << EOF
172 172 > echo "==== before editing"
173 173 > cat \$1
174 174 > echo "===="
175 175 > echo "check saving last-message.txt" >> \$1
176 176 > EOF
177 177
178 178 $ rm -f .hg/last-message.txt
179 179 $ hg status --rev '8e03a72b6f83^1::c4a9eb7989fc'
180 180 A c
181 181 A d
182 182 A f
183 183 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 8e03a72b6f83 --commands - 2>&1 <<EOF
184 184 > pick 8e03a72b6f83 f
185 185 > fold c4a9eb7989fc d
186 186 > EOF
187 187 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
188 188 adding d
189 189 allow non-folding commit
190 190 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
191 191 ==== before editing
192 192 f
193 193 ***
194 194 c
195 195 ***
196 196 d
197 197
198 198
199 199
200 200 HG: Enter commit message. Lines beginning with 'HG:' are removed.
201 201 HG: Leave message empty to abort commit.
202 202 HG: --
203 203 HG: user: test
204 204 HG: branch 'default'
205 205 HG: added c
206 206 HG: added d
207 207 HG: added f
208 208 ====
209 209 transaction abort!
210 210 rollback completed
211 211 abort: pretxncommit.abortfolding hook failed
212 212 [255]
213 213
214 214 $ cat .hg/last-message.txt
215 215 f
216 216 ***
217 217 c
218 218 ***
219 219 d
220 220
221 221
222 222
223 223 check saving last-message.txt
224 224
225 225 $ cd ..
226 226 $ rm -r r
227 227
228 228 folding preserves initial author
229 229 --------------------------------
230 230
231 231 $ initrepo
232 232
233 233 $ hg ci --user "someone else" --amend --quiet
234 234
235 235 tip before edit
236 236 $ hg log --rev .
237 237 changeset: 5:a00ad806cb55
238 238 tag: tip
239 239 user: someone else
240 240 date: Thu Jan 01 00:00:00 1970 +0000
241 241 summary: f
242 242
243 243
244 244 $ hg histedit e860deea161a --commands - 2>&1 <<EOF | fixbundle
245 245 > pick e860deea161a e
246 246 > fold a00ad806cb55 f
247 247 > EOF
248 248 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
249 249 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
250 250 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 251 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 252
253 253 tip after edit
254 254 $ hg log --rev .
255 255 changeset: 4:698d4e8040a1
256 256 tag: tip
257 257 user: test
258 258 date: Thu Jan 01 00:00:00 1970 +0000
259 259 summary: e
260 260
261 261
262 262 $ cd ..
263 263 $ rm -r r
264 264
265 265 folding and creating no new change doesn't break:
266 266 -------------------------------------------------
267 267
268 268 folded content is dropped during a merge. The folded commit should properly disappear.
269 269
270 270 $ mkdir fold-to-empty-test
271 271 $ cd fold-to-empty-test
272 272 $ hg init
273 273 $ printf "1\n2\n3\n" > file
274 274 $ hg add file
275 275 $ hg commit -m '1+2+3'
276 276 $ echo 4 >> file
277 277 $ hg commit -m '+4'
278 278 $ echo 5 >> file
279 279 $ hg commit -m '+5'
280 280 $ echo 6 >> file
281 281 $ hg commit -m '+6'
282 282 $ hg logt --graph
283 283 @ 3:251d831eeec5 +6
284 284 |
285 285 o 2:888f9082bf99 +5
286 286 |
287 287 o 1:617f94f13c0f +4
288 288 |
289 289 o 0:0189ba417d34 1+2+3
290 290
291 291
292 292 $ hg histedit 1 --commands - << EOF
293 293 > pick 617f94f13c0f 1 +4
294 294 > drop 888f9082bf99 2 +5
295 295 > fold 251d831eeec5 3 +6
296 296 > EOF
297 297 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 298 merging file
299 299 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
300 300 Fix up the change and run hg histedit --continue
301 301 [1]
302 302 There were conflicts, we keep P1 content. This
303 303 should effectively drop the changes from +6.
304 304 $ hg status
305 305 M file
306 306 ? file.orig
307 307 $ hg resolve -l
308 308 U file
309 309 $ hg revert -r 'p1()' file
310 310 $ hg resolve --mark file
311 311 (no more unresolved files)
312 312 $ hg histedit --continue
313 313 251d831eeec5: empty changeset
314 314 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 315 saved backup bundle to $TESTTMP/*-backup.hg (glob)
316 316 $ hg logt --graph
317 317 @ 1:617f94f13c0f +4
318 318 |
319 319 o 0:0189ba417d34 1+2+3
320 320
321 321
322 322 $ cd ..
323 323
324 324
325 325 Test fold through dropped
326 326 -------------------------
327 327
328 328
329 329 Test corner case where folded revision is separated from its parent by a
330 330 dropped revision.
331 331
332 332
333 333 $ hg init fold-with-dropped
334 334 $ cd fold-with-dropped
335 335 $ printf "1\n2\n3\n" > file
336 336 $ hg commit -Am '1+2+3'
337 337 adding file
338 338 $ echo 4 >> file
339 339 $ hg commit -m '+4'
340 340 $ echo 5 >> file
341 341 $ hg commit -m '+5'
342 342 $ echo 6 >> file
343 343 $ hg commit -m '+6'
344 344 $ hg logt -G
345 345 @ 3:251d831eeec5 +6
346 346 |
347 347 o 2:888f9082bf99 +5
348 348 |
349 349 o 1:617f94f13c0f +4
350 350 |
351 351 o 0:0189ba417d34 1+2+3
352 352
353 353 $ hg histedit 1 --commands - << EOF
354 354 > pick 617f94f13c0f 1 +4
355 355 > drop 888f9082bf99 2 +5
356 356 > fold 251d831eeec5 3 +6
357 357 > EOF
358 358 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
359 359 merging file
360 360 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
361 361 Fix up the change and run hg histedit --continue
362 362 [1]
363 363 $ cat > file << EOF
364 364 > 1
365 365 > 2
366 366 > 3
367 367 > 4
368 368 > 5
369 369 > EOF
370 370 $ hg resolve --mark file
371 371 (no more unresolved files)
372 372 $ hg commit -m '+5.2'
373 373 created new head
374 374 $ echo 6 >> file
375 375 $ HGEDITOR=cat hg histedit --continue
376 376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 377 +4
378 378 ***
379 379 +5.2
380 380 ***
381 381 +6
382 382
383 383
384 384
385 385 HG: Enter commit message. Lines beginning with 'HG:' are removed.
386 386 HG: Leave message empty to abort commit.
387 387 HG: --
388 388 HG: user: test
389 389 HG: branch 'default'
390 390 HG: changed file
391 391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 392 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
393 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/617f94f13c0f-3d69522c-backup.hg (glob)
393 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/55c8d8dc79ce-4066cd98-backup.hg (glob)
394 saved backup bundle to $TESTTMP/fold-with-dropped/.hg/strip-backup/617f94f13c0f-a35700fc-backup.hg (glob)
394 395 $ hg logt -G
395 396 @ 1:10c647b2cdd5 +4
396 397 |
397 398 o 0:0189ba417d34 1+2+3
398 399
399 400 $ hg export tip
400 401 # HG changeset patch
401 402 # User test
402 403 # Date 0 0
403 404 # Thu Jan 01 00:00:00 1970 +0000
404 405 # Node ID 10c647b2cdd54db0603ecb99b2ff5ce66d5a5323
405 406 # Parent 0189ba417d34df9dda55f88b637dcae9917b5964
406 407 +4
407 408 ***
408 409 +5.2
409 410 ***
410 411 +6
411 412
412 413 diff -r 0189ba417d34 -r 10c647b2cdd5 file
413 414 --- a/file Thu Jan 01 00:00:00 1970 +0000
414 415 +++ b/file Thu Jan 01 00:00:00 1970 +0000
415 416 @@ -1,3 +1,6 @@
416 417 1
417 418 2
418 419 3
419 420 +4
420 421 +5
421 422 +6
422 423 $ cd ..
423 424
424 425
425 426 Folding with initial rename (issue3729)
426 427 ---------------------------------------
427 428
428 429 $ hg init fold-rename
429 430 $ cd fold-rename
430 431 $ echo a > a.txt
431 432 $ hg add a.txt
432 433 $ hg commit -m a
433 434 $ hg rename a.txt b.txt
434 435 $ hg commit -m rename
435 436 $ echo b >> b.txt
436 437 $ hg commit -m b
437 438
438 439 $ hg logt --follow b.txt
439 440 2:e0371e0426bc b
440 441 1:1c4f440a8085 rename
441 442 0:6c795aa153cb a
442 443
443 444 $ hg histedit 1c4f440a8085 --commands - 2>&1 << EOF | fixbundle
444 445 > pick 1c4f440a8085 rename
445 446 > fold e0371e0426bc b
446 447 > EOF
447 448 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
448 449 reverting b.txt
449 450 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
450 451 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
451 452 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 453
453 454 $ hg logt --follow b.txt
454 455 1:cf858d235c76 rename
455 456 0:6c795aa153cb a
456 457
457 458 $ cd ..
458 459
459 460 Folding with swapping
460 461 ---------------------
461 462
462 463 This is an excuse to test hook with histedit temporary commit (issue4422)
463 464
464 465
465 466 $ hg init issue4422
466 467 $ cd issue4422
467 468 $ echo a > a.txt
468 469 $ hg add a.txt
469 470 $ hg commit -m a
470 471 $ echo b > b.txt
471 472 $ hg add b.txt
472 473 $ hg commit -m b
473 474 $ echo c > c.txt
474 475 $ hg add c.txt
475 476 $ hg commit -m c
476 477
477 478 $ hg logt
478 479 2:a1a953ffb4b0 c
479 480 1:199b6bb90248 b
480 481 0:6c795aa153cb a
481 482
482 483 Setup the proper environment variable symbol for the platform, to be subbed
483 484 into the hook command.
484 485 #if windows
485 486 $ NODE="%HG_NODE%"
486 487 #else
487 488 $ NODE="\$HG_NODE"
488 489 #endif
489 490 $ hg histedit 6c795aa153cb --config hooks.commit="echo commit $NODE" --commands - 2>&1 << EOF | fixbundle
490 491 > pick 199b6bb90248 b
491 492 > fold a1a953ffb4b0 c
492 493 > pick 6c795aa153cb a
493 494 > EOF
494 495 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
495 496 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
496 497 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
497 498 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
498 499 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 500 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
500 501 commit 9599899f62c05f4377548c32bf1c9f1a39634b0c
501 502
502 503 $ hg logt
503 504 1:9599899f62c0 a
504 505 0:79b99e9c8e49 b
505 506
506 507 $ echo "foo" > amended.txt
507 508 $ hg add amended.txt
508 509 $ hg ci -q --config extensions.largefiles= --amend -I amended.txt
509 510
510 511 Test that folding multiple changes in a row doesn't show multiple
511 512 editors.
512 513
513 514 $ echo foo >> foo
514 515 $ hg add foo
515 516 $ hg ci -m foo1
516 517 $ echo foo >> foo
517 518 $ hg ci -m foo2
518 519 $ echo foo >> foo
519 520 $ hg ci -m foo3
520 521 $ hg logt
521 522 4:21679ff7675c foo3
522 523 3:b7389cc4d66e foo2
523 524 2:0e01aeef5fa8 foo1
524 525 1:578c7455730c a
525 526 0:79b99e9c8e49 b
526 527 $ cat > $TESTTMP/editor.sh <<EOF
527 528 > echo ran editor >> $TESTTMP/editorlog.txt
528 529 > cat \$1 >> $TESTTMP/editorlog.txt
529 530 > echo END >> $TESTTMP/editorlog.txt
530 531 > echo merged foos > \$1
531 532 > EOF
532 533 $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 1 --commands - 2>&1 <<EOF | fixbundle
533 534 > pick 578c7455730c 1 a
534 535 > pick 0e01aeef5fa8 2 foo1
535 536 > fold b7389cc4d66e 3 foo2
536 537 > fold 21679ff7675c 4 foo3
537 538 > EOF
538 539 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
539 540 reverting foo
540 541 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
541 542 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
542 543 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
543 544 merging foo
544 545 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
545 546 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
546 547 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
547 548 $ hg logt
548 549 2:e8bedbda72c1 merged foos
549 550 1:578c7455730c a
550 551 0:79b99e9c8e49 b
551 552 Editor should have run only once
552 553 $ cat $TESTTMP/editorlog.txt
553 554 ran editor
554 555 foo1
555 556 ***
556 557 foo2
557 558 ***
558 559 foo3
559 560
560 561
561 562
562 563 HG: Enter commit message. Lines beginning with 'HG:' are removed.
563 564 HG: Leave message empty to abort commit.
564 565 HG: --
565 566 HG: user: test
566 567 HG: branch 'default'
567 568 HG: added foo
568 569 END
569 570
570 571 $ cd ..
@@ -1,460 +1,463 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 saved backup bundle to $TESTTMP/base/.hg/strip-backup/96e494a2d553-3c6c5d92-backup.hg (glob)
67 [1]
68 68 $ hg log --graph --hidden
69 @ 8:cacdfd884a93 f
69 @ 10:cacdfd884a93 f
70 |
71 o 9:59d9f330561f d
70 72 |
71 o 7:59d9f330561f d
72 |
73 | x 8:b558abc46d09 fold-temp-revision e860deea161a
74 | |
75 | x 7:96e494a2d553 d
76 |/
73 77 o 6:b346ab9a313d c
74 78 |
75 79 | x 5:652413bf663e f
76 80 | |
77 81 | x 4:e860deea161a e
78 82 | |
79 83 | x 3:055a42cdd887 d
80 84 | |
81 85 | x 2:177f92b77385 c
82 86 | |
83 87 | x 1:d2ae7f538514 b
84 88 |/
85 89 o 0:cb9a9f314b8b a
86 90
87 91 $ hg debugobsolete
92 96e494a2d553dd05902ba1cee1d94d4cb7b8faed 0 {b346ab9a313db8537ecf96fca3ca3ca984ef3bd7} (*) {'user': 'test'} (glob)
93 b558abc46d09c30f57ac31e85a8a3d64d2e906e4 0 {96e494a2d553dd05902ba1cee1d94d4cb7b8faed} (*) {'user': 'test'} (glob)
88 94 d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob)
89 95 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob)
90 96 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
91 97 e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob)
92 98 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob)
93 99
94 100
95 101 Ensure hidden revision does not prevent histedit
96 102 -------------------------------------------------
97 103
98 104 create an hidden revision
99 105
100 106 $ hg histedit 6 --commands - << EOF
101 107 > pick b346ab9a313d 6 c
102 108 > drop 59d9f330561f 7 d
103 109 > pick cacdfd884a93 8 f
104 110 > EOF
105 111 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
106 112 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 113 $ hg log --graph
108 @ 9:c13eb81022ca f
114 @ 11:c13eb81022ca f
109 115 |
110 116 o 6:b346ab9a313d c
111 117 |
112 118 o 0:cb9a9f314b8b a
113 119
114 120 check hidden revision are ignored (6 have hidden children 7 and 8)
115 121
116 122 $ hg histedit 6 --commands - << EOF
117 123 > pick b346ab9a313d 6 c
118 124 > pick c13eb81022ca 8 f
119 125 > EOF
120 126 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 127
122 128
123 129
124 130 Test that rewriting leaving instability behind is allowed
125 131 ---------------------------------------------------------------------
126 132
127 133 $ hg up '.^'
128 134 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
129 135 $ hg log -r 'children(.)'
130 9:c13eb81022ca f (no-eol)
136 11:c13eb81022ca f (no-eol)
131 137 $ hg histedit -r '.' --commands - <<EOF
132 138 > edit b346ab9a313d 6 c
133 139 > EOF
134 140 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
135 141 adding c
136 142 Make changes as needed, you may commit or record as needed now.
137 143 When you are finished, run hg histedit --continue to resume.
138 144 [1]
139 145 $ echo c >> c
140 146 $ hg histedit --continue
141 147 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 148
143 149 $ hg log -r 'unstable()'
144 9:c13eb81022ca f (no-eol)
150 11:c13eb81022ca f (no-eol)
145 151
146 152 stabilise
147 153
148 154 $ hg rebase -r 'unstable()' -d .
149 rebasing 9:c13eb81022ca "f"
155 rebasing 11:c13eb81022ca "f"
150 156 $ hg up tip -q
151 157
152 158 Test dropping of changeset on the top of the stack
153 159 -------------------------------------------------------
154 160
155 161 Nothing is rewritten below, the working directory parent must be change for the
156 162 dropped changeset to be hidden.
157 163
158 164 $ cd ..
159 165 $ hg clone base droplast
160 166 updating to branch default
161 167 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 168 $ cd droplast
163 169 $ hg histedit -r '40db8afa467b' --commands - << EOF
164 170 > pick 40db8afa467b 10 c
165 171 > drop b449568bf7fc 11 f
166 172 > EOF
167 173 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
168 174 $ hg log -G
169 @ 10:40db8afa467b c
175 @ 12:40db8afa467b c
170 176 |
171 177 o 0:cb9a9f314b8b a
172 178
173 179
174 180 With rewritten ancestors
175 181
176 182 $ echo e > e
177 183 $ hg add e
178 184 $ hg commit -m g
179 185 $ echo f > f
180 186 $ hg add f
181 187 $ hg commit -m h
182 188 $ hg histedit -r '40db8afa467b' --commands - << EOF
183 189 > pick 47a8561c0449 12 g
184 190 > pick 40db8afa467b 10 c
185 191 > drop 1b3b05f35ff0 13 h
186 192 > EOF
187 193 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
188 194 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 195 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 196 $ hg log -G
191 @ 15:ee6544123ab8 c
197 @ 17:ee6544123ab8 c
192 198 |
193 o 14:269e713e9eae g
199 o 16:269e713e9eae g
194 200 |
195 201 o 0:cb9a9f314b8b a
196 202
197 203 $ cd ../base
198 204
199 205
200 206
201 207 Test phases support
202 208 ===========================================
203 209
204 210 Check that histedit respect immutability
205 211 -------------------------------------------
206 212
207 213 $ cat >> $HGRCPATH << EOF
208 214 > [ui]
209 215 > logtemplate= {rev}:{node|short} ({phase}) {desc|firstline}\n
210 216 > EOF
211 217
212 218 $ hg ph -pv '.^'
213 219 phase changed for 2 changesets
214 220 $ hg log -G
215 @ 11:b449568bf7fc (draft) f
221 @ 13:b449568bf7fc (draft) f
216 222 |
217 o 10:40db8afa467b (public) c
223 o 12:40db8afa467b (public) c
218 224 |
219 225 o 0:cb9a9f314b8b (public) a
220 226
221 227 $ hg histedit -r '.~2'
222 228 abort: cannot edit public changeset: cb9a9f314b8b
223 229 (see "hg help phases" for details)
224 230 [255]
225 231
226 232
227 233 Prepare further testing
228 234 -------------------------------------------
229 235
230 236 $ for x in g h i j k ; do
231 237 > echo $x > $x
232 238 > hg add $x
233 239 > hg ci -m $x
234 240 > done
235 241 $ hg phase --force --secret .~2
236 242 $ hg log -G
237 @ 16:ee118ab9fa44 (secret) k
243 @ 18:ee118ab9fa44 (secret) k
238 244 |
239 o 15:3a6c53ee7f3d (secret) j
245 o 17:3a6c53ee7f3d (secret) j
240 246 |
241 o 14:b605fb7503f2 (secret) i
247 o 16:b605fb7503f2 (secret) i
242 248 |
243 o 13:7395e1ff83bd (draft) h
249 o 15:7395e1ff83bd (draft) h
244 250 |
245 o 12:6b70183d2492 (draft) g
251 o 14:6b70183d2492 (draft) g
246 252 |
247 o 11:b449568bf7fc (draft) f
253 o 13:b449568bf7fc (draft) f
248 254 |
249 o 10:40db8afa467b (public) c
255 o 12:40db8afa467b (public) c
250 256 |
251 257 o 0:cb9a9f314b8b (public) a
252 258
253 259 $ cd ..
254 260
255 261 simple phase conservation
256 262 -------------------------------------------
257 263
258 264 Resulting changeset should conserve the phase of the original one whatever the
259 265 phases.new-commit option is.
260 266
261 267 New-commit as draft (default)
262 268
263 269 $ cp -r base simple-draft
264 270 $ cd simple-draft
265 271 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
266 272 > edit b449568bf7fc 11 f
267 273 > pick 6b70183d2492 12 g
268 274 > pick 7395e1ff83bd 13 h
269 275 > pick b605fb7503f2 14 i
270 276 > pick 3a6c53ee7f3d 15 j
271 277 > pick ee118ab9fa44 16 k
272 278 > EOF
273 279 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
274 280 adding f
275 281 Make changes as needed, you may commit or record as needed now.
276 282 When you are finished, run hg histedit --continue to resume.
277 283 [1]
278 284 $ echo f >> f
279 285 $ hg histedit --continue
280 286 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
281 287 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
282 288 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
283 289 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 290 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
285 291 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 292 $ hg log -G
287 @ 22:12e89af74238 (secret) k
293 @ 24:12e89af74238 (secret) k
288 294 |
289 o 21:636a8687b22e (secret) j
295 o 23:636a8687b22e (secret) j
290 296 |
291 o 20:ccaf0a38653f (secret) i
297 o 22:ccaf0a38653f (secret) i
292 298 |
293 o 19:11a89d1c2613 (draft) h
299 o 21:11a89d1c2613 (draft) h
294 300 |
295 o 18:c1dec7ca82ea (draft) g
301 o 20:c1dec7ca82ea (draft) g
296 302 |
297 o 17:087281e68428 (draft) f
303 o 19:087281e68428 (draft) f
298 304 |
299 o 10:40db8afa467b (public) c
305 o 12:40db8afa467b (public) c
300 306 |
301 307 o 0:cb9a9f314b8b (public) a
302 308
303 309 $ cd ..
304 310
305 311
306 312 New-commit as draft (default)
307 313
308 314 $ cp -r base simple-secret
309 315 $ cd simple-secret
310 316 $ cat >> .hg/hgrc << EOF
311 317 > [phases]
312 318 > new-commit=secret
313 319 > EOF
314 320 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
315 321 > edit b449568bf7fc 11 f
316 322 > pick 6b70183d2492 12 g
317 323 > pick 7395e1ff83bd 13 h
318 324 > pick b605fb7503f2 14 i
319 325 > pick 3a6c53ee7f3d 15 j
320 326 > pick ee118ab9fa44 16 k
321 327 > EOF
322 328 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
323 329 adding f
324 330 Make changes as needed, you may commit or record as needed now.
325 331 When you are finished, run hg histedit --continue to resume.
326 332 [1]
327 333 $ echo f >> f
328 334 $ hg histedit --continue
329 335 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 336 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
331 337 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
332 338 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 339 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 340 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 341 $ hg log -G
336 @ 22:12e89af74238 (secret) k
342 @ 24:12e89af74238 (secret) k
337 343 |
338 o 21:636a8687b22e (secret) j
344 o 23:636a8687b22e (secret) j
339 345 |
340 o 20:ccaf0a38653f (secret) i
346 o 22:ccaf0a38653f (secret) i
341 347 |
342 o 19:11a89d1c2613 (draft) h
348 o 21:11a89d1c2613 (draft) h
343 349 |
344 o 18:c1dec7ca82ea (draft) g
350 o 20:c1dec7ca82ea (draft) g
345 351 |
346 o 17:087281e68428 (draft) f
352 o 19:087281e68428 (draft) f
347 353 |
348 o 10:40db8afa467b (public) c
354 o 12:40db8afa467b (public) c
349 355 |
350 356 o 0:cb9a9f314b8b (public) a
351 357
352 358 $ cd ..
353 359
354 360
355 361 Changeset reordering
356 362 -------------------------------------------
357 363
358 364 If a secret changeset is put before a draft one, all descendant should be secret.
359 365 It seems more important to present the secret phase.
360 366
361 367 $ cp -r base reorder
362 368 $ cd reorder
363 369 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
364 370 > pick b449568bf7fc 11 f
365 371 > pick 3a6c53ee7f3d 15 j
366 372 > pick 6b70183d2492 12 g
367 373 > pick b605fb7503f2 14 i
368 374 > pick 7395e1ff83bd 13 h
369 375 > pick ee118ab9fa44 16 k
370 376 > EOF
371 377 0 files updated, 0 files merged, 5 files removed, 0 files unresolved
372 378 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
373 379 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 380 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 381 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 382 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 383 $ hg log -G
378 @ 21:558246857888 (secret) k
384 @ 23:558246857888 (secret) k
379 385 |
380 o 20:28bd44768535 (secret) h
386 o 22:28bd44768535 (secret) h
381 387 |
382 o 19:d5395202aeb9 (secret) i
388 o 21:d5395202aeb9 (secret) i
383 389 |
384 o 18:21edda8e341b (secret) g
390 o 20:21edda8e341b (secret) g
385 391 |
386 o 17:5ab64f3a4832 (secret) j
392 o 19:5ab64f3a4832 (secret) j
387 393 |
388 o 11:b449568bf7fc (draft) f
394 o 13:b449568bf7fc (draft) f
389 395 |
390 o 10:40db8afa467b (public) c
396 o 12:40db8afa467b (public) c
391 397 |
392 398 o 0:cb9a9f314b8b (public) a
393 399
394 400 $ cd ..
395 401
396 402 Changeset folding
397 403 -------------------------------------------
398 404
399 405 Folding a secret changeset with a draft one turn the result secret (again,
400 406 better safe than sorry). Folding between same phase changeset still works
401 407
402 408 Note that there is a few reordering in this series for more extensive test
403 409
404 410 $ cp -r base folding
405 411 $ cd folding
406 412 $ cat >> .hg/hgrc << EOF
407 413 > [phases]
408 414 > new-commit=secret
409 415 > EOF
410 416 $ hg histedit -r 'b449568bf7fc' --commands - << EOF
411 417 > pick 7395e1ff83bd 13 h
412 418 > fold b449568bf7fc 11 f
413 419 > pick 6b70183d2492 12 g
414 420 > fold 3a6c53ee7f3d 15 j
415 421 > pick b605fb7503f2 14 i
416 422 > fold ee118ab9fa44 16 k
417 423 > EOF
418 424 0 files updated, 0 files merged, 6 files removed, 0 files unresolved
419 425 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 426 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
421 427 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 428 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 429 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 430 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
425 431 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 432 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 433 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 434 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
429 435 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 436 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/58019c66f35f-96092fce-backup.hg (glob)
432 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/83d1858e070b-f3469cf8-backup.hg (glob)
433 saved backup bundle to $TESTTMP/folding/.hg/strip-backup/859969f5ed7e-d89a19d7-backup.hg (glob)
434 437 $ hg log -G
435 @ 19:f9daec13fb98 (secret) i
438 @ 27:f9daec13fb98 (secret) i
436 439 |
437 o 18:49807617f46a (secret) g
440 o 24:49807617f46a (secret) g
438 441 |
439 o 17:050280826e04 (draft) h
442 o 21:050280826e04 (draft) h
440 443 |
441 o 10:40db8afa467b (public) c
444 o 12:40db8afa467b (public) c
442 445 |
443 446 o 0:cb9a9f314b8b (public) a
444 447
445 $ hg co 18
448 $ hg co 49807617f46a
446 449 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
447 450 $ echo wat >> wat
448 451 $ hg add wat
449 452 $ hg ci -m 'add wat'
450 453 created new head
451 $ hg merge 19
454 $ hg merge f9daec13fb98
452 455 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 456 (branch merge, don't forget to commit)
454 457 $ hg ci -m 'merge'
455 458 $ echo not wat > wat
456 459 $ hg ci -m 'modify wat'
457 $ hg histedit 17
460 $ hg histedit 050280826e04
458 461 abort: cannot edit history that contains merges
459 462 [255]
460 463 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now