hg log: how to get latest commit by a particular user? - mercurial

I have a repo with multiple users. I need to make a python script to retrieve a particular user's latest commits. How do I do that with mercurial?
I was thinking of calling an hg log command thru Python's subprocess call. The problem is how I should call the hg log command such that it tells me a user's latest logs.

Easy (but not efficient or elegant way)
hg log -u USERNAME
or (with revsets)
hg log -r "author(USERNAME)"
with added value
If string starts with "re:", the remainder of the string is treated as a regular expression. To match a user that actually contains "re:", use the prefix "literal:".

I think you should be able to get a single user's latest commit by calling something like this with a system call. (Command-line version follows.)
$ hg log -u your-user-name | head -5
The head -5 gives you the whole abbreviated hg log output for the latest changeset for your-user-name, which includes five lines: changeset, tag, user, date, and summary. If you want only the changeset, you could use something along these lines. (Command-line version, again.)
$ hg log -u mike#fontling.com | head -1 | awk '{print $2}'
Comments suggest this makes unwarranted assumptions about the output format. I agree.
Based on comments, this seems to be the best expression for getting the last commit from a user.
hg log -r "last(author('email#domain.com'))"
hg log -r "last(author('Fred Flintstone'))"
To get the last three . . .
hg log -r "last(author('email#domain.com'), 3)"
hg log -r "last(author('Fred Flintstone'), 3)"

Related

Hg: How can I find the files I have changed between two revisions (or dates)?

In mercurial I am trying to find the list of files I have touched.
I came close with the commands:
hg log -u joe.doe#foo.com
which gives the changesets of joe.doe
hg status --rev 3870:4100
which gives the files that were changed between revisions.
Is there a way to know the files I have touched between two revisions or two dates?
Thanks in advance.
Combine your two things and throw a bit bash post-processing onto the output of log:
hg log -r20000:tip -u joe.doe#foo.com --template "{files % '{file}'}\n" | sort | uniq
Without the bash-postprocessing, you'll have files listed as often as they are changed.

Is there an equivalent to git's "describe" function for Mercurial?

I'm currently adding packaging to a something that is maintained in Mercurial. Currently the version is defined in the Makefile. I would like to change this so I can build daily packages or properly versioned packages.
Git provides a use "describe" function that can give you a description of the closest tagged build and current revision. For example if I run this in the kernel:
git describe HEAD
GIT returns:
v3.0-rc7-68-g51414d4
telling me that the revision is later than v3.0-rc7, with a git commitish of 51414d4
Is there something similar I can do in Mercurial?
Maybe something like this?
hg log -r . --template '{latesttag}-{latesttagdistance}-{node|short}\n'
Of course you should make an alias for that with AliasExtension.
Note however, unlike "git describe", this command will always show the "latesttagdistance" and "node|short" parts, instead of omitting them when latesttagdistance is 0.
This is a close emulation of git describe:
hg log -r . -T "{latesttag}{sub('^-0-.*', '', '-{latesttagdistance}-m{node|short}')}"
The {sub(...)} function ensures that a working copy that's exactly at tag v0.1.0 will show up as v0.1.0 and not v0.1.0-0-m123456789abc.
Note that the m before the hash is for mercurial, similar to the way git describe uses a g for git.
For convenience, create an alias by adding the following to your ~/.hgrc:
[alias]
describe = log -r . -T "{latesttag}{sub('^-0-.*', '', '-{latesttagdistance}-m{node|short}')}"
Then use the alias by simply typing hg describe.
If you'd like to emulate git describe --dirty, things get even messier – but you can still hide it all in an hg alias:
[alias]
describe = !
dirtymark=;
case " $1 " in " --dirty ") dirtymark=-dirty; ;; esac;
echo $($HG log -r . --template "{latesttag}-{latesttagdistance}-m")$($HG id -i) |
sed -r -e "s/\+\$/${dirtymark}/" -e 's/-0-m[[:xdigit:]]+//'
Now running hg describe --dirty will produce strings like:
v0.1.0
v0.1.0-dirty
v0.1.0-1-mf6caaa650816
v0.1.0-1-mf6caaa650816-dirty
Omitting the --dirty option means that you'll never get a -dirty suffix like (2) and (4), even when the working copy contains uncommitted changes.

How can I get the changeset ID of the base file when merging with mercurial?

I have a couple branches that I need to merge, but I don't know where some of the changes are coming from that are showing up in my merge tool. The change sets of local and other are obvious, but how can I find out which change set the base file came from? I'm working in a repository with dozens of branches, so viewing the graph and tracking it doesn't work very well.
Using revsets (Mercurial 1.6 and later), you can get the common ancestor of two changesets with:
hg log -r ancestor(rev1,rev2)
Try the hg grep command:
hg grep [OPTION]... PATTERN [FILE]...
search for a pattern in specified files and revisions
Search revisions of files for a regular expression.
This command behaves differently than Unix grep. It only accepts
Python/Perl regexps. It searches repository history, not the working
directory. It always prints the revision number in which a match appears.
By default, grep only prints output for the first revision of a file in
which it finds a match. To get it to print every revision that contains a
change in match status ("-" for a match that becomes a non-match, or "+"
for a non-match that becomes a match), use the --all flag.
Returns 0 if a match is found, 1 otherwise.
options:
-0 --print0 end fields with NUL
--all print all revisions that match
-f --follow follow changeset history, or file history across
copies and renames
-i --ignore-case ignore case when matching
-l --files-with-matches print only filenames and revisions that match
-n --line-number print matching line numbers
-r --rev REV [+] only search files changed within revision range
-u --user list the author (long with -v)
-d --date list the date (short with -q)
-I --include PATTERN [+] include names matching the given patterns
-X --exclude PATTERN [+] exclude names matching the given patterns
--mq operate on patch repository
[+] marked option can be specified multiple times
use "hg -v help grep" to show global options
You can use it like:
hg grep "a string"
and it will tell you in which revision it was first added.
If you're looking for something less search-y and more overview-y you can use hg log -v to see what files were changes in each changeset and hg log -p to see the actual diffs for each.

In Mercurial (hg), how do you see a list of files that will be pushed if an "hg push" is issued?

We can see all the changesets and the files involved using
hg outgoing -v
but the filenames are all scattered in the list of changesets.
Is there a way to just see a list of all the files that will go out if hg push is issued?
First, create a file with this content:
changeset = "{files}"
file = "{file}\n"
Let's say you call it out-style.txt and put it in your home directory. Then you can give this command:
hg -q outgoing --style ~/out-style.txt | sort -u
A somewhat under-appreciated feature: hg status can show information about changes in file status between arbitrary changesets. This can be used to get a list of files changed between revisions X and Y:
hg status --rev X:Y
In this case, we can use hg outgoing, to find the first outgoing changeset X and then do
hg status --rev X:
to see the files changes since revision X. You can combine this into a single line in your shell:
hg status --rev $(hg outgoing -q --template '{node}' -l 1):
I usually use
hg outgoing -v | grep files
It makes the listing shorter, but doesnt sort. But thus far I havent been in a situation where I want to push so much (and at the same time check the files) that its been a problem.
[Edit]
To do what you want:
Use cut to remove the files: part
For changesets with more than one touched file, use tr to put them on separate lines
Finally sort the resulting output with sort
Like so:
hg outgoing -v |grep files: |cut -c 14- |tr ' ' '\n' |sort -u
You can put this in ~/outgoingfiles.sh or something to have it nice and ready.
I use Torgoise Hg, which is a shell extension that has a "synchronize" view allowing you to see outgoing files before you push them. It's convenient for commits as well, and other things.
A simple hg out will also solve this.
It will list all committed but yet to push checkins.

How do I get the current mercurial revision without calling hg?

In Git the current revision hash is stored in
.git/refs/heads/master
Is there an equivalent in Mercurial that doesn't require me making a call to hg log -l1? I know I can get the current branch in .hg/branch.
This is to "display" the current hg hash on screen when browsing a web page.
$ hg parents --template="{node}\n"
52b8cee1e59c91b9147635b7f44a3a8896ee0b00
$ hexdump -n 20 -e '1/1 "%02x"' .hg/dirstate
52b8cee1e59c91b9147635b7f44a3a8896ee0b00
But why can't you just call hg parents --template="{node}\n"?
hg id --debug -i -r .
I'm not a mercurial expert, but taking the sledgehammer approach and doing a grep for the current revision hash in .hg yields only one possible, and that is .hg/branchheads.cache.
I believe this caches all the heads of the repository, so it may have multiple entries. By default, I think it will always have two entries, one for the default branch and one for the tip revision number.
I think that branchheads.cache is rebuilt whenever new changesets arrive, so it should always have the correct current revision hash in it.