Reputation: 96468
When working in Python (e.g. running a script), how can I find the path of the root of the git repository where the script lives?
So far I know I can get the current path with:
path_to_containing_folder = os.path.dirname(os.path.realpath(__file__))
How can I then find out where the git repository lives?
Upvotes: 51
Views: 65047
Reputation: 3447
I found the other answers too confusing for the task so I made this function to solve the issue. Basically, it loops through the parent directories of the given path and returns the first one that contains ".git" directory. If none found, None is returned.
from pathlib import Path
def find_repo(path):
"Find repository root from the path's parents"
for path in Path(path).parents:
# Check whether "path/.git" exists and is a directory
git_dir = path / ".git"
if git_dir.is_dir():
return path
# Find the repo root where the script is
find_repo(__file__)
Pathlib is part of the standard library (Python 3) so there is no extra dependencies. Gitpython is overkill if this is the only thing you need from it.
Upvotes: 8
Reputation: 48268
This function is generic (not depending on external module or calling git
command).
It searches up from a given path to find the first one containing a .git
directory.
def find_vcs_root(test, dirs=(".git",), default=None):
import os
prev, test = None, os.path.abspath(test)
while prev != test:
if any(os.path.isdir(os.path.join(test, d)) for d in dirs):
return test
prev, test = test, os.path.abspath(os.path.join(test, os.pardir))
return default
Example use:
import os
print(find_vcs_root(os.path.dirname(__file__)))
Or check for other version control:
import os
print(find_vcs_root(os.path.dirname(__file__)), dirs=(".hg", ".git", ".svn"))
Upvotes: 7
Reputation: 18241
Without any external libraries:
import subprocess
def getGitRoot():
return subprocess.Popen(['git', 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE).communicate()[0].rstrip().decode('utf-8')
Upvotes: 16
Reputation: 15202
The GitPython module provides this attribute right out-of-the-box for you:
import git
repo = git.Repo('.', search_parent_directories=True)
repo.working_tree_dir
Upvotes: 49
Reputation: 786
Use the GitPython module http://gitpython.readthedocs.io/en/stable/.
pip install gitpython
Assume you have a local Git repo at /path/to/.git
. The below example receives /path/to/your/file
as input, it correctly returns the Git root as /path/to/
.
import git
def get_git_root(path):
git_repo = git.Repo(path, search_parent_directories=True)
git_root = git_repo.git.rev_parse("--show-toplevel")
print git_root
if __name__ == "__main__":
get_git_root("/path/to/your/file")
Upvotes: 53
Reputation: 15017
I just wrote a small python module for this task: https://github.com/MaxNoe/python-gitpath
Install with pip install git+https://github.com/maxnoe/python-gitpath
Usage:
import gitpath
print(gitpath.root())
print(gitpath.abspath('myfile.txt'))
gitpath.abspath(relative_path)
will return the absolute path on your machine
for a path given relative to the root of the git repository.
The code to get the root is partially derived from Ryne Everetts comment:
from subprocess import check_output, CalledProcessError
from functools import lru_cache
@lru_cache(maxsize=1)
def root():
''' returns the absolute path of the repository root '''
try:
base = check_output('git rev-parse --show-toplevel', shell=True)
except CalledProcessError:
raise IOError('Current working directory is not a git repository')
return base.decode('utf-8').strip()
The caching makes the second call to root()
ca. 3500 times faster (measured with ipython
and %%timeit
)
Upvotes: 8
Reputation: 26565
Looking for a .git
directory will not work in all cases. The correct git command is:
git rev-parse --show-toplevel
Upvotes: 30
Reputation: 1878
I do not know much about python, but I think you could keep going down a directory with
os.path.abspath(os.path.join(dir, '..'))
Until you detect a .git
directory (os.walk
might help)
Upvotes: -1