diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -557,8 +557,21 @@ class fold(histeditaction): middlecommits) def skipprompt(self): + """Returns true if the rule should skip the message editor. + + For example, 'fold' wants to show an editor, but 'rollup' + doesn't want to. + """ return False + def mergedescs(self): + """Returns true if the rule should merge messages of multiple changes. + + This exists mainly so that 'rollup' rules can be a subclass of + 'fold'. + """ + return True + def finishfold(self, ui, repo, ctx, oldctx, newnode, internalchanges): parent = ctx.parents()[0].node() hg.update(repo, parent) @@ -566,7 +579,7 @@ class fold(histeditaction): commitopts = {} commitopts['user'] = ctx.user() # commit message - if self.skipprompt(): + if not self.mergedescs(): newmessage = ctx.description() else: newmessage = '\n***\n'.join( @@ -601,7 +614,22 @@ class fold(histeditaction): replacements.append((ich, (n,))) return repo[n], replacements +class _multifold(fold): + """fold subclass used for when multiple folds happen in a row + + We only want to fire the editor for the folded message once when + (say) four changes are folded down into a single change. This is + similar to rollup, but we should preserve both messages so that + when the last fold operation runs we can show the user all the + commit messages in their editor. + """ + def skipprompt(self): + return True + class rollup(fold): + def mergedescs(self): + return False + def skipprompt(self): return True @@ -644,6 +672,7 @@ actiontable = {'p': pick, 'edit': edit, 'f': fold, 'fold': fold, + '_multifold': _multifold, 'r': rollup, 'roll': rollup, 'd': drop, @@ -850,6 +879,14 @@ def _histedit(ui, repo, state, *freeargs 'histedit') state.backupfile = backupfile + # preprocess rules so that we can hide inner folds from the user + # and only show one editor + rules = state.rules[:] + for idx, ((action, ha), (nextact, unused)) in enumerate( + zip(rules, rules[1:] + [(None, None)])): + if action == 'fold' and nextact == 'fold': + state.rules[idx] = '_multifold', ha + while state.rules: state.write() action, ha = state.rules.pop(0) @@ -995,7 +1032,7 @@ def verifyrules(rules, repo, ctxs): raise util.Abort(_('duplicated command for changeset %s') % ha[:12]) seen.add(ha) - if action not in actiontable: + if action not in actiontable or action.startswith('_'): raise util.Abort(_('unknown action "%s"') % action) parsed.append([action, ha]) missing = sorted(expected - seen) # sort to stabilize output diff --git a/tests/test-histedit-fold.t b/tests/test-histedit-fold.t --- a/tests/test-histedit-fold.t +++ b/tests/test-histedit-fold.t @@ -509,4 +509,64 @@ into the hook command. $ hg add amended.txt $ hg ci -q --config extensions.largefiles= --amend -I amended.txt +Test that folding multiple changes in a row doesn't show multiple +editors. + + $ echo foo >> foo + $ hg add foo + $ hg ci -m foo1 + $ echo foo >> foo + $ hg ci -m foo2 + $ echo foo >> foo + $ hg ci -m foo3 + $ hg logt + 4:21679ff7675c foo3 + 3:b7389cc4d66e foo2 + 2:0e01aeef5fa8 foo1 + 1:578c7455730c a + 0:79b99e9c8e49 b + $ cat > $TESTTMP/editor.sh < echo ran editor >> $TESTTMP/editorlog.txt + > cat \$1 >> $TESTTMP/editorlog.txt + > echo END >> $TESTTMP/editorlog.txt + > echo merged foos > \$1 + > EOF + $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 1 --commands - 2>&1 < pick 578c7455730c 1 a + > pick 0e01aeef5fa8 2 foo1 + > fold b7389cc4d66e 3 foo2 + > fold 21679ff7675c 4 foo3 + > EOF + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + reverting foo + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + merging foo + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg logt + 2:e8bedbda72c1 merged foos + 1:578c7455730c a + 0:79b99e9c8e49 b +Editor should have run only once + $ cat $TESTTMP/editorlog.txt + ran editor + foo1 + *** + foo2 + *** + foo3 + + + + HG: Enter commit message. Lines beginning with 'HG:' are removed. + HG: Leave message empty to abort commit. + HG: -- + HG: user: test + HG: branch 'default' + HG: added foo + END + $ cd ..