I can get the head of the current branch via
hg head .
I can then get the data I need by copying and pasting the changeset ID from the output of that command into this one:
'hg' 'log' --'limit' '1' --'style' 'xml' --'verbose' --'rev' 'ac99e18fbca1'
The problem is that I need to do this programatically, and I'd prefer not to parse the output of hg head .. So, can I either:
Do this with a single command? I couldn't find anything in revsets that would work.
Format hg head . to give me just the changeset ID?
You can use in log any usable cset-id, not only short-hash
Revset for hg head . (may produce more than one changeset in case of anonymous branching)
hg log -l 1 --style xml -v -r "heads(branch(.))"
is perfectly valid and always usable single command for your task
For all log-style commands (including heads) output can be modified with --template and template-keywords
Only changeset-hash in head output will be something like
hg head . --template "{node|short}\n"
Test-case:
Standard head
>hg head .
changeset: 39:dc3bad781bc5
tag: tip
user: Ray Bream <...>
date: Fri Aug 16 16:35:17 2013 +0600
summary: ***
Templated head for the same repo
>hg head . --template "{node|short}\n"
dc3bad781bc5
Just noticed head accepts the --style param.
hg head . --style xml --verbose
Related
A number of changes have been made to a file in a branch. Some of the changes were for a feature that now needs to be implemented on the main branch.
How can I create a patch for each revision of the file so that I can choose which changes I wish to apply to my main branch? Ideally I would like each patch to contain the description of the revision too for reference purposes.
You can get a log for just one file by quoting that file in the log command:
hg log FILENAME
and you can get the diff for a certain revision and filename by giving both as argument to log, asking it to give you the patch (I've configured my hg to use the git-style patch format by default - maybe that's needed here, too):
hg log --patch --rev XXX FILENAME
if you want a patch for each revision FILENAME was changed, you could try in bash something like
for rev in $(hg log -T"{rev}\n" FILENAME); do hg log -p -r${rev} FILENAME > FILENAME.${rev}.patch; done
which yields you the typical patches, including the commit message used:
$ cat FILENAME.15.patch
Änderung: 15:441bead3e0b3
Vorgänger: 7:36479da8f266
Nutzer: planetmaker <email#example.org>
Datum: Tue Feb 10 22:58:24 2015 +0100
Zusammenfassung: More boo
diff --git a/FILENAME b/FILENAME
--- a/FILENAME
+++ b/FILENAME
## -1,1 +1,2 ##
foo is boo!
+Even moar booo!
Mercurial tracks the contents of a file throughout renames (hg mv $OLD $NEW), so that hg annotate $NEW also shows up the line-wise changes formerly made to $OLD with their original identification. That works fine.
BUT there seems no straightforward way to find out the name of the $OLD file, to which some given line has belonged within the ancestry of $NEW. hg annot $NEW -r$REV only works down to the rename changeset.
Of course the information is somehow accessible, e. g. by crawling through hg log (without --follow) and identifying the renames with some hg log -r$RENAMEREV -g -p (or by clicking through hg serve's web interface).
But this “workflow” is not only annoying and error-prone, but [most importantly] it isn't non-interactive/scriptable.
My question: Is there a way to get/construct either
some list of the file name history of $NEW (best with respective revision ranges), or
the name of the file in which line $LINE was commited (some kind of filename option for hg annot)?
Ideas in either the hg CLI or Python/hglib appreciated.
Either include the {file_copies} keyword in your hg log template:
$ hg init demo
$ cd demo
$ touch a
$ hg ci -Am 'file a'
adding a
$ hg mv a b
$ hg ci -Am 'moved to file b'
$ hg log -r . -T"{file_copies}\n"
b (a)
The built-in template status will include file copy info when you set the --copies flag:
$ hg log -r 1 -Tstatus --copies
changeset: 1:b37952faaddc
tag: tip
user: Martijn Pieters <mjpieters#fb.com>
date: Sun Jul 31 16:07:04 2016 +0100
summary: moved to file b
files:
A b
a
R a
So file b was taken from a.
See hg help template for more things you can include in log output.
So there was a new branch created where we made some breaking changes to the codebase.
Now we are going to merge, but before that I want to get a list of all the files that were changed in the branch.
How can I get a list of files? I tried:
hg status --change REV
But i'm not sure if that is what I want, since I want all files changed in this branch and not a specific revision in the branch.
BTW, how can I view the revision numbers?
Try with
$ hg status --rev "branch('your-branch')"
to get the changes between the first and the last changeset on the branch (hg status will implicitly use min(branch('your-branch')) and max(branch('your-branch')) when you give it a range of revisions like this).
Since you'll be merging, you should really look at
$ hg status --rev default:your-branch
to see what is changed between the default branch and your-branch. This shows you the modifications done, and filters out any modifications done on the branch due to merges with default.
This is necessary in case your history looks like this:
your-branch: x --- o --- o --- o --- o --- o --- y
/ / /
default: o --- a --- o --- b --- o --- c --- o --- o --- d
where you've already merged default into your branch a couple of times. Merging default into your branch is normal since you want to regularly integrate the latest stuff from that branch to avoid the branches drifting too far away from each other.
But if a new file was introduced on default and later merged up into B, then you don't really want to see that in the hg status output. You will see it if you do
$ hg status --rev a:y
since the file was not present in a, but is present in y. If you do
$ hg status --rev d:y
then you wont see the file in the output, assuming that it's present in both heads.
You write in a comment that you're working Kiln repository. They mean "clone" when they say "branch", but the above can still be adapted for your case. All changesets will be on the default named branch, but that's okay.
Run the following command in your local clone of the "branch" repository:
$ hg bookmark -r tip mybranch
This marks the current tip as the head of mybranch. Then pull all the changesets from the main repository:
$ hg pull https://you.kilnhg.com/Repo/public/Group/Main
You then mark the new tip as the tip of the main repository:
$ hg bookmark -r tip main
You can now run
$ hg status --rev main:mybranch
to see the changes between main and my-branch. If you want to see what you did on the branch itself, the use
$ hg status --rev "::mybranch - ::main"
The ::mybranch part will select changesets that are ancestors of mybranch — this is all your new work, plus old history from before you branched. We remove the old history with - ::main. In older versions of Mercurial, you would use hg log -r -r mybranch:0 -P main.
In cases like this, I prefer to do a test merge from a newly checked-out copy of the repo. This has the advantage that I can see how many conflicts the merge will produce, and I can keep the merge result because I did it in its own copy.
To view the revision numbers, enable the graphlog extension and run:
$ hg log -b your-branch -G
This gives you a nice ASCII graph. This can be handy to quickly look at the graph, but I recommend using TortoiseHg for a cross-platform log viewer:
I had to merge the default branch into my branch to get some fixes, now the commands above shows also files changed because of merges (this files changed after the merge again in the default branch).
Therefore, to get only the correct files I use something like this:
hg log --rev "branch('my-branch') and not merge()" --template '{files}\n' | sed -e 's/ /\n/g' | sort -u
if you have spaces in file names, you can do it this way:
hg log --rev "branch('my-branch') and not merge()" --template '{rev}\0' | xargs -0 -I # hg status -n --change # | sort -u
And to answer your last question, revisions can be shown this way:
hg log --rev "branch('my-branch') and not merge()" --template '{rev}\n'
TIP: I use a hg-alias for this:
[alias]
_lf = ! $HG log --rev "branch(\"$1\") and not merge()" --template '{rev}\0' | xargs -0 -I # hg status -n --change # | sort -u
With mercurial, if you want to get the list of all the files changed in your current branch (changes done of your changeset) you can use these commands: :
hg log --branch $(hg branch) --stat | grep '|' | awk -F\ '{printf ("%s\n", $1)}' | sort -u
Example result:
api/tests/test_my_app.py
docker/run.sh
api/my_app.py
Explanation of the commands:
hg log --branch $(hg branch) --stat
Show revision history of entire repository or files and output diffstat-style summary of changes
hg branch
Show the current branch name
grep '|'
Search for a text pattern, in this case, it is "|"
awk -F\ '{printf ("%s\n", $1)}'
Space separator denotes each field in a record and prints each one in a new line
sort -u
Sort all the printed lines and delete duplicates
When we do hg log -v we see:
changeset: 2639:283fb2da345f
parent: 2638:e06cb712d37b
parent: 2631:d8f619046812
user: joe#pub.com
date: Wed Apr 13 12:29:57 2011 -0400
files: core/src/main/java/com/blah/boards/InvalidRateException.java core/src/main/java/com/blah/boards/InvalidException.java core/src/main/java/com/blah/area/xxx/instructions/AssignInstruction.java core/src/main/java/com/blah/area/xxx/instructions/AutoAssignInstruction.java core/src/main/java/com/blah/area/xxx/instructions/AutoDeliveryInstruction.java
description:
Commiting after merge
Is there a way to output the file in a more readable manner? Something like:
files:
core/src/main/java/com/blah/boards/InvalidRateException.java
core/src/main/java/com/blah/boards/InvalidException.java
core/src/main/java/com/blah/area/xxx/instructions/AssignInstruction.java
core/src/main/java/com/blah/area/xxx/instructions/AutoAssignInstruction.java
core/src/main/java/com/blah/area/xxx/instructions/AutoDeliveryInstruction.java
You can specify your own template via --template option. See hg help templates. You could try e.g.
hg log --template "(...) files:\n{files|stringify|fill76}\n"
If you want just the files list for a single revision you can use hg status --change 2639 which shows the file list prefixed with M, A, R, D prefixed, which you can omit by adding the --no-status flag.
This question is quite old, but anyway, here goes a solution:
hg log -v --template "{files % '{file}\n'}"
Worth checking this: http://www.selenic.com/mercurial/hg.1.html#template-usage
I need to use the hg keyword extension to embed the build date and revision into a source file. Leaving aside the whole "you really don't want to be doing that" argument, how can I do this?
Here's what my source file (lib/foo/version.rb) looks like (which happens to be Ruby, but that's only relevant from the point of view that I don't have a "compile" step in my build which I could do a -DREVISION="$(hg id)" in):
module Foo
VERSION = {
:date => "$Date$",
:changeset => "$Revision$"
}
end
The problem is that $Revision$ and $Date$ are expanded with the changeset and commit date of that file, whereas what I need is the tip changeset and commit date of the whole repository.
I don't see an obvious template I can use in hg help templates, nor does the keyword extension mention anything with global scope. Is what I'm trying to do possible?
You can install a post-commit hook that updates the file:
[hooks]
post-commit = sed -i lib/foo/version.rb \
-e "s|\$Date.*\$|\$Date: $(date)\$|" \
-e "s|\$Version.*\$|\$Version: $(hg id -i)\$|"
You should then probably add the version file to the .hgignore file -- it will change after every commit and thus always be dirty. You could also add a encode filter that will clean up the version file:
[encode]
lib/foo/version.rb = sed -e "s|\$Date.*\$|\$Date\$|" \
-e "s|\$Version.*\$|\$Version\$|"
This script will make Mercurial see the file as clean -- no matter what date and changeset has it really contains, Mercurial will see it as containing un-expanded $Date$ and $Version$ keywords:
$ hg commit -m test
$ hg tip
changeset: 7:df81c9ddc9ad
tag: tip
user: Martin Geisler
date: Wed Apr 06 14:39:26 2011 +0200
summary: test
$ hg status
$ hg cat version.py
date = "$Date$"
version = "$Version$"
$ cat version.py
date = "$Date: Wed Apr 6 14:39:26 CEST 2011$"
version = "$Version: df81c9ddc9ad$"
If you're running your code from a checkout you can invoke hg directly and cache the value. Something like:
module Foo
VERSION = {
:version => system("hg log --template '{note|short}-{latesttag}-{latesttagdistance}' -r .")
}
end
and if you're not running the code from inside a checkout on a system with Mercurial installed, then your deploy script can easily get/use the value -- perhaps by using hg archive to get the tarball to send which then automatically includes a .hg_archive.txt.
I guarantee you there's a prettier way to do this than the keywords extension no matter what your setup is.