How do I prevent a commit using pre-commit and hg incoming? - mercurial

Sometimes developers on my team forget to pull in other developer's changesets before committing their own (admittedly, I do this as well). For a week long project there could be dozens of changes in the tree that the new commit skips over. When trying to push, hg aborts with the new remote head message then they pull and merge in all those new commits. What I'm looking for is an easy way to test if there are any new changes before someone commits and if there are to prevent the commit from happening. Ideally, there would be a clear message stating why the commit failed.
This seems like it should be very easy for a hook to accomplish but the pre-commit hook will continue on a status code of 0 and hg incoming will return 1 when there are no changes. All I need to do is invert the status of the hg incoming command but I can't find the syntax to do it. Most of the search results that I've found dive right into writing python hooks but that seems like overkill for such a simple problem.
I'm looking for something like this:
[hooks]
pre-commit != hg incoming
or
pre-commit = hg incoming == 0
I'm not sure where the message would go, either.

On Windows you can use this command to check for incoming changes:
[hooks]
pre-commit.checkNew = CMD /V /C "hg incoming & IF !ErrorLevel! EQU 0 (Exit 1) Else (Exit 0)"
If new changes are found it will cancel the commit and you will need to pull (and possibly merge) the new changes.

You had it mostly right, but you got the hook wrong:
[hooks]
precommit = ! hg incoming
There's no dash in the hook that can cancel the commit.
If, however, you turn a DVCS system into something where people can't commit without being connected to the internet your coworkers will string you up. :)

I found a solution by rereading the docs again: control if hook can proceed. Where I found the grep command in use.
[hooks]
precommit.comment = REM Don't forget to pull first!
precommit.test = hg incoming | grep -q "no changes found"
When a developer gets a failed commit they can check the output log and see the note. Not too pretty but should suffice most of the time. -q prevents "no changes found" from appearing in the log which would be confusing after a failed commit. I added my own extensions .comment and .test so the hooks get run in the correct order (c before t).

Related

hg rebase abort fails: "unknown revision"

Occasionally when performing a rebase using the MercurialEclipse plugin my repository gets thrown into an odd state. It will become stuck in a "rebasing" state, yet when I try to abort the rebase (e.g. "hg rebase -a") I get this error message:
abort: unknown revision 'xxxx'!
Where xxxx is a revision hash. Usually at this point I've abandoned all hope of performing the rebase -- I just want to get back to a happier time when my repository was not screwed up. So far my solution has been to nuke my project directory and clone it again. Is there a less drastic solution?
Just remove the .hg/rebasestate and your repo will work.
The patch described in this thread calls the internal function clearstate which just unlinks this file.
In situations similar to this, I usually do:
$ hg check
$ hg verify
$ hg up -C default
Instead of default, use whatever branch you're working on. This takes time, but so does re-cloning the repo.
It usually helps.

Get the dates of pull and update in Mercurial

Is it possible to know when a certain commit was pulled from a distant repository and the files updated with Mercurial ?
More precisely, I made a hg pull -u a few days ago, and now I'd like to know if this pull downloaded only the last commit, or if there were some commits that had not been pulled yet, making my last pull getting them as well.
hg log seems to give the dates of the commits, but nothing about the updates. Is this information anywhere ?
This information is not recorded by Mercurial. A Mercurial repository is just a container for changesets and Mercurial does not store how (or when) the changesets entered the repository.
You can setup hooks for this, though you would have to build the scripts yourself. A very rudimentary system would be
[hooks]
pre-pull = (date; hg root; hg tip) >> ~/.pull-log
post-pull = hg tip >> ~/.pull-log
This would record the current date, the current repository, and the current tip in ~/.pull-log just before every hg pull. After the pull the new tip is recorded. You could build scripts that parse the log file to extract information about what each pull did.
hg log seems to give the dates of the commits, but nothing about the updates
Yes, hg log is only concerned with the stored history (changesets) and working copy operations like updating is not part of recorded history.
Finally, let me mention that this is the first time I've seen someone ask for a "pull log". However, the opposite is quite common: there are scripts for maintaining a "push log" on a server to see who pushed what and when. This is done by Mozilla among others. See this README for some starting instructions.
If you want to log when and with which revision hg update was used to update the code, then use these hooks:
[hooks]
pre-update = (echo "---------------------------------"; date --rfc-3339=s; hg root; echo "pre-update:"; hg identify --id --branch) >> .hgupdates
post-update = (echo "post-update:"; hg identify --id --branch) >> .hgupdates
the above hooks produce a log entry like this for each time hg update is run:
2015-12-23 00:44:31+02:00
/var/www/my/project
pre-update:
802120d1d3a0 somebranch
post-update:
302720d1d3d2 otherbranch
This also works when hg update is run without a specific revision flag (-r) set

How does Mercurial tell a file was modified?

How does Mercurial tell a file was modified?
The reason I am asking is because when I run hg status its telling me several files are modified.
However, when I run hg diff there are no changes to report.
I have a theory as why this is happening: (but I am not positive)
I am using NetBeans which has Mercurial support built in. When I edit a file, it shows it as modified, although if I undo (rather than revert) those changes and save it, NetBeans tells me there are no local changes. So I am guessing NetBeans uses diffs to check for modifications while Mercurial is using something else like modification-date.
Is this correct or is something else the cause?
Mercurial does not use modification date to determine the status. This can be verified with a simple experiment:
hg init
echo "This is a test" > test.txt
hg commit -Am "commit"
touch test.txt
hg status
The code which performs the status check is in dirstate.py. If the dirstate is unsure about a file's status (e.g. because only the modification time differs, then it passes it up to localrepo.status for further analysis as seen here.
The hg help status text has some clues that may help:
status may appear to disagree with
diff if permissions have changed or a
merge has occurred. The standard diff
format does not report permission
changes and diff only reports changes
relative to one merge parent.
When you run hg diff, are you specifying any command-line options?
Is it possible the permissions of the file changed? Try hg diff --git which shows the git-style extended diffs that support permissions and binaries. By default hg diff shows only patch-friendly diffs, which don't show permissions changes.

Mercurial auto update problem

We are starting to use Mercurial for source control. We have configured the HGRC configuration file to do an auto update after we push to the "central" repository.
With some PCs we get this error msg:
warning: changegroup hook exited with status -1
HGRC looks like this:
[ui]
username=ADMIN
verbose=true
[hooks]
changegroup = hg update >&2
Later we perform the update manually and everything works right.
I had a very simmilar issue. This finally works now:
changegroup = cmd /c hg update
The bold cmd /c causes cmd.exe to spawn which will execute hg update as we want it to, but now the exit value from cmd.exe will be 0.
Longer Story:
setup: win 2008 server.
mercurial 1.9.3
hgwebdir via plain http, its an internal network
error:
my error was funnily not the -1 as in your case but
"warning: changegroup hook exited with status 1"
Anyway, the update was not performed.
I found out that I can put the hooks into either .hgrc or into hgweb.config the problem was the same here or there. I finally put it into hgweb.config as below, so all repositories are auto commiting, which is way better than having this loose branch all the time. The main reason I wanted auto commit is that the respositories on the vcs & build server hold now the latest version which makes admin tasks often simpler.
[web] push_ssl = False allow_push = *
[collections] c:\Dev\Reps = c:\Dev\Reps
[ui] debug=true
[hooks] changegroup = cmd /c hg update
It might be related with the user actually executing the hook, which might not be the one with the correct privileges.
Do you have a IIS webserver managing your Mercurial repos?
(from the thread:)
From experience with Mercurial/IIS, things I'd recommend trying:
(a) Does running a simple non-HG command work? Permissions on cmd.exe will
affect out-of-process python hooks.
(b) Does a simple hook like 'python -c "import sys; sys.exit(0)"' work?
(c) If you make it this far, can you confirm that the process is running as the
user you think it's running as, with a hook that does something like:
import win32api
username = win32api.GetUserName()
(write username to a file so you can read it)

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.