¿Hay alguna manera de get el directory raíz de git en un command?

Mercurial tiene una forma de imprimir el directory raíz (que contiene .hg) a través de

hg root 

¿Hay algo equivalente en git para get el directory que contiene el directory .git?

Sí:

 git rev-parse --show-toplevel 

La página man para git-config (bajo Alias ) dice:

Si la expansión de alias está precedida por un signo de exclamación, se tratará como un command de shell. Por ejemplo, al definir "alias.new =! Gitk –all –n ORIG_HEAD", la invocación "git new" es equivalente a ejecutar el command de shell "gitk –all –n ORIG_HEAD". Tenga en count que los commands de shell se ejecutarán desde el directory de nivel superior de un repository, que puede no ser necesariamente el directory actual.

Entonces, en UNIX puedes hacer:

 git config --global --add alias.root '!pwd' 

¿Recientemente se ha agregado " git rev-parse to --show-toplevel a " git rev-parse o por qué nadie lo menciona?

De la página de manual de git rev-parse :

  --show-toplevel Show the absolute path of the top-level directory. 

¿Qué tal " git rev-parse --git-dir "?

 F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir F:/prog/git/test/copyMerge/.git 

La opción --git-dir parece funcionar.

De la página de manual de git rev-parse :

 --git-dir Show $GIT_DIR if defined else show the path to the .git directory. 

Puedes verlo en acción en esta secuencia de commands de git setup-sh .

Si ya está en el nivel superior o no está en un repository de git, cd $(git rev-parse --show-cdup) lo llevará a su casa (solo cd). cd ./$(git rev-parse --show-cdup) es una forma de corregir eso.

Para escribir una respuesta simple aquí, para que podamos usar

 git root 

para hacer el trabajo, simplemente configura tu git usando

 git config --global alias.root "rev-parse --show-toplevel" 

y luego es posible que desee agregar lo siguiente a su ~/.bashrc :

 alias cdroot='cd $(git root)' 

para que pueda usar cdroot para ir a la parte superior de su repository.

Para calcular la ruta absoluta del directory raíz de git actual, digamos para usar en un script de shell, use esta combinación de readlink y git rev-parse:

 gitroot=$(readlink -f ./$(git rev-parse --show-cdup)) 

git-rev-parse --show-cdup te da el número correcto de ".." s para llegar a la raíz desde tu cwd, o la cadena vacía si estás en la raíz. Luego anteponga "./" para tratar el caso de cadena vacía y use readlink -f para traducir a una ruta completa.

También puede crear un command git-root en su PATH como script de shell para aplicar esta técnica:

 cat > ~/bin/git-root << EOF #!/bin/sh -e cdup=$(git rev-parse --show-cdup) exec readlink -f ./$cdup EOF chmod 755 ~/bin/git-root 

(Lo anterior se puede pegar en un terminal para crear git-root y establecer bits de ejecución, el script real se encuentra en las líneas 2, 3 y 4.)

Y luego podrías ejecutar git root para get la raíz de tu tree actual. Tenga en count que en el script de shell, use "-e" para hacer que el shell salga si el rev-parse falla para que pueda get correctamente el estado de salida y el post de error si no se encuentra en un directory de git.

Como otros han notado, el núcleo de la solución es usar git rev-parse --show-cdup . Sin embargo, hay algunos casos extremos que abordar:

  1. Cuando el cwd ya es la raíz del tree de trabajo, el command produce una cadena vacía.
    En realidad produce una línea vacía, pero la sustitución de command elimina el salto de la línea final. El resultado final es una cadena vacía.

    La mayoría de las respuestas sugieren anteponer la salida con ./ para que una salida vacía se convierta en "./" antes de alimentar a cd .

  2. Cuando GIT_WORK_TREE se establece en una location que no es la principal del cwd, la salida puede ser una ruta de acceso absoluta.

    El anteponer ./ es incorrecto en esta situación. Si a ./ se antepone a una ruta absoluta, se convierte en una ruta relativa (y solo se refieren a la misma location si la cwd es el directory raíz del sistema).

  3. La salida puede contener espacios en blanco.

    Esto realmente solo se aplica en el segundo caso, pero tiene una solución fácil: use comillas dobles alnetworkingedor de la sustitución del command (y cualquier uso posterior del valor).

Como han notado otras respuestas, podemos hacer cd "./$(git rev-parse --show-cdup)" , pero esto se rompe en el segundo caso marginal (y el tercer caso marginal si dejamos fuera las comillas dobles).

Muchas shells tratan cd "" como no-operativa, entonces para esas shells podemos hacer cd "$(git rev-parse --show-cdup)" (las comillas dobles protegen la cadena vacía como un argumento en la primera caja de borde y preservar espacios en blanco en el tercer caso de borde). POSIX dice que el resultado de cd "" no está especificado, por lo que puede ser mejor evitar hacer esta suposition.

Una solución que funciona en todos los casos anteriores requiere una testing de algún tipo. Hecho explícitamente, podría verse así:

 cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup" 

No se realiza un cd para la primera caja de borde.

Si es aceptable ejecutar cd . para el primer caso de borde, entonces el condicional se puede hacer en la expansión del parámetro:

 cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}" 

Para modificar la respuesta de "git config" solo un poco:

 git config --global --add alias.root '!pwd -P' 

y limpiar el path Muy agradable.

Por si acaso, si estás alimentando esta ruta al propio Git, utiliza :/

 # this adds the whole working tree from any directory in the repo git add :/ # and is equal to git add $(git rev-parse --show-toplevel) 

Si estás buscando un buen alias para hacer esto, además de no explotar el cd si no estás en un directory de git:

 alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"' 

Este alias de shell funciona ya sea que esté en un subdirectory git o en el nivel superior:

 alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`' 

actualizado para usar syntax moderna en lugar de backticks:

 alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)' 

Soluciones breves que funcionan con submodules, en ganchos y dentro del directory .git

Aquí está la respuesta corta que la mayoría querrá:

 r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}" 

Esto funcionará en cualquier parte de un tree de trabajo de git (incluido dentro del directory .git ), pero supone que los directorys del repository se llaman .git (que es el valor pnetworkingeterminado). Con los submodules, esto irá a la raíz del depósito que contiene más externo.

Si desea llegar a la raíz del submodule actual, use:

 echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) )) 

Para ejecutar fácilmente un command en la raíz de su submodule, debajo de [alias] en su .gitconfig , agregue:

 sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f" 

Esto le permite hacer cosas fácilmente como git sh ag <string>

Solución robusta que admite directorys .git o $GIT_DIR nombre diferente o externos.

Tenga en count que $GIT_DIR puede apuntar a un lugar externo (y no llamarse .git ), de ahí la necesidad de una verificación posterior.

Pon esto en tu .bashrc :

 # Print the name of the git working tree's root directory function git_root() { local root first_commit # git displays its own error if not in a repository root=$(git rev-parse --show-toplevel) || return if [[ -n $root ]]; then echo $root return elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then # We're inside the .git directory # Store the commit id of the first commit to compare later # It's possible that $GIT_DIR points somewhere not inside the repo first_commit=$(git rev-list --parents HEAD | tail -1) || echo "$0: Can't get initial commit" 2>&1 && false && return root=$(git rev-parse --git-dir)/.. && # subshell so we don't change the user's working directory ( cd "$root" && if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then pwd else echo "$FUNCNAME: git directory is not inside its repository" 2>&1 false fi ) else echo "$FUNCNAME: Can't determine repository root" 2>&1 false fi } # Change working directory to git repository root function cd_git_root() { local root root=$(git_root) || return # git_root will print any errors cd "$root" } 

git_root escribiendo git_root (después de reiniciar su shell: exec bash )

 alias git-root='cd \`git rev-parse --git-dir\`; cd ..' 

Todo lo demás falla en algún momento, ya sea yendo al directory de inicio o fallando miserablemente. Esta es la forma más rápida y más corta de volver al GIT_DIR.

Aquí hay un script que he escrito que maneja ambos casos: 1) repository con un espacio de trabajo, 2) repository vacío.

https://gist.github.com/jdsumsion/6282953

git-root (file ejecutable en su ruta):

 #!/bin/bash GIT_DIR=`git rev-parse --git-dir` && ( if [ `basename $GIT_DIR` = ".git" ]; then # handle normal git repos (with a .git dir) cd $GIT_DIR/.. else # handle bare git repos (the repo IS a xxx.git dir) cd $GIT_DIR fi pwd ) 

Espero que esto sea útil.

 $ git config alias.root '!pwd' # then you have: $ git root 

git-extras

agrega $ git root
ver https://github.com/tj/git-extras/blob/master/Commands.md#git-root

 $ pwd .../very-deep-from-root-directory $ cd `git root` $ git add . && git commit 

Disponibilidad de git-extas

Tuve que resolver esto yo mismo hoy. Lo resolvió en C # como lo necesitaba para un progtwig, pero creo que se puede volver a escribir. Considera este dominio público.

 public static string GetGitRoot (string file_path) { file_path = System.IO.Path.GetDirectoryName (file_path); while (file_path != null) { if (Directory.Exists (System.IO.Path.Combine (file_path, ".git"))) return file_path; file_path = Directory.GetParent (file_path).FullName; } return null; }