How to set up a different pager and color mode in Mercurial? - mercurial

I set up Mercurial in .hgrc to use less as a pager together with customized colors and templates following this guide:
[pager]
pager = LESS='FSrX' less
[templates]
# ...
[color]
mode=terminfo
This works very nicely and I'd like to keep this for all commands except for hg diff. For this command only I'd like to use a completely different mechanism:
No ANSI escape codes in output.
Use https://github.com/dandavison/delta as a pager.
Is it possible to configure Mercurial this way?

I found a solution here which achieves this setup using the extdiff extension.
[extensions]
hgext.extdiff =
[extdiff]
cmd.delta =
[alias]
diff = delta
Earlier I had this workaround - to create a separate alias:
[alias]
d = !$HG diff "$#" | delta
Unfortunately it's not possible to replace the original diff command this way. While it's possible (although discouraged) to replace a command with an alias, in this case it doesn't work: Invoking $HG diff from a diff alias would cause an infinite loop.

Beware of using manuals for Mercurial from 2014 in 2022, they can be outdated and just irrelevant
Correct using less now as pager will be (without artefacts of pager extension)
[pager]
pager = less -FRX
According to hg help pager in fresh HG (6.2), you can, with active pager, disable using it for some command(s)
You can disable the pager for certain commands by adding them to the pager. Ignore list
i.e. have smth. like
[pager]
ignore = diff
and get diff totally without paging
From the other side (contrary to the above point), you can use --config
set/override config option (use 'section.name=value')
option on calling hg diff (when|if you'll have delta as working pager) and for simplicity create hg-alias for "hg diff with delta" like
ddiff = diff --config pager.pager=delta $#

Related

.hgignore regex syntax to ignore a specific file (e.g. "core") anywhere

Suppose I have a working directory like this:
t.c
core
multicore
test1/core
I want to ignore all "core" files.
If I use "/core$" (4) will get ignored but not (2).
If I use "^core$" (2) will get ignored but not (4)
If I use "core$" (2) and (4) will get ignored but so will (3) which is not what I want.
How do you do this?
planetmaker's answer, "use glob syntax", is simpler and is what I would usually recommend. There is, however, a regexp answer, and a minor flaw in the glob syntax version.
Mercurial uses Python regular expressions, so we have the (alt1|alt2|...) syntax available. Note that these are grouped.1 We can and should use (?:...) to avoid grouping when required, but for .hgignore, the grouping is irrelevant, so it is simpler (and much more readable) to just use the parentheses, and I do so where possible below.
We could just write:
^core$
/core$
to ignore the file core with nothing coming before it (first pattern) and to ignore a file with a name like test1/core (second pattern). This is a fine, but we can compress it a bit more using the alternation syntax. The leading ^ works even in an alternate within a group, as long as it is still, in effect, leading, so:
(^|/)core$
means the same thing and accomplish the job using regexp syntax.
Annoyingly, all of these patterns ignore all files in any directory named core (whether or not we use regexp vs glob syntax):
$ rm core
$ mkdir core
$ touch core/keepme
$ cat .hgignore
syntax: glob
core
$ hg status -A
? .hgignore
? multicore
? t.c
I core/keepme
I test1/core
The problem is that as soon as we say ignore (some pattern that matches a directory named core), if there are files in that directory that are currently untracked, Mercurial ignores them too. You can forcibly add the file—as with Git, once a file is tracked, any ignore-file pattern that matches it becomes irrelevant—but this does not help with additional files we stick into the directory:
$ hg add core/keepme
$ touch core/keep-me-too
$ hg status -A
A core/keepme
? .hgignore
? multicore
? t.c
I core/keep-me-too
I test1/core
Here, regular expressions can prove to be the answer. Python (and Perl) regexps allow "negative lookbehind", i.e., you can say "as long as some pattern does not appear". Hence we can replace the existing .hgignore contents with:
$ cat .hgignore
(?<!^core/).*/core$
and now we have this status:
$ hg status -A
A core/keepme
? .hgignore
? core/keep-me-too
? multicore
? t.c
I test1/core
This particular regular expression depends on the wanted core directory being named core at the top level (^core). If we wanted to keep core directories named core (top level) and a/subsys/core, we would write:
(?<!(^core|^a/subsys/core)/).*/core$
as our regular expression.
Constructing these regexps is something of an art form, and rarely worth a lot of effort. Glob syntax is almost always simpler, and as long as it suffices, I prefer it. It was once significantly slower than regexp syntax but this was fixed back around Mercurial 3.1.
1Grouped, here, means that in Python code, we may use the .groups() method to obtain the parts of the string matched by these parts of the regular expressions. Non-grouped (?:...) expressions do not affect the way .groups() gathers the parts of the strings. As in the paragraph to which this is a footnote, this is more a concern when writing Python (or Perl, or whatever) code, not when using these patterns in .hgignore or other parts of Mercurial.
Try to give the filename using glob syntax:
syntax: glob
core
It gives:
~/hg-test$ hg st -A
M .hgignore
? multicore
I core
I dir1/core

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 make 'hg log --verbose' show files on multiple lines?

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

Managing a pair of files as one in Mercurial

I'm working with small binary files in Mercurial as posted.
This binary files can be dumped as text to make a diff between versions, but the problem is that the files comes in pairs (eg: Form.scx / Form.sct), and I cannot found a way to tell Mercurial to "make a snapshot" (copy to a temporary location) of the other corresponding file when I do an hg ediff.
Just make a quick script and set that as the tool for extdiff. I'm guessing you're on Windows, but whatever the powershell equivalent to this is:
#!/bin/sh
binary-to-text $1 /tmp/$1.sct
binary-to-text $2 /tmp/$2.sct
diff /tmp/$1.sct /tmp/$2.sct
rm /tmp/$1.sct /tmp/$2.sct
That creates, compares, and then deletes the text versions. You'd want to be careful to not overwrite, deal with multiple concurrent invocations, etc.
Then configure a new command to run your script:
[extdiff]
cmd.mydiff = that_script_above.sh
Then you can do things like:
hg mydiff
Ideally you have only the "source" bonary format in your respository, not the text format, as you shouldn't keep generated items in the repo -- because if you update one but not the other you have an inconsistent state. Generating the comparable text files on demand is a better way to go.
As suggested by #Ryan, I ended up with a small batch previous to the diff program:
#echo off
set f1=%1
set f2=%2
::Temporary dir created by hg to copy the snapshot file
set tdir=%~dp1
::Original repository dir
set repo=%~dp2
::Filename extension
set ext=%~x1
::The binary files comes in pairs: scx/sct \ vcx/vct ...
set ex2=%ext:~0,-1%t
::Check if "dumpable" extension
echo %ext% | grep -iE "(vcx|vct|scx|sct|pjx|pjt|frx|frt)" > nul && goto DumpFile
goto diff
:DumpFile
set f1="%tdir%\_Dump1.prg"
set f2="%tdir%\_Dump2.prg"
::Get the pair file from the repository
hg cat %repo%\%~n1%ex2% -o "%~dpn1%ex2%" -R %repo%
::Do the dump, then the diff
MyDumpProgram.exe %1 %f1%
MyDumpProgram.exe %2 %f2%
goto diff
:diff
ExamDiff.exe %f1% %f2%
pause
and then config the batch in %UserProfile%\.hgrc
[extdiff]
cmd.ediff = d:\Utiles\diff2.bat

How to configure Mercurial to use Kompare when merging?

I've tried adding merge=kompare to my ~/.hgrc, but when I run hg merge, it runs kompare, but there's no UI to be seen. Hg says merging path/to/first-file and stays there, actionless.
The kompare.args posted earlier probably wont work. I've had difficulty using Kompare for merging, especially 3-way merges (which are preferred and safe).
BTW, most of the other options are enabled by default I believe, but you can verify with: hg showconfig merge-tools
You are better off using kdiff3. Incase you are on Ubuntu Intrepid, kdiff3 was erroneously removed from the repos - but you can easily compile from source.
You will also need to add a section that explains how to call Kompare. I don't know Kompare, so I don't know what the command line should look like (no guarantees for the kompare.args line), but it should be something like this:
[merge-tools]
kompare.executable = C:\<path...>\kompare.exe
kompare.args = $base $local $other -o $output
kompare.priority = 1
kompare.gui = True
kompare.binary = True
If merges aren't detected correctly, you might want to add
kompare.checkconflicts = True
kompare.checkchanged = True
Kompare does not support 3-way diffs, so it can be used for Visual Diff feature only. Here's the config to make it work:
[merge-tools]
kompare.executable = kompare
kompare.diffargs = -c $parent $child
kompare.gui = True
Note the diffargs field instead of args.