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.

+4


source to share


2 answers


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 directory objects/

    .

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. :-)

+5


source


I would use hg id

that also usefully sets the return code.



0


source







All Articles