mercurial - first revision a string appeared - mercurial

Say the string "abc123" first appeared in revision 12, and the current revision is 200. How can I know that the string "abc123" first appeared in revision 12? Plus, how do I get verision 12's hash?

You should be able to use
hg grep abc123 -r 0:tip
to search revisions in order for the first revision that the string abc123 appears in. Keep in mind that this can be a very slow process for a large repository with a long history, as each revision will have to be checked individually.
To speed up the process for such a repository, you can use hg bisect. E.g.:
hg bisect -r # reset bisect if needed
hg bisect -g 0
hg bisect -b tip
hg bisect -c '! hg grep -r . abc123'
Note that marking revisions that contain the string as "bad" and those that don't contain it as "good" seems counterintuitive, because bisect is normally used to hunt for the first revision that contains a bug. Thus the "bad" revisions are the ones that contain the string.
Note also that bisect may not work if there are revision ranges that do not contain the string you are looking for.
Finally, the ! operator to negate a shell exit code may not be supported by some shells. In those cases, use
hg bisect -c 'if hg grep -r . abc123; then false; else true; fi'
instead.
To get the hash of (say) revision 12, use:
hg id -i -r 12
or:
hg id --debug -i -r 12
The latter version will print the full hash, the former will give you the abbreviated hash.

Related

How can I view the remaining changesets left to check in an hg bisect?

When I'm running hg bisect, sometimes I want to "look ahead" at what's remaining, to see if there are any obvious culprits I could check while a fairly slow bisection test runs.
So given I've run
> hg bisect -g
Testing changeset 15802:446defa0e64a (8 changesets remaining, ~2 tests)
How can I view which 8 changesets are remaining?
You can use the bisect("untested") revset to view the untested changesets. E.g.:
hg log -r 'bisect(untested)'
If that is too much information, you can also combine it with a template option:
hg log -r 'bisect(untested)' -T '{rev}\n'
Or you can just restrict the output to the first and last entry of the range:
hg log -r 'first(bisect(untested))+last(bisect(untested))'
You can also create revset aliases in your .hg/hgrc or ~/.hgrc file to save some typing, e.g.:
[revsetalias]
tbt = bisect("untested")
tbt2 = first(tbt)+last(tbt)
Then you can do (for example):
hg log -r tbt
Note that if you call a revset alias untested, you'll have to quote the string untested (e.g. bisect("untested")), hence my choice of tbt (for "to be tested").
See hg help revsets for more revsets pertaining to bisection.

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

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)"

Finding first appearance of text in Mercurial repository

I have a Mercurial repository with ~800 changesets and I need to find the first changeset where the word Example appeared. The word appears inside a .php file and not on a commit comment etc.
What is the quickest/easiest way to do that?
try hg grep Example *.php
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.
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 search in given revision range
-u --user list the author (long with -v)
-d --date list the date (short with -q)
-I --include include names matching the given
patterns
-X --exclude exclude names matching the given
patterns
use "hg -v help grep" to show global options
The selected answer is incomplete:
hg grep --all --files-with-matches 'PATTERN' [FILES]
is normally what you want.
You would want to use the --diff (--all is deprecated) flag of hg grep. It searches the diffs rather than file contents itself, what this would result in is, you would get all the changesets/revisions where the word Example appeared or removed.
Now to get the first hit you need to pass this in revlog order via the -r flag. That is the revisions will be searched from 0 to tip. ( -r 0:tip )
And for the .php files you would want to pass -I flag which is for file name patterns.
So your command will be :
hg grep --all -r 0:tip "Example" -I "*.php"
hg help filesets
...
"grep(regex)"
File contains the given regular expression.
hg locate "set:grep(Example) and **.php"
or
hg locate "set:**.php and (**Example*)"

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.

Is there any way to see difference between last two versions of a file using hg commands?

I want something like this
hg vdiff filename.txt -lastRevision -secondLastRevision
I don't know what vdiff is, but how about:
hg diff -r rev1 -r rev2 filename.txt
Edit: to get the last 2 revisions, that would be:
hg diff -r -2 -r -1 filename.txt
Type hg help revisions for information about specifying revisions.
As of this writing, the top answers refer to -1, -2 and -3. The negative integers are historical artifacts and should not be used with modern Mercurial workflows.
Typically, the "last version" means "the currently checked out revision". In that case, to see the changes to file in the currently checked out commit, you can use
hg diff --change . filename.txt
If you'd like to see the last time filename.txt was changed, you can use
hg log --follow --patch --limit 1 filename.txt
The --follow argument causes hg log to follow history, so it'll only output the current revision or its ancestors.
Use
hg diff -r -3 -r -2 file