How to disable pretxncommit hooks with mercurial queues or histedit? - mercurial

I have some pretxncommit hooks in my local mercurial repository, those hooks are used to check that the commit message includes a reference to a ticket and some other sanity checks.
My problem is that when I try to use mercurial queues, commands like qnew try to run these hooks and the one of the ticket checking fails, I have seen the same problem with histedit and similar extensions.
Why are pretxncommit hooks executed with these commands? Do they run some kind of internal commit?
How can I make these hooks to be run only on commits?

Yes, a qnew creates a real commit and thus invokes all the relevant commit hooks. You can confirm this for yourself by temporarily disabling MQ while you have an MQ patch applied and looking at the log.
There is no way to make the pretxncommit hook apply to only some commands except by jury-rigging something with other hooks:
$ cat .hg/hgrc
[hooks]
pre-qnew = touch .hg/skiphook
post-qnew = rm .hg/skiphook
pretxncommit = test -e .hg/skiphook || echo not skipping
$ hg rm README # make some change
$ hg qnew asdf # no hook
$ hg qpop
$ hg rm README
$ hg ci -m asdf
not skipping
Here our pretxncommit hook makes sure a specific file doesn't exist before running its (trivial) hook, and the pre-/post-qnew hooks create the file and clean it up.

The function abort_commit_to_wrong_branch in https://stackoverflow.com/a/19349636/350713
shows an approach to run a hook only on a "real" commit, not an MQ commit.
The idea is to check for the attribute _committingpatch in repo.
If repo has '_committingpatch' attribute, then it is an MQ commit in progress.
The relevant line is
if hasattr(repo, "_committingpatch"):
This is mentioned in the function newcommit in
http://hg.intevation.org/mercurial/crew/file/7032dcff290c/hgext/mq.py#l293

pretxncommit works with all changes (recordable) inside repo
if you want ignore mq-operation, you could look for the changeset parents and see if that's a descendant
of the qparent/qbase tag or see at WC. Smth. like (dirty from head, not from test) hg id -tr .
Or (maybe delirium) - when you work with MQ, you work with qtip always, sn't it?
>hg parents
...
tag: qtip
tag: tip
..

Related

How to make a Mercurial commit with no files?

I'm looking for the Mercurial equivalent of git commit --allow-empty for testing purposes.
Can't be done. There doesn't have to be a change to a source file, but you have to have changes something, be it file permissions, branch name, tag, or something.
You say "for testing purposes". If that's the case I usually just use
echo another line >> README ; hg commit -m 'added another line'
I can hit up-arrow enter on that plenty fast.
I think the best solution I've found is:
touch foo
hg add foo
hg commit -m 'Empty commit'
hg rm foo
hg commit --amend
Works with MQ. Make a MQ changeset with some dummy change, then revert the change and refresh (hg qref) the patch. Voila.

Mercurial: Include secret changesets in bundle?

Using Mercurial, how can I bundle all changesets not known to be in another repository, including secret changesets?
I know bundle's --base option happens to include secret changesets, but I don't want the --base behavior. (And it seems unusually weird that secret changesets are always included with --base but are never included without it. Shouldn't there be a separate option?)
FYI, I commonly want to make a backup of all changesets which are only in my local repo before attempting a potentially dangerous history rewrite.
You are correct that hg bundle will normally exclude secret changesets. This is because it's just running the equivalent of hg outgoing and bundling these changesets.
So some work-arounds:
If you know that you have at least one draft or public outgoing changeset as an ancestor of your secret changesets, then you can use
$ hg bundle --base "parents(outgoing())"
to get what you want. The outgoing() revset will pick the missing draft and public changesets and parents(outgoing() will be suitable bases. Since you use --base you get all descendants (public, draft, and secret) from these bases.
You could temporarily make your secret changesets draft, bundle, and then mark them secret again:
$ secret=$(hg log --template "{rev} " -r "secret()"); \
hg phase -d $secret; \
hg bundle out.hg; \
hg phase -f -s $secret
(I use Zsh and there I had to use ${=secret} instead of $secret because Zsh doesn't do word splitting on parameter expansion by default.)
It's important to chain the commands with ; instead of && since you'll want to reset the phases regardless of what happens in the hg bundle call — passing wrong parameters to hg bundle should not mean that you lose all the information about the secret changesets. Note also that since secret changesets only have secret descendants, there's no information loss with this technique.
You can turn this into a shell alias:
[alias]
bundle-all = !secret=$(hg log --template "{rev} " -r "secret()");
hg phase -d $secret;
hg bundle $#;
hg phase -f -s $secret
The $# is expanded by Mercurial before the alias is invoked and this lets you insert the necessary arguments for hg bundle.
Note that phase information cannot be stored in bundles — the bundle format has not been changed to accommodate it.
If you know there is at least one public changeset, you can use this:
hg bundle -r "not public()" --base public()
OTOH, that won't work if there are no public changesets, use this instead:
hg bundle -r "not public()" --base null
The problem with Martin's answer is that it relies on outgoing, which in turn relies on a direct connection to the push repo. If you don't always have an internet connection to that repo, these methods work well for me. It's also somewhat simpler than the phase dance.
One test for whether there are any public changesets is to capture the output of:
hg log -r public() -l 1 --template "{rev}"
and test its length, or the presence of [0-9].

Generating patches in Mercurial

I've looked for that in the manual, but I can't generate a patch for the last commit.
I tried
hg qnew patch_name
but it does only file with
# HG changeset patch
# Parent a6a8e225d16ff5970a8926ee8d24272a1c099f9c
I also tried
hg export tip
but it doesn't do anything. I committed the changes exactly.
How to generate a patch file with the last commit in?
The command to do this is export:
$ hg export -o FILE -r REV
It doesn't require redirection and will thus work correctly on any platform/shell.
Your hg export tip is the best way to do it, and the hg diff and hg log based answers are just lesser versions of the same. What exactly do you see/get when you type hg export tip? What does the output of hg log -p -r tip show?
The changeset tip is just means "the changeset that most recently arrived in my repository" which isn't as useful a concept as you might think, since hg pull and hg tag all create changesets too. If you really want the last thing you committed you'll need a more precise revspec.
Like so:
hg diff -r tip > tip.patch
You can use this command:
hg log -r tip -p > tip.patch
this will generate a patch for just that revision.
If you want to convert the latest commit to a patch file, use
hg qimport -r tip
This will replace the topmost regular commit with an applied MQ patch file.
To generate patches using "mq extensions" in mercurial, you can follow the below given steps. This will create a patch using mercurial:
1) Enabling mq extensions: Add the following lines to your hgrc file and save it.
[extensions]
mq =
2) Creating a patch using mq extensions: To create a patch using mq extensions you can do the following.
hg qnew -e -m "comment you want to enter" bug_name.patch
In the above command, -e flag is for editing the patch and -m flag is for adding a message to the patch.
3) Updating the patch: For updating the patch, you can use the following command when a patch is already applied.
hg qrefresh

Can't branch a single file with Mercurial?

is this possible with Mercurial? and which Version Control system can do this besides Clearcase?
David is correct that you can't have a branch that exists on only a single file, but it's worth pointing out that people often have branches that alter only a single file. Since the branch metadata is stored in the changeset, and since the changeset contains only a delta (change), having a branch that alters only a single files is nearly instantanous to create, update, commit, and merge, plus it takes up almost no space on disk.
Resultingly, it's a very common way to handle per-customer configurations. Keep the tiny change for them in a branch, and merge from main, where development happened, into that branch, whenever you want to update their deployment.
How you could use MQ:
$ hg qnew -m "Changes for client0" client0
... change the file ...
$ hg qref # update the client0 patch with the changes
$ hg qpop # pop the changes off the queue stack
... develop like normal ...
... client0 asks for a build ...
$ hg qpu # apply client0's patch
$ make release
$ hg qpop
It would get a bit finicky if you've got to deal with a lot of clients… But it may be worth considering.
The other thing you could do, of course, is just commit a bunch of .diff files:
... make changes for client 0 ...
$ hg diff > client0.diff
$ hg revert --all
$ hg add client0.diff
$ hg ci -m "Adding client0 changes"
... develop ...
... client0 asks for a build ...
$ patch -p1 < client0.diff
$ make release
$ hg revert --all
No, it's not possible. A branch in Mercurial is a snapshot of the entire repository state.
You could do it with CVS, though, as CVS tracks changes on a per-file basis :)

How to avoid accidentally 'hg push' instead of 'hg qpush'?

For those of you that use Mercurial with the MQ extension:
This is the second time I accidentally submit changes to the central repository (hg push) instead of applying a patch to my working directory (hg qpush).
I think this is very unfortunate, because it is a very simple error to make and has very severe consequences (the least having to do a hg backout and an extra hg push for each submitted change in order to generate a new commit that "undoes" the las one to the central repository, but the history becomes convoluted and unpleasant.
My goal is to configure some alias or something in my environment in orden to make hg push harder to do by accident.
Do you have any suggestions? I was thinking something like:
[alias]
push= <-- how to NOP the push command??
pushtoserver=push
As this is a completely subjective question, this goes as community wiki.
thanks!
some vague ideas:
you could remove the default push location from your repo
you could write a "did you mean qpush? yes, no" pre-push hook
This hook (bash command line) asks for confirmation before pushing changes to the remote (tested with mercurial 1.4):
[hooks]
preoutgoing.confirm = read -p 'Are you sure you want to push to remote? (y/n): '; echo $REPLY | grep -q 'y'
you could alias push to qpush and alias pushtoserver to push (i think this works but can't try it now)
Put the following in your .hgrc:
[alias]
pushtoserver = push
push = 'Did you mean qpush or pushtoserver?'
Works like this:
$ hg push
alias 'push' resolves to unknown command 'Did you mean qpush or pushtoserver?'
$ hg pushtoserver
abort: repository default-push not found!
See also the alias section of the hgrc manpage.