2010-01-11 23 views
59

¿Cómo puedo saber si un directorio determinado es parte de un repositorio git?Determinar si el directorio está bajo el control de git

(Lo siguiente es en python, pero bash o algo estaría bien.)

os.path.isdir('.svn') 

le dirá si el directorio actual es controlado por la subversión. Mercurial y Git simplemente una .hg/.git en la parte superior del depósito, por lo que para hg puedo usar

os.system('hg -q stat 2> /dev/null > /dev/null') == 0) 

pero git status devuelve un distinto de cero (error) el código de salida si nada ha cambiado.

¿Está iterando en el camino en busca de .git mismo lo mejor que puedo hacer?

+4

Doesnt 'git status' se quejan de no ser parte de un acuerdo de recompra si usted lo llama en un camino? Creo que capturar eso y comparar una o dos líneas de texto sería mejor que repetir una copia de seguridad del árbol. – prodigitalson

+2

sí, salir del estado 128 en mi máquina. – falstro

+0

La velocidad no es un gran problema, excepto que me gusta hacer las cosas bien cuando sea posible. Tal vez solo itere los directorios principales. – Grumdrig

Respuesta

42

En ruby, system('git rev-parse') devolverá verdadero si el directorio actual está en un repositorio git, y de lo contrario será falso. Me imagino que el equivalente pitonico debería funcionar de manera similar.

EDIT: Efectivamente:

# in a git repo, running ipython 
>>> system('git rev-parse') 
0 

# not in a git repo 
>>> system('git rev-parse') 
32768 

en cuenta que hay alguna salida en stderr cuando no está en una cesión temporal, si lo que importa a usted.

+3

Gracias! Voy con 'os.path.isdir (". Git ") o os.system ('git rev-parse 2>/dev/null>/dev/null') == 0' – Grumdrig

+6

@grumdrig os.path .isdir (". git") no funcionará, ya que .git puede ser un archivo normal que solo contiene una ruta a un directorio de git. Usa git rev-parse. –

+0

Pero estaría bien, porque entonces entraría la cláusula 'o' que llama a 'git rev-parse'. (Ese' o' está en código; no describe dos alternativas que estoy considerando) – Grumdrig

4

Bueno, el directorio también puede ser ignorado por el archivo .gitignore, por lo que debe buscar un repositorio .git, y si hay uno, analizar el .gitignore para ver si ese directorio está realmente en el repositorio git .

¿Qué es exactamente lo que quieres hacer? Puede haber una manera más simple de hacer esto.

EDIT: ¿Quiere decir "Es este directorio la raíz de un repositorio GIT" o, quiere decir "¿Es este directorio parte de un repositorio GIT"?

Para la primera, simplemente comprueba si hay un .git, ya que está en la raíz, y listo. Para el segundo, una vez que haya determinado que está dentro de un repositorio de GIT, debe marcar .gitignore para el subdirectorio en cuestión.

+0

Tengo una herramienta de python que engloba varios programas de control de versiones que uso, por lo que puedo obtener el estado, por ejemplo, independientemente de qué VC se use. Git es una nueva adición para mí. No necesito ser tan robusto como para considerar .gitignore, realmente. – Grumdrig

+0

Este último.[15 caracteres:] – Grumdrig

+0

Mantenerse consistente con su método actual es probablemente el mejor (a menos que, por supuesto, su herramienta haga algo diferente para cada VCS). Probablemente, a largo plazo, sea más fácil seguir el sistema de recorrido del directorio para descubrir qué es qué, y luego ir a acciones personalizadas, si es necesario. – Trevoke

4

Para el registro, el estado de uso git o similares, esto es simplemente para la corrección: :)

en busca de un árbol hacia arriba es que no es problema de verdad, en bash que puede hacer este sencillo de una sola línea (si lo pones en una línea ...);) Devuelve 0 si se encuentra uno, 1 en caso contrario.

d=`pwd` 
while [ "$d" != "" ]; do 
    [ -d "$d"/.git ] && exit 0 
    d=${d%/*} 
done 
exit 1 

buscará hacia arriba buscando una carpeta .git.

+0

Me gusta éste. Ty. – lzap

+0

Hmmmm loops para mí. Tengo que hacerlo: while ["$ d"! = ""]; do – lzap

+0

@lzap; estás en lo correcto ../a/b/c se convierte en/a/b se vuelve/a se convierte en nada. – falstro

78

acaba de encontrar esto en git help rev-parse

git rev-parse --is-inside-work-tree 

impresiones true si es en el árbol de trabajo, false si está en el árbol '.git', y un error grave si se trata de ninguno de ellos. Tanto 'verdadero' como 'falso' se imprimen en stdout con un estado de salida de 0, el error fatal se imprime en stderr con un estado de salida de 128.

+0

Para comprobar si una carpeta está en git, incluso si la carpeta no existe utilicé: '\' cd "# {dir}" && git rev-parse --is-inside-work-tree \ ''. Devuelve "verdadero" si está bajo el control de git. Si existe una carpeta pero no debajo de git o si la carpeta no existe, devuelve "". – peterept

+0

En realidad, 'git rev-parse --is-inside-work-tree' permite saber dónde estamos dentro de un directorio de Git. Devolverá true en directy de trabajo, false si está en la carpeta .git o en un repositorio simple. – Dereckson

+2

¿Por qué esta respuesta obtuvo tantos votos positivos? La respuesta es bastante antigua, así que tal vez cambió el comportamiento en git. Respondo por la versión de Git 1.7.1. "git rev-parse --is-inside-work-tree" solo muestra verdadero, si el directorio está jerárquicamente bajo un directorio que está controlado por git. PERO, pero no se puede deducir que el directorio que estamos buscando está bajo control de git, lo que significa que se ejecutó "git add" en este directorio. – user637338

1

Agregue esto a .bash_profile, y su mensaje siempre mostrará la rama activa de git y si tiene cambios no confirmados.

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=' \[\033[0;33m\]\w\[\033[00m\]\[\033[01;00m\]$(parse_git_branch): ' #PS1='\w> ' 

Usted verá esto:

~: 
~: cd code/scala-plugin/ 
~/code/scala-plugin[master*]: 
+1

No utilice comandos de porcelana (interfaz de usuario) en las secuencias de comandos: la salida puede cambiar. Utilice 'git rev-parse' y' git symbolic-ref' en su lugar. Consulte también la función '__git_ps1' en 'contrib/completion/git-completion.bash' –

1

De git help rev-parse de nuevo, creo que se puede hacer algo como:

git rev-parse --resolve-git-dir <directory> 

y comprobar si el comando devuelve la ruta del directorio en sí. Según el manual, git rev-parse devuelve la ruta al directorio si el argumento contiene un git repo o es un archivo que contiene la ruta a un git repo.

2

Hice un poco de experimentación para ver lo que Git considera como un repositorio de Git.

A partir de 1.9.1, la mínima estructura de directorios que deben estar dentro de un directorio .git de Git a tener en cuenta es:

mkdir objects refs 
printf 'ref: refs/' > HEAD 

como se reconoce en rev-parse.

También es obviamente un repositorio corrupto en el que la mayoría de los comandos útiles fallarán.

La moral es: como cualquier otra detección de formato, los falsos positivos son inevitables, especialmente aquí que el repositorio mínimo es tan simple.

Si desea algo robusto, en lugar de detectar si se trata de un repositorio de Git, intente hacer lo que quiera, y plantee errores y trate con ellos si falla.

Es más fácil pedir perdón que obtener permiso.

+1

Esto es exacto. El código de Git relevante se puede encontrar en [directorio_de_grupo_i] (https://github.com/git/git/blob/57dd3dd/setup.c#L297) y [validate_headref] (https://github.com/git/git /blob/57dd3dd/path.c#L636). –

-1

Si prefiere buscar un directorio .git, aquí es una manera linda de hacer eso en Ruby:

require 'pathname' 

def gitcheck() 
    Pathname.pwd.ascend {|p| return true if (p + ".git").directory? } 
    false 
end 

Soy incapaz de encontrar algo similar a ascender en Python.

5

Con gitpython, se puede hacer una función como esta:

import git 

... 

def is_git_repo(path): 
    try: 
     _ = git.Repo(path).git_dir 
     return True 
    except git.exc.InvalidGitRepositoryError: 
     return False 
Cuestiones relacionadas