Determine if directory is under git control
Question:
How can I tell if a given directory is part of a git respository?
(The following is in python, but bash or something would be fine.)
os.path.isdir('.svn')
will tell you if the current directory is controlled by Subversion. Mercurial and Git just have a .hg/.git at the top of the repository, so for hg
I can use
os.system('hg -q stat 2> /dev/null > /dev/null') == 0)
but git status
returns a nonzero (error) exit status if nothing’s changed.
Is iterating up the path looking for .git
myself the best I can do?
Answers:
Well, the directory can also be ignored by the .gitignore file – so you need to check for a .git repository, and if there is one, parse the .gitignore to see whether that directory is indeed in the git repository.
What exactly do you want to do? There may be a simpler way to do this.
EDIT:
Do you mean “Is this directory the root of a GIT repository” or, do you mean “Is this directory part of a GIT repository” ?
For the first one, then just check if there is a .git — since that’s at the root, and you’re done.
For the second one, once you’ve determined that you’re inside a GIT repository, you need to check .gitignore for the subdirectory in question.
In ruby, system('git rev-parse')
will return true if the current directory is in a git repo, and false otherwise. I imagine the pythonic equivalent should work similarly.
EDIT: Sure enough:
# in a git repo, running ipython
>>> system('git rev-parse')
0
# not in a git repo
>>> system('git rev-parse')
32768
Note that there is some output on STDERR when you aren’t in a repo, if that matters to you.
For the record, use git status or similar, this is just for completeness: ๐
Searching upward a tree is no biggie really, in bash you can do this simple one-liner (if you put it on one line…) ๐ Returns 0 if one is found, 1 otherwise.
d=`pwd`
while [ "$d" != "" ]; do
[ -d "$d"/.git ] && exit 0
d=${d%/*}
done
exit 1
will search upward looking for a .git folder.
Just found this in git help rev-parse
git rev-parse --is-inside-work-tree
prints true
if it is in the work tree, false
if it’s in the ‘.git’ tree, and fatal error if it’s neither. Both ‘true’ and ‘false’ are printed on stdout with an exit status of 0, the fatal error is printed on stderr with an exit status of 128.
Add this to your .bash_profile, and your prompt will always show the active git branch and whether you have uncommitted changes.
function parse_git_dirty {
[[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
}
function parse_git_branch {
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* (.*)/[1$(parse_git_dirty)]/"
}
export PS1=' [ 33[0;33m]w[ 33[00m][ 33[01;00m]$(parse_git_branch): ' #PS1='w> '
You’ll see this:
~:
~: cd code/scala-plugin/
~/code/scala-plugin[master*]:
From git help rev-parse again, I think you can do something like :
git rev-parse --resolve-git-dir <directory>
and check if the command returns the directory path itself. According to the manual git rev-parse returns the path to the directory if the argument contains a git repo or is a file which contains the path to a git repo.
It is hard to define what a .git/
repository is
I did a bit of experimenting to see what Git considers as a Git repository.
As of 1.9.1, the minimal directory structure that must be inside a .git
directory for Git to consider it is:
mkdir objects refs
printf 'ref: refs/' > HEAD
as recognized by rev-parse
.
It is also obviously a corrupt repository in which most useful commands will fail.
The morale is: like any other format detection, false positives are inevitable, specially here that the minimal repo is so simple.
If you want something robust, instead of detecting if it is a Git repo, try to do whatever you want to do, and raise errors and deal with them if it fails.
It’s easier to ask forgiveness than it is to get permission.
If you’d prefer to look for a .git
directory, here’s a cute way of doing that in Ruby:
require 'pathname'
def gitcheck()
Pathname.pwd.ascend {|p| return true if (p + ".git").directory? }
false
end
I’m unable to find something similar to ascend in Python.
With gitpython
, you can make a function like this:
import git
...
def is_git_repo(path):
try:
_ = git.Repo(path).git_dir
return True
except git.exc.InvalidGitRepositoryError:
return False
Using git rev-parse --is-inside-work-tree
along with subprocess.Popen
, you can check if “true” is printed from the output indicating the directory does have a git repo:
import subprocess
repo_dir = "../path/to/check/"
command = ['git', 'rev-parse', '--is-inside-work-tree']
process = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=repo_dir,
universal_newlines=True)
process_output = process.communicate()[0]
is_git_repo = str(process_output.strip())
if is_git_repo == "true":
print("success! git repo found under {0}".format(repo_dir))
else:
print("sorry. no git repo found under {0}".format(repo_dir))
How can I tell if a given directory is part of a git respository?
(The following is in python, but bash or something would be fine.)
os.path.isdir('.svn')
will tell you if the current directory is controlled by Subversion. Mercurial and Git just have a .hg/.git at the top of the repository, so for hg
I can use
os.system('hg -q stat 2> /dev/null > /dev/null') == 0)
but git status
returns a nonzero (error) exit status if nothing’s changed.
Is iterating up the path looking for .git
myself the best I can do?
Well, the directory can also be ignored by the .gitignore file – so you need to check for a .git repository, and if there is one, parse the .gitignore to see whether that directory is indeed in the git repository.
What exactly do you want to do? There may be a simpler way to do this.
EDIT:
Do you mean “Is this directory the root of a GIT repository” or, do you mean “Is this directory part of a GIT repository” ?
For the first one, then just check if there is a .git — since that’s at the root, and you’re done.
For the second one, once you’ve determined that you’re inside a GIT repository, you need to check .gitignore for the subdirectory in question.
In ruby, system('git rev-parse')
will return true if the current directory is in a git repo, and false otherwise. I imagine the pythonic equivalent should work similarly.
EDIT: Sure enough:
# in a git repo, running ipython
>>> system('git rev-parse')
0
# not in a git repo
>>> system('git rev-parse')
32768
Note that there is some output on STDERR when you aren’t in a repo, if that matters to you.
For the record, use git status or similar, this is just for completeness: ๐
Searching upward a tree is no biggie really, in bash you can do this simple one-liner (if you put it on one line…) ๐ Returns 0 if one is found, 1 otherwise.
d=`pwd`
while [ "$d" != "" ]; do
[ -d "$d"/.git ] && exit 0
d=${d%/*}
done
exit 1
will search upward looking for a .git folder.
Just found this in git help rev-parse
git rev-parse --is-inside-work-tree
prints true
if it is in the work tree, false
if it’s in the ‘.git’ tree, and fatal error if it’s neither. Both ‘true’ and ‘false’ are printed on stdout with an exit status of 0, the fatal error is printed on stderr with an exit status of 128.
Add this to your .bash_profile, and your prompt will always show the active git branch and whether you have uncommitted changes.
function parse_git_dirty {
[[ $(git status 2> /dev/null | tail -n1) != "nothing to commit (working directory clean)" ]] && echo "*"
}
function parse_git_branch {
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e "s/* (.*)/[1$(parse_git_dirty)]/"
}
export PS1=' [ 33[0;33m]w[ 33[00m][ 33[01;00m]$(parse_git_branch): ' #PS1='w> '
You’ll see this:
~:
~: cd code/scala-plugin/
~/code/scala-plugin[master*]:
From git help rev-parse again, I think you can do something like :
git rev-parse --resolve-git-dir <directory>
and check if the command returns the directory path itself. According to the manual git rev-parse returns the path to the directory if the argument contains a git repo or is a file which contains the path to a git repo.
It is hard to define what a .git/
repository is
I did a bit of experimenting to see what Git considers as a Git repository.
As of 1.9.1, the minimal directory structure that must be inside a .git
directory for Git to consider it is:
mkdir objects refs
printf 'ref: refs/' > HEAD
as recognized by rev-parse
.
It is also obviously a corrupt repository in which most useful commands will fail.
The morale is: like any other format detection, false positives are inevitable, specially here that the minimal repo is so simple.
If you want something robust, instead of detecting if it is a Git repo, try to do whatever you want to do, and raise errors and deal with them if it fails.
It’s easier to ask forgiveness than it is to get permission.
If you’d prefer to look for a .git
directory, here’s a cute way of doing that in Ruby:
require 'pathname'
def gitcheck()
Pathname.pwd.ascend {|p| return true if (p + ".git").directory? }
false
end
I’m unable to find something similar to ascend in Python.
With gitpython
, you can make a function like this:
import git
...
def is_git_repo(path):
try:
_ = git.Repo(path).git_dir
return True
except git.exc.InvalidGitRepositoryError:
return False
Using git rev-parse --is-inside-work-tree
along with subprocess.Popen
, you can check if “true” is printed from the output indicating the directory does have a git repo:
import subprocess
repo_dir = "../path/to/check/"
command = ['git', 'rev-parse', '--is-inside-work-tree']
process = subprocess.Popen(command, stdout=subprocess.PIPE, cwd=repo_dir,
universal_newlines=True)
process_output = process.communicate()[0]
is_git_repo = str(process_output.strip())
if is_git_repo == "true":
print("success! git repo found under {0}".format(repo_dir))
else:
print("sorry. no git repo found under {0}".format(repo_dir))