How to make 'hg log --verbose' show files on multiple lines? - mercurial

By default all files changed in a changeset are on the same line, which makes them very easily to skip one or two, and hard to read.
How to make each file show on its own separate line?

The real way to see information about changed files is to use hg status. This shows the files that were modified in revision 100:
$ hg status -c 100
But if you want to have the log messages as well, then hg log is of course a natural starting point. Unfortunately there is no built-in switch that will make it display one file per line.
However, the output of hg log is controlled by a template system and you can write your own styles for it. The default style is here and you can customize to do what you want by changing
file = ' {file}'
to
file = '{file}\n'
Then save the new style as my-default.style and add
[ui]
style = ~/path/to/my-default.style
to your configuration file. This gives you one file per line and it even works when there are spaces in your file names.
I'm aware of one problem: you lose colors in the hg log output. It turns out that Mercurial is cheating here! It doesn't actually use the default template I showed you when generating log output. It doesn't use any template system at all, it just generates the output using direct code since this is faster. The problem is that the color extension only work with the hard-coded template. When you switch to a custom template and thereby invoke the template engine, you lose the color output.
However, you can recover the colors by inserting the ANSI escape codes directly into your template (on Unix-like systems). Changing
changeset = 'changeset: {rev}:{node|short}\n{branches}...
to
changeset = '\033[33mchangeset: {rev}:{node|short}\033[0m\n{branches}...
does the trick and hard-codes a yellow header line for the changeset. Adjust the changeset_verbose and changeset_quiet lines as well and you'll have colored output with your own template.

The hg template help file has this gem in its examples.
Format lists, e.g. files:
$ hg log -r 0 --template "files:\n{files % ' {file}\n'}"
This works on Windows without any translation.

I believe there is no built-in way to achieve this, but a bit of sed (also available for Windows: http://gnuwin32.sourceforge.net/packages/sed.htm) can help:
hg log --template "Rev: {rev}:{node}\nDate: {date|isodate}\nFiles: {files}\n\n" -l 10 | sed -e '/^Files:/s/ /\n /g'
Output:
Rev: 1:2538bd4661c755ccab9b68e1d5e91144f6f97d33
Date: 2011-12-20 15:47 +0100
Files:
test1.txt
Rev: 2:853a6f3c505308c9babff5a5a2f1e09303f1689c
Date: 2011-12-20 15:44 +0100
Files:
test2.txt
test3.txt
Explanation of sed -e '/^Files:/s/ /\n /g':
/^Files:/ searches for lines starting woth "Files:", and applies the following search and replace just to those line
s/ /\n /g replaces all lines with a newline, followed by the spaces.
This solution won't work when file names contain spaces.

To see all files that changed in a revision, use:
hg status --change REV

hg log --style changelog
OR
hg log --template "Description: {desc}\n" - supported keywords like desc, files etc. are listed here

Related

auto-accepting a Mercurial change chunk

I have a very large repo with thousands of files that can regularly get updated by automatic processes that are out of my control (this is for Unity 3D, for what it's worth).
For example, if I upgrade Unity to a new version, it will reimport all textures and maybe add a line in thousands of .meta files that correspond to a new serialized data that didn't exist previously.
Obviously reviewing thousands of files is terrible. Most of the time though, I can quickly identify a particular diff, and would just like to automatically check all the files that have the same diff, commit to get them out of the way, and see what's left: other diffs that I might not know about.
For example I just commited 4000+ files that all contained this diff:
So the pattern would be easy to find:
- textureFormat: -5
+ textureFormat: -1
I suppose I could write a script, or a TortoiseHg tool to do that, I just have no idea where to begin. I'd need to iterate over all changed files/chunks, match a pattern, commit the chunks...
I know of no tool to do exactly what you want. However I believe it's relatively easy to write a small bash script for such or use the command line:
hg diff --nodates --noprefix -U 0 | grep '^+' | grep -v '+++' | sort | uniq -c
will list you the inserted lines of the current diff in descending order of the number of occurences, thus the most frequently occurring diff first.
With that list you get a list of files which match the newly inserted pattern, for instance
hg files "set:grep('^ textureFormat: -1')"
should give you all files with that pattern (whether it's new or not, though). You probably want to check those files, whether their diff contains anything else:
hg diff "set:grep('^ textureFormat: -1')"
Now you can make use of the results and even exclude single files, if the diff output didn't suit you:
hg commit "set:grep('^ textureFormat: -1') and not 'unwantedFilename.cpp'"
In the above commands I made use of the fileset capability and of hg grep which accepts regular expressions. Check hg help grep, hg help fileset and hg help patterns for a more in-depth explanation.

Mercurial & Keyword ext.: updating keywords when tagging a revision

I'm using Mercurial with the keyword extention, and I'm very pleased with it. Expect one thing, expanding the version tag which is:
Version = {latesttag|nonempty}
All the keywords are expanded as expected on every check in. But when I'm tagging a revision, nothing happens at this moment. I expect/want to expand the tags in all files. Right now the version tag gets updated/expanded on the next commit of a file. I guess, I have to do this with a hook, but i stuck with this.
Any suggestions?
Thank you very much
Roland
Your filter do nothing, because for repository without tags `{latesttag} returns "null" text-string
Keywords in files have "this file" scope, not global, i.e reflect only state at the time of last change of file, and, for tagging (which commit only .hgtags) not changing $Version$ is expected
All the keywords are expanded as expected on every check in
Only for files in this changeset, not included files aren't touched. See at final content of two (originally identical) files in repo
Current version of file: $Version$ and $Revision$
each of which was committed some times separately
>hg log file.txt -l 1
changeset: 5:3ceaea734895
>hg log file2.txt -l 1
changeset: 3:09939c9b8243
file.txt
Current version of file: $Version: v 0.1 $ and $Revision: 3ceaea734895 $
file2.txt
Current version of file: $Version: v 0.1 $ and $Revision: 09939c9b8243 $
If you want to change keywords in all files for every commit, you can|have to include files in questions in every commit (it can be alias, which uses commit -I)

How to add different colors to mercurial template command?

What I want:
A command that prints number of added (+) and removed (-) from change log, where the added portion(+) written in green and deleted portion (-) written in red.
What I have currently:
hg log -T {diffstat} prints what I want (+20/-31:) but in black color.
hg log -T "{label('custom.colorcode', diffstat)} \n" prints the entire diffstat (+20/-31:) in green (my custom.colorcode is set to green in .hgrc)
References:
https://www.mercurial-scm.org/repo/hg/help/templates
Can I add custom colors to mercurial command templates?
I don't believe there is a way for Mercurial to automatically parse the diffstat output and to assign colors to parts of it, but you can use a workaround by doing the parsing yourself. E.g. with the following template:
hg log -T '{sub("(.*): (.*)/(.*)", "\\1: \033[0;32m\\2\033[0m/\033[0;31m\\3\033[0m", diffstat)}\n'
Note that this hardcodes ANSI color escapes (32 for green, 31 for red). If you want to do it with labels, this is also possible, but much slower (because diffstat has to be calculated multiple times). This approach can still be useful for other keywords, so I'm explaining it anyway. Here is an example template:
{sub(":.*","",diffstat)}: \
{label("diff.inserted", sub(".*([+][0-9]+).*", "\\1", diffstat))}/\
{label("diff.deleted", sub(".*(-[0-9]+).*", "\\1", diffstat))}
The easiest way to use such a long template is to put it in a file (for example ~/.hgtemplates/diffstat) and then use hg log -T ~/.hgtemplates/diffstat. If a template contains a slash or backslash and corresponds to an existing file, Mercurial will look at the contents of the file instead. Long templates can also be put in the templates section of your .hgrc, e.g.:
[templates]
diffstat = "{sub(":.*","",diffstat)}: \
{label("diff.inserted", sub(".*([+][0-9]+).*", "\\1", diffstat))}/\
{label("diff.deleted", sub(".*(-[0-9]+).*", "\\1", diffstat))}\n"
And can then be used with the corresponding name (e.g. hg log -T diffstat).

how do I open files with conflicts during git/mercurial merge in textmate/sublime

how do I open from terminal window only files with conflicts during git/mercurial merge in textmate/sublime text2 editors
You can use the following to open all files with git merge conflicts in sublime text:
git diff --name-only | uniq | xargs subl
I wanted to add another answer. git diff --name-only will give you all files that have diffs. This is why sometimes it will yield duplicate entries because it marks the file as "modified" as well as in a merge conflict state. Piping it into uniq is a good solution for this but git diff --name-only will also include files you might have purposely changed so it doesn't actually filter only files with merge conflicts. When you are in the middle of rebasing, this is probably not going to happen often though I would say in most cases #StephanRodemeier's answer works.
However, what you can do though is leverage the --diff-filter option which assigns a states to files. See more in the docs
--diff-filter=[(A|C|D|M|R|T|U|X|B)…​[*]]
Select only files that are Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, …​) changed (T), are Unmerged (U), are Unknown (X), or have had their pairing Broken (B). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected.
It seems when files are in the both modified state, the diff status gets set to U (Unmerged) and M (Modified) so you can filter for only Unmerged files.
git diff --diff-filter=U --name-only | xargs subl
Should work without needing to pipe into uniq
Another thing you can consider is simply setting your editor as the difftool i.e. for VSCode documentation specifies how to do this by adding this to your .gitconfig
[diff]
tool = default-difftool
[difftool "default-difftool"]
cmd = code --wait --diff $LOCAL $REMOTE

How to create a PATCH file for the binary difference output file

I want to know how to create a PATCH for the difference file I got by comparing two binary files.
$cmp -l > output file name
I checked for text files 'diff" can be used to compare and generate a PATCH file
$ diff -u oldFile newFile > mods.diff # -u tells diff to output unified diff format
I want to apply the PATCH on the old binary image file to get my new binary image file.
Diff and Patch are designed to work with text files, not arbitrary binary data. You should use something like bsdiff instead.
If your repository, or package is using git you can make binary diff with
git diff --patch --binary old_dir patched_dir
Of course you can also use it with commits
git diff --patch --binary commit1 commit2
JDIFF is a program that outputs the differences between two (binary) files.
Also you can use therdiff command.
If you still want to use diff & patch. Here is a way...
Write a c program yourself to insert a newline character at the end of every 512/1024/your_choice bytes (this is just to fool the diff as it compares the files line by line). Run this script on your two input files.
Then run 'diff -au file1 file2 > mod.diff (you will get the patch here)'
Patching is simple 'patch < mod.diff'
Than again write a program to remove the newlines from the binary file. That is all...