Pitfalls With Mercurial, ZSH and SSH

| Comments

I ran into a couple of issues trying to clone a mercurial repository over ssh tonight. I’m documenting the solutions here in case they’re useful for anyone else (or me when I forget what I did in 6 months :).

The first issue was that I’m running ssh on a non-standard port and the repository does not reside in my home directory.

The Mercurial Documentation on using SSH does document how to use mercurial with unusual ssh locations, but it’s not obvious in the “hg -v help clone” documentation. You will want to use a ssh:// format URI and also need to make sure to use a “//” if you want to use an absolute path to your repository.

This example shows how to ssh to port 9292 on example.com as user “ted” and get to a repository that’s located at /export/repos on that server.

hg -v clone ssh://ted@example.com:9292//export/repos

If you don’t use a “//” it assumes that the location of the repository is relative to the user’s home directory.

The “-v” (verbose) parameter is also useful for debugging what’s going on as it will show you the SSH command that it’s running under the covers.

The second issue was that after entering the above command and typing in my password, I’d see this error:

remote: zsh: command not found: hg
abort: no suitable response from remote hg!

This seemed strange as I knew I had mercurial installed on my remote computer (that’s how the repository got there in the first place). I’ve got mercurial installed under /usr/local/bin which is a directory that’s added to my PATH environment variable in my .zshrc file (I’m using the ZSH shellinstead of the default bash shell that most people use on OSX).

It turns out that under the covers, mercurial is executing a command like this:

ssh ted@example.com -p 9292 "hg -R /export/repos serve --stdio"

When ssh is directly executing a command on a server instead of logging in, that’s called “non-interactive” mode and it doesn’t source your .zshrc file (I’m assuming that a similar thing happens in bash). To fix this for ZSH, you can create a .zshenv file that WILL get executed by both interactive and non-interactive shells commands and put your PATH in there.

I’m assuming that a similar thing happens in a bash shell (and other shells as well), so if you’re seeing that the “hg” command can’t be found, make sure that you can execute a command like this:

ssh foo@bar.com "hg help"

If it says “command not found: hg”, then you don’t have the correct path for a non-interactive shell.