TortoiseHg (Mercurial) normally uses TortoisePLink/plink to connect via SSH. Different SSH hosts have different settings, including private keys and ports to connect to.
In its global hgrc
settings, TortoiseHg lets you specify different logins and passwords for different hosts, but not private keys nor ports.
How to override SSH port/private key globally, but only for some hosts and not others?
I'll list a number of imperfect approaches for completeness, then give the one I've found that I think is better:
Mercurial ssh
setting can be used to pass additional params to plink globally:
ssh=path\to\TortoisePLink.exe -i "private1.key" -i "private2.key" -P port
But the same ssh
string is used for all hosts, so different ports cannot be configured. And while you can list several private keys, some servers will refuse all but the first one.
plink comes from putty package, and putty can store server configurations (sessions) in the registry, HKEY_CURRENT_USER\SOFTWARE\SimonTatham\PuTTY\Sessions
. plink can use these if you use a session name in the host place, e.g. ssh://session-name/path/to/repository
.
But for some reason plink ignores stored port settings and will use the default SSH port. Probably a bug, but it's unfixed.
You can override ssh
for each repository by creating a local .hgrc
file, but it's unwieldy if you have lots of repos.
You can specify ports explicitly in the remote repository address:
ssh://server.name:port/path/to/repository
Same problems as with local hgrcs.
After struggling with this for a while, I have finally thought of something that seems to work. We can wrap TortoisePLink in a script that adds per-server params:
ssh=path\to\TortoisePLinkWrapper.cmd <all the normal common params>
Create a file called username@host.name.cfg
for every host you want to override, and its contents should be additional params to pass to TortoisePLink, e.g.:
-P 1234 -i "path\to\key.file"
Place this in the same dir:
@echo off
set SERVER_PARAMS=
set SERVER_NAME=
call :find_server %*
if "%SERVER_NAME%"=="" goto :call_plink
set "SERVER_CONFIG_FILE=%~dp0%SERVER_NAME%.cfg"
if NOT EXIST "%SERVER_CONFIG_FILE%" goto :call_plink
set /p SERVER_PARAMS=<"%SERVER_CONFIG_FILE%"
:call_plink
rem TortoisePLink ignores some params if you pass them after the ssh command, so add extra commands before the bulk of them
"%ProgramFiles%\TortoiseHg\lib\TortoisePLink.exe" %SERVER_PARAMS% %*
exit /B
:find_server
if [%1]==[] exit /B
rem Known arguments which eat some more positions
rem https://putty.org.ru/htmldoc/chapter7.html
if [%1]==[-P] shift & shift & goto :find_server
if [%1]==[-l] shift & shift & goto :find_server
if [%1]==[-pw] shift & shift & goto :find_server
if [%1]==[-proxycmd] shift & shift & goto :find_server
if [%1]==[-sercfg] shift & shift & goto :find_server
if [%1]==[-D] shift & shift & goto :find_server
if [%1]==[-L] shift & shift & goto :find_server
if [%1]==[-R] shift & shift & goto :find_server
if [%1]==[-i] shift & shift & goto :find_server
if [%1]==[-hostkey] shift & shift & goto :find_server
if [%1]==[-m] shift & shift & goto :find_server
if [%1]==[-nc] shift & shift & goto :find_server
if [%1]==[-sshlog] shift & shift & goto :find_server
if [%1]==[-sshrawlog] shift & shift & goto :find_server
set "PARAM=%~1"
rem Other flag argument:
if "%PARAM:~0,1%"=="-" shift & goto :find_server
rem First positional argument
set "SERVER_NAME=%~1"
exit /B