Amelio Vazquez-Reina
Amelio Vazquez-Reina

Reputation: 96468

Find the root of the git repository where the file lives

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

Answers (8)

miksus
miksus

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

ideasman42
ideasman42

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

rouble
rouble

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

CivFan
CivFan

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

quat
quat

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

MaxNoe
MaxNoe

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

michas
michas

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

PlasmaPower
PlasmaPower

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

Related Questions