Find the root of the git repository where the file lives

Question:

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?

Answers:

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)

Answered By: PlasmaPower

Looking for a .git directory will not work in all cases. The correct git command is:

git rev-parse --show-toplevel
Answered By: michas

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)

Answered By: MaxNoe

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")
Answered By: quat

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"))
Answered By: ideasman42

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
Answered By: CivFan

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')
Answered By: rouble

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.

Answered By: miksus
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.