George Kulakowski
George Kulakowski

Reputation: 41

How can I (quickly) tell if $PWD is in a git/hg repository?

I want to test if my present directory is part of a git/hg/etc. repository, as part of my shell prompt. Searching around a bit, I found this setup which has similar tests to what I want. And so I guess my question is: what are the fastest tests to see if I am in a git, hg, darcs, or svn repository? In particular, in the link I gave he uses git branch > /dev/null and hg root > /dev/null; are those the fastest?

Upvotes: 4

Views: 404

Answers (5)

dimir
dimir

Reputation: 793

Don't know if it will be helpful for you but here is my PS1 for git repository:

$ egrep 'PS|RESET|PS1' ~/.bashrc
PS_AT='\[\033[1;30m\]'
PS_PWD='\[\033[1;34m\]'
RESET='\[\033[m\]'
export PS1='$(branch=$(git branch 2>/dev/null | grep "^*" | cut -d" " -f2-); [ -n "$branch" ] && (repo=$(git config --get remote.origin.url 2>/dev/null); ([ -n "$repo" ] && echo $repo || echo origin) | sed -r "s,/?.git$,," | awk -F"/" "{print \\$NF}" | xargs -r -I r echo -ne "\[\033[1;34m\][\[\033[0;34m\]r\[\033[1;34m\]:"; echo $branch | xargs -r -I r echo -e "\[\033[0;33m\]r\[\033[1;34m\]]\[\033[m\] "))'"\u${PS_AT}@${RESET}\h${PS_AT}:${PS_PWD}\W${PS_AT}\$${RESET} "

Yes, it's a bit crazy to call 'git branch' on every directory change but I've been living with that for ages without a problem. :-)

Upvotes: 0

qneill
qneill

Reputation: 1704

If you look at what git does, it's probably the simplest (nothing to write), fastest (it's written in C) and surest way (you're using the official algorithm).

In short 'git branch 2>/dev/null' is the way to go.

From a git working directory:

$ cd /d/qneill/gcc
$ strace -e trace=access,chdir,stat git branch 2>&1 | egrep -v '/etc/|/lib/'
stat(".git", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
access(".git/objects", X_OK)            = 0
access(".git/refs", X_OK)               = 0
access("/home/qneill/.gitconfig", R_OK) = 0
stat(".git", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
access(".git/config", R_OK)             = 0
access("/home/qneill/.gitconfig", R_OK) = 0
access(".git/config", R_OK)             = 0
access("/home/qneill/.gitconfig", R_OK) = 0
access(".git/config", R_OK)             = 0
stat(".git/refs/remotes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
. . .

From a non-git directory:

$ mkdir -p /tmp/d1; cd /tmp/d1; pwd
/tmp/d1
$ strace -e trace=access,chdir,stat git branch 2>&1 | egrep -v '/etc/|/lib/'
stat(".git", 0x7fff32570650)            = -1 ENOENT (No such file or directory)
access(".git/objects", X_OK)            = -1 ENOENT (No such file or directory)
access("./objects", X_OK)               = -1 ENOENT (No such file or directory)
chdir("..")                             = 0
stat(".git", 0x7fff32570650)            = -1 ENOENT (No such file or directory)
. . .
fatal: Not a git repository (or any of the parent directories): .git

IMO git-show should provide a way to introspect about the given repository and working directory, because of how GIT_WORK_TREE and GIT_DIR work.

Upvotes: 0

Testing for the existence of .git, .hg and so on is a very good approximation (definitely good enough for a prompt). But you can't just test in the current directory, you need to check parent directories as well. The following (untested) bash/ksh/zsh snippet sets vc to the version control system the current directory appears to be under, or to the empty string if it can't find one.

vc=
if [ -d .svn ]; then
  vc=svn
elif [ -d CVS ]; then
  vc=cvs
else
  d=..
  while ! [ "$d" -ef / ]; do
    if [ -d "$d/.bzr" ]; then
      vc=bzr
    elif [ -d "$d/_darcs" ]; then
      vc=darcs
    elif [ -d "$d/.git" ]; then
      vc=git
    elif [ -d "$d/.hg" ]; then
      vc=hg
    fi
    if [ -n "$vc" ]; then break; fi
    d=$d/..
  done
fi

Upvotes: 1

Someguy
Someguy

Reputation: 96

morning, I had this terrible piece, because I could not remember.

#!/bin/bash -
MYPATH=/home/user

fail() {
echo "$1"
exit 1
}

test -d $MYPATH || fail "Can't chdir to $MYPATH, exiting .."
for x in $(locate $MYPATH | egrep "\.svn|CVS|\.hg|\.git" | awk -F '/' '{print $4}' | sort -u); do

 if [ -n "$x" ]; then

    find $x -name  "\.svn" -o -name "CVS" -o -name "\.hg" -o -name "\.git" -type d| \
    awk -v v="$MYPATH" -F '/' '{print v,$1,$2,$3}'| \
    egrep "\.svn|CVS|\.hg|\.git";

 else

   fail "Hm, no repositories found"

 fi

done

gives:

/home/user src onioncat .svn

/home/user src sqlmap .svn

/home/user src airprobe .git

/home/user src nagios CVS

Might not be for you, as you want it in the prompt. (I hate overloading my prompt :)

Upvotes: 0

moinudin
moinudin

Reputation: 138407

If you really need performance, you could check for .git or .hg directories. But this of course is not going to be 100% reliable.

Upvotes: 2

Related Questions