I'm trying to speed up my zsh theme prompt and hg
checks are a bit slower than git
's. That result in a slower prompt to show when using the hg
plugin.
For git
we use git rev-parse --is-inside-work-tree
which is the standard and pretty fast.
For hg
I've tried to find a similar command but nothing is as fast:
hg --cwd $PWD root
hg summary
hg root
hg -q stat
All these commands work but are not as efficient as git rev-parse --is-inside-work-tree
.
Also tried this little script which is the best one currently. Anything I can do to speed this script even more?
is_dir_hg() {
local root="$(pwd -P)"
while [[ $root && ! -d $root/.hg ]]
do
root="${root%/*}"
done
echo "$root"
}
Note that the solution must detect hg
directory even when we're not in the root directory.
I doubt you can do much better than your script unless you write a compiled program that does the equivalent.
Git's test, using git rev-parse
, is coded in C and compiled to a simple binary and hence runs very quickly. Mercurial's is coded in Python, so you pay the Python startup overhead. Moreover, any extensions you load in Mercurial require searching extension paths and additional run-time loading, which makes Mercurial more flexible than Git, but slower.
If hg root
were fast enough, you could just run both hg root
and git rev-parse --show-toplevel
(and then maybe resolve symbolic links if desired) and see which one is closer to the current directory (again with symbolic links resolved), if both succeed. Presumably you already tried this and it was not fast enough.
You can resort to your own path-searching, as you did in the sample code. Instead of just searching for .hg
, however, you could search for both .hg
and .git
, and stop when you find either one. There are many prompt libraries for many shells and several of them use this approach.
All methods are a bit error-prone, especially because it is possible to have a Git repository within a Mercurial repository and vice versa (e.g., /path/to/current/working/dir
might be Mercurial at the current
level and Git at the dir
level, or vice versa). Meanwhile, the presence of a .git
directory is not sufficient to guarantee that you are in a valid Git work-tree. For instance, Git believes a directory is a repository only if:
$GIT_DIR
; Mercurial does not seem to have an environment variable override the way Git does; if no $GIT_DIR
, start at the current directory and climb as needed); andHEAD
; andrefs
directory; and$GIT_OBJECT_DIRECTORY
points to a directory, or the found directory contains an objects/
directory.The climbing-towards-root search normally tests for, and stops at, mount points, so that if $HOME/foo
is a Git repository, but your current working directory is $HOME/foo/bar
and this is a mount point and this is not a Git repository, Git will not detect $HOME/foo
as a repository. A simple in-shell path search would detect $HOME/foo
as a repository.
Mercurial, by default, just looks for the .hg
directory in each parent directory, so you are on much firmer ground here.
Note that you can even have a single directory that has both .hg
and .git
subdirectories, with both being valid repositories (I have done this for experimental purposes; it works, it is just a bit tricky: you will want to ignore the other VCS's VCS-control files). That's probably not something you need to handle, which is good since there's no right obvious right way to handle it. :-)
I’d use hg id
, which sets the return code usefully as well. At least it’s fast to type :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With