Fastest way to check if the current directory is under mercury?
I am trying to speed up a zsh topic request and the hg
checks are a little slower than git
. This results in a slower request when using the plugin hg
.
For git
what we are using git rev-parse --is-inside-work-tree
, which is standard and fairly fast.
For hg
I tried to find a similar command, but nothing is so fast:
-
hg --cwd $PWD root
-
hg summary
-
hg root
-
hg -q stat
All of these commands work, but are not as effective as git rev-parse --is-inside-work-tree
.
And tried this little script which is the best right now. Anything I can do to speed up this script even more?
is_dir_hg() {
local root="$(pwd -P)"
while [[ $root && ! -d $root/.hg ]]
do
root="${root%/*}"
done
echo "$root"
}
Please note that the solution should detect the directory hg
even if we are not in the root directory.
source to share
I doubt that you can do much better than your script unless you write a compiled program that does the equivalent.
Git test, using git rev-parse
, is coded in C and compiled into a simple binary and is therefore very fast. Mercurial is coded in Python, so you pay the overhead of running Python. Moreover, any extensions you load into Mercurial require extension paths and additional loading at runtime, making Mercurial more flexible than Git, but slower.
If you hg root
were fast enough, you could just run both hg root
and git rev-parse --show-toplevel
(and then possibly resolve symlinks) and see which one is closer to the current directory (again with symlinks allowed) if both succeed. Presumably you've already tried this and it wasn't fast enough.
You can use your own path lookup as in the example code. However, instead of searching .hg
you can look like .hg
, and .git
, and stop when you find one. There are many online libraries for many shells, and some of them use this approach.
All methods are error prone, especially because a Mercurial repository can store a Git repository and vice versa (for example, there /path/to/current/working/dir
can be Mercurial at the level current
and Git at the level dir
or vice versa). In the meantime, having a directory is .git
not enough to ensure that you are in the Git working tree. For example, Git considers a directory to be a repository only if:
- It can find the Git directory itself (perhaps using
$GIT_DIR
; Mercurial doesn't have an environment variable overriding the way Git works, if not$GIT_DIR
, start at the current directory and climb up as needed); and - the found Git directory contains a file named
HEAD
; and - the found directory contains a directory
refs
; and -
$GIT_OBJECT_DIRECTORY
indicates a directory, or the found directory contains a directoryobjects/
.
Searching towards the root usually checks and stops mount points, so if it $HOME/foo
is a Git repository, but your current working directory $HOME/foo/bar
is a mount point and it is not a Git repository, Git will not detect $HOME/foo
as a repository. A simple shell path lookup would discover $HOME/foo
how the repository is.
Mercurial, by default, just looks for a directory .hg
in every parent directory, so you're much more solid here.
Note that you can even have one directory with subdirectories .hg
and .git
both being valid repositories (I did this for experimental purposes, it works, it's a little tricky: you'll want to ignore other VCS VCS control files). This is probably not something you need to handle, which is good because there is no right obvious right way to handle it. :-)
source to share