Mercurial hooks -- pass information between hooks? - mercurial

I currently have a pre-commit hook in my mercurial project that gives the user the option to update the version number of the project if they wish (e.g. 1.0 to 1.0.1 or 1.1 or 2.0). They select one of these options, and the hook updates the version number in one of the project's files prior to the commit taking place.
When I run hg commit, this hook runs and updates the relevant file with the new version number, and then performs the commit.
I'd like to add to the hook such that it calls hg tag <new_verson_number> as well.
However, I can't add this to the pre-commit hook, because then the tag will be added before the commit is called, causing the tag to be one revision out of date.
I'd like to add the hg tag command to a commit hook (run after the commit), so that the sequence of events is like so:
hg commit -m "my commit message"
user says yes, I'd like to change the version number
version number is updated in the relevant file
commit occurs [everything up to here is fine]
if the user changed the version number, run a commit hook: hg tag <new_version_number>.
Now, I could add a commit hook that read off the new version number from the file it's stored in and run hg tag <new_version_number>, but what if the user decided not to change the version number? In that case, I don't want a tag added, and if I blindly run hg tag <new_version_number> I'll end up with tags I don't want.
So - is there some way I can tell the pre-commit hook to leave some information for the commit hook (a yes/no of whether to add the tag), and the commit hook can use this to determine whether to add the tag or not?
cheers.

How about a commit hook that checks if the last commit modified the file in which you store the version? Something like:
[hooks]
commit.tagversion = if hg log -r $HG_NODE --template '{files}' | grep -q VERSION_FILE ; then hg tag $(hg cat -r $HG_NODE VERSION_FILE) ; fi
I haven't tested it, but that or something like it should work.

You could extract the tag name that you would add and then check to see if it already exists in hg tags before you add it. That would also catch the case where the developer amends the version number manually.

Related

What is the name for the commit/head that corresponds to the local checked-out state?

There is a commit in my hg repository with hash 123abc. This is the last commit I made in the repo. When I run hg diff --from 123abc, I see no output. When I run hg log --graph, I see an # next to 123abc.
In Git this commit would be called "HEAD". I'm not sure what it's called in Mercurial. It is not the "tip", because I pulled other changes after the last time I committed (and hg log -r tip shows commit 456def).
What is this commit/head called?
Mercurial calls this the "parent" or the "parent revision of the working directory", and you can see it by running hg parent, hg id, or hg summary.
You can refer to it as . with the hg log command:
hg log -r . # show the commit message for the parent
If 123abc has no children, then it is a "head".
A head is a changeset with no child changesets. The tip is the most
recently changed head. Other heads are recent pulls into a repository
that have not yet been merged.
(https://www.mercurial-scm.org/wiki/Head)
Regardless whether the current working directory derives from a head or a non-head, I would refer to the commit that precedes it as the "working directory parent" changeset or commit. (That may just be the term my team uses - not sure it is "official".)
The parent may be visible in a GUI tool (like Tortoise) or you can get it using hg parent.
Based on the statements about 456def I'm a little confused whether it has no children, or not? (Maybe update the question to clarify / add more detail)

Get Mercurial next commit hash

I am at revision 56, hash 6af16aa3edf8. Next revision will be 57, with hash ???. Is there a way to know the hash of revision 57? I need it in a pre-commit hook.
WHY THO?
I developed a script, called via pre-commit hook, that update some version files. That way, the compiled executables can give all info about the revision they are build from. I'm adding the revision number of the current commit in my version file, simply retrieved with "parent revision number + 1". Since the revision number is not reliable when collaborating with other people on the same repository, I prefer to add the hash, too. Don't know how to retrieve it...
No, you cannot predict the next hash even when you know its changeset completely. The commit time also plays a role there:
~/hg-test $ hg ci -m "b in foo"
~/hg-test $ hg id
d65d61e6898a tip
~/hg-test $ hg rollback
~/hg-test $ hg ci -m "b in foo"
~/hg-test $ hg id
c7f5ff744e43 tip
https://www.mercurial-scm.org/wiki/Nodeid
I suggest to solve your problem such:
In your build tools, query whether the project is built from a repository. If so: retrieve the repository information. E.g.
ver = $(hg log -r. -T"{node|short} from {date|isodate}")
will give you
c7f5ff744e43 from 2017-07-26 14:05 +0200
Generate the version file from that information in your build chain on the fly
For distribution purposes, generate and amend this file to the package, so that the build process, when it finds it is not started from a repository checkout, still has a version file it can make use of.

How can I commit a file before the tag is committed?

I want to automatically bump the version of my project when I use hg tag XXX.
I have set up a pretag hook in my hgrc (note: I have removed the stuff that ensures it is outputting to VERSION in hg root, for clarity):
[hooks]
pretag.bump_version = (echo "$HG_TAG" > VERSION; hg commit -m "Updated VERSION to $HG_TAG" VERSION)
When I create a new tag:
$ hg tag 1.1
I get the error:
warning: ignoring unknown working parent <revision_id>!
I can use a tag hook instead, which succeeds, but then the VERSION number is exactly one revision later than the tag: which means that updating to the tagged revision, and then building will result in the product's version number (which depends upon the VERSION file) will be incorrect.
Is there a better way to handle this? I've looked at SO question #2558531, but that deals with updating the version number each time: I just want to update the version number before I tag the repository.
Switch to a pre-tag instead of a pretag hook. The hook pretag is a special hook which is aware that you're tagging. By contrast the pre-tag hook is a generic pre-* hook which is run before the tag command launches at all and is completely unaware that it's tagging -- which means it runs earlier too. (There are pre-* hooks for everything even, say, pre-log).
I got your example to work like this:
[hooks]
pre-tag.bump_version = echo $HG_ARGS > VERSION; hg commit -m "updated version to $HG_ARGS" VERSION
Using the command line only that looked like:
ry4an#ry4an:~$ hg init tagtest
ry4an#ry4an:~$ cd tagtest
ry4an#ry4an:~/tagtest$ echo text > VERSION
ry4an#ry4an:~/tagtest$ hg commit -A -m initial
adding file
ry4an#ry4an:~/tagtest$ hg tag --config hooks.pre-tag='echo $HG_ARGS > VERSION; hg commit -m "updated version to $HG_ARGS" VERSION' 1.1
Notice I had to switch the argument to $HG_ARGS since it's a pre-* command that doesn't know we're tagging. The details are in the hgrc manpage.
Also note I'm committing only the VERSION file when I commit in the hook by naming it explicitly. You don't want to accidentally commit a bunch of debugging stuff you'd excluded from a previous commit just because you tagged.

Can I revert a range of lines in a file with mercurial?

I often notice a few unwanted changes when I review my working copy (with hg status and hg diff) right before a commit. For example, I might have temporarily added or remove some code just for the duration of a debugging session.
I know I can use hg revert to remove unwanted changes, but this removes all the changes in the entire file. Is there a way to revert just a part of a file?
I'm not sure if you can revert individual lines explicitly, but what I do in situation like yours is to commit the good code and revert the rest (the bad code). This workflow is easy using Mercurial's record or crecord extension (I recommend the latter one).
I've been doing this with the interactive ncurses style ui hg revert -i that lets you walk around and select the parts you want to destroy, either file, diff chunk or line by line, as you please, depending on how deep you unfold your changes.
I am not sure if this is a standard hg feature or not, you can verify easily enough if yours has it:
> hg revert --help --verbose | grep -- -interactive
-i --interactive interactively select the changes (EXPERIMENTAL)
Just remember that the changes you mark (X) will be what gets nuked, not what you retain.
Assuming you have the record and shelve extensions enabled, you can do as follows:
hg record -m "garbage" # pick out and commit the change you want to revert
hg shelve --all # temporarily hide other changes
hg strip tip # remove the garbage changeset
hg unshelve # restore the changes you want to keep
One way is using a graphical diff tool like kdiff3. If you feed it the diff and choose "merge current file" you can go line by line and pick what you want.
The better way is to commit more often. If you make a habit to commit right before adding debugging code, then either commit or revert your debug code before adding your "real" code, it makes it very easy to remove your debug code because it has its own revision. Alternately, you can put your debugging code in a separate branch altogether.
The TortoiseHg GUI's "Commit" window has a "Hunk Selection" tab that allows selection of specific sections of a file's changes to be committed.
I've got a different answer for your problem, which is the same problem I have. This is a great use case for mercurial queues!
When I am about to start adding debugging code to a change that I think is ready, I do the following:
hg qnew -m "fix for bug #123" fix.patch # basically a local-only commit
hg qnew -m "debugging" dbg.patch # prepare the next changeset at the tip
[add my debugging]
hg qrefresh # update the changeset at the tip
[...]
hg qpop # pop the debugging off the repo history
It takes a little bit of getting used to -- you end up having to reorder your patches to then fold whatever fixes you made into the original work patch.
Also, check out Bill Barry's attic extension. This page talks about how to use it for a few different workflows and how that compares to using mq. https://www.mercurial-scm.org/wiki/AtticExtension
If the commit where you want the change is e.g. ba1c841aaff4,
the easiest is to use:
hg meld -r ba1c841aaff4^ <filename>
Now click on a right arrow (pointing to the right) in the middle to revert your lines, save the file and close meld. kdiff3 (old and unintuitive) can be an alternative.
Side note: in order to use meld you need to configure it in our ~/.hgrc file:
[extdiff]
cmd.meld =
[merge-tools]
meld.args=$base $local $other
Download and install meld https://meldmerge.org/
(You should have Mercurial installed locally or TortoiseHg)
Launch Meld and select Version Control View and then select you will be asked to choose a parent directory of the file you want to modify.
Select the file which has the uncommitted changes
Choose which lines you want to revert to the last commit by selecting the arrow. The document on the left is from the last commit and the right document is the file with the uncommitted changes.

mercurial automatic push on every commit

Being very familiar with the subversion workflow and that fact that 99.9% of the time my computer is connected to the internet, I don't like doing 'hg ci' and 'hg push' separately.
I remember bzr had a 'checkout' command that would bind subsequent 'commit' commands to automatically commit directly to the server ('push').
Does mercurial have something similar to this?
PS: Writing a shell script or alias that runs 'hg ci $* && hg push' would be the last thing I'd do.
You could add a hook to run push after a successful commit.
EDIT: I just tried it out and it seems to work fine. I added the following to the .hg/hgrc file of the repository I wanted to activate automatic pushing for:
[hooks]
commit.autopush = hg push
EDIT 2: Also, you don't have to worry about something like this:
You're in a repository that you don't want to automatically push.
You use hg -R ~/another-repo-that-autopushes commit to commit in a different repo that does automatically push.
Will the hg push hook end up pushing the changes in the current directory instead of the one you're committing in?
No, it won't. According to the page I linked:
An executable hook is always run with its current directory set to a repository's root directory.
It's an edge case, but Mercurial handles it correctly.