1

As noted in the documentation, the hg backout command can cause problems when used with merge changesets. We have had a couple of cases recently of newer developers backing out merge changesets and causing code that we wanted to keep to be reverted when everything gets merged back together.

To avoid this, I'm trying to think of a good way to prevent this from happening at all. Is there a good general way I could write a hook or just disable the backout command entirely?

(Part of our standard developer setup is to install a custom set of extensions, so I already have a good way to install these types of rules locally for our entire development team -- I just haven't thought of a good way to implement the ruleset.)

Chris Phillips
  • 11,607
  • 3
  • 34
  • 45

2 Answers2

1

What about this:

$ hg --version
Mercurial Distributed SCM (version 2.6.3)
...
$ hg log --graph --template='{rev} {desc}'
@  5 c5
|
o    4 merge
|\
| o  3 c4
| |
o |  2 c3
|/
o  1 c2
|
o  0 c1

$ hg backout 4
abort: cannot backout a merge changeset

So it looks like Mercurial does what you want by default. Maybe you need a more recent Mercurial version.

If you are stuck to an old Mercurial version, here is a hacky hook (for *nix/Bash) which aborts backouts of merges:

[hooks]
pre-backout=REV=`echo $HG_PATS | sed -e "s/[^0-9]//g"`; test `hg log -r "parents($REV)" --template='{node}\n' | wc -l` -eq 1 || { echo 'do not do that'; exit 1; }

It extract the revision number from $HG_PATS and then uses hg log and wc to count the number of parents of the revision in question. If there is more than one parent, it is a merge.

Still, I highly recommend to use a recent Mercurial: check the release notes for exciting features you are missing.

Oben Sonne
  • 9,893
  • 2
  • 40
  • 61
  • Unfortunately, as of Mercurial 2.8, it's still possible to backout a merge using the --parent option (it's marked deprecated, but still works). It's also "helped" by the dialog in TortoiseHg that just asks you to select a parent. I need my solution to work on Windows, but I'll see if I can do something like your hook. – Chris Phillips Jan 29 '14 at 21:28
  • Oben -- thanks for your help. I didn't know about the pre-backout hook. I've posted the answer I came up with as the accepted answer, but awarded you the bounty, since your help is what put me on the right track. – Chris Phillips Jan 29 '14 at 22:06
  • Fair enough. Glad I could help. And I was not aware of the `--parent` option, thanks for pointing that out. – Oben Sonne Jan 31 '14 at 19:38
1

Here's a simple Python-based hook that prevents backout of merges. Credit goes to @Oben for pointing me in the right direction.

def prebackout_prevent_backout_merge( ui, repo, **kwargs ):
    '''Don't allow backouts to of merge changesets.'''

    # Figure out if a --parent version was given or not.
    backout_to_parent = kwargs['opts'].get( 'parent', None )

    # If no parent version was given, proceed.
    if backout_to_parent is '':
        return False

    # Otherwise abort the operation.
    from mercurial import util
    raise util.Abort( 'Backout of a merge changeset is not allowed.' )

You can configure this hook in .hgrc or Mercurial.ini with:

[hooks]
pre-backout.ttd_prevent_backout_merge = python:PATH_TO_HOOK_SCRIPT:prebackout_prevent_backout_merge
Chris Phillips
  • 11,607
  • 3
  • 34
  • 45