Mercurial tiene una forma de imprimir el directorio raíz (que contiene .hg) a través de
hg root
¿Hay algo equivalente en git para obtener el directorio que contiene el directorio .git?
fuente
Mercurial tiene una forma de imprimir el directorio raíz (que contiene .hg) a través de
hg root
¿Hay algo equivalente en git para obtener el directorio que contiene el directorio .git?
Si:
git rev-parse --show-toplevel
Si desea replicar el comando Git más directamente, puede crear un alias :
git config --global alias.root 'rev-parse --show-toplevel'
y ahora git root
funcionará igual que hg root
.
Nota : en un submódulo, esto mostrará el directorio raíz del submódulo y no el repositorio principal. Si está utilizando Git> = 2.13 o superior, hay una forma en que los submódulos pueden mostrar el directorio raíz del superproyecto. Si su git es más viejo que eso, vea esta otra respuesta.
git config --global alias.exec '!exec '
para poder hacer cosas como git exec make
. Esto funciona porque los alias de shell siempre se ejecutan en el directorio de nivel superior.
hg root
hace. Imprime el directorio de nivel superior de su repositorio desprotegido. No lo cambia a él (y, de hecho, no pudo hacerlo debido a cómo interactúa todo el concepto de directorio actual y su shell).
~/my.proj/foo/bar
y ~/my.proj
tiene un enlace simbólico ~/src/my.proj
, el comando anterior lo moverá a ~/src/my.proj
. Podría ser un problema, si lo que quiera hacer después de eso no es independiente del árbol.
.git
directorio del proyecto .
La man
página de git-config
(bajo Alias ) dice:
Si la expansión de alias tiene como prefijo un signo de exclamación, se tratará como un comando de shell. [...] Tenga en cuenta que los comandos de shell se ejecutarán desde el directorio de nivel superior de un repositorio, que puede no ser necesariamente el directorio actual.
Entonces, en UNIX puedes hacer:
git config --global --add alias.root '!pwd'
.zshrc
, y defino `alias cg =" cd $ (git root) ", la parte $ () se evalúa en el tiempo de origen, y siempre apunta a ~ / dotfiles, ya que ahí es donde está mi zshrc .
¿Se --show-toplevel
ha agregado recientemente git rev-parse
o por qué nadie lo menciona?
Desde la git rev-parse
página del manual:
--show-toplevel
Show the absolute path of the top-level directory.
git-rev-parse
, debido a que su nombre sugiere que se trata de procesar especificaciones de revisión. Por cierto, me gustaría ver un git --work-tree
trabajo similar a git --exec-path[=<path>]
: "Si no se proporciona ninguna ruta, git imprimirá la configuración actual"; al menos, en mi opinión, sería un lugar lógico para buscar esa característica.
root = rev-parse --show-toplevel
en su gitconfig.
git config --global alias.root "rev-parse --show-toplevel"
y luego git root
podrá hacer el trabajo
git rev-parse --show-toplevel
funciona cuando lo probé en un submódulo. Imprime el directorio raíz del submódulo git. ¿Qué imprime para ti?
--show-cdup
a --show-top-level
en febrero de 2011 (después de que se envió esta respuesta).
¿Qué tal " git rev-parse --git-dir
"?
F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir
F:/prog/git/test/copyMerge/.git
los --git-dir
opción parece funcionar.
Desde la página del 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 este git setup-sh
script .
Si está en una carpeta de submódulos, con Git> = 2.13 , use :
git rev-parse --show-superproject-working-tree
Si está utilizando git rev-parse --show-toplevel
, asegúrese de que sea con Git 2.25+ (Q1 2020) .
.git
si ya está en el directorio raíz. (Al menos, lo hace en msysgit.)
Para escribir una respuesta simple aquí, para que podamos usar
git root
para hacer el trabajo, simplemente configure su git usando
git config --global alias.root "rev-parse --show-toplevel"
y luego puede agregar lo siguiente a su ~/.bashrc
:
alias cdroot='cd $(git root)'
para que puedas usar cdroot
para ir a la parte superior de tu repositorio.
Si ya estás en el nivel superior o no en un repositorio git cd $(git rev-parse --show-cdup)
te llevará a casa (solo cd). cd ./$(git rev-parse --show-cdup)
es una forma de arreglar eso.
cd "$(git rev-parse --show-cdup)"
. Esto funciona porque cd ""
no te lleva a ningún lado, en lugar de regresar $HOME
. Y es una buena práctica citar las invocaciones de $ () de todos modos, en caso de que generen algo con espacios (sin embargo, este comando no lo hará en este caso).
$PWD
. Este ejemplo resolverá la raíz de git en $PWD
lugar de realpath $PWD
.
Para calcular la ruta absoluta del directorio raíz 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
le da el número correcto de ".." para llegar a la raíz desde su cwd, o la cadena vacía si está 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 git-root
comando en su RUTA como un 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 está en las líneas 2, 3 y 4.)
Y luego podrás correr git root
para obtener la raíz de tu árbol actual. Tenga en cuenta que en la secuencia de comandos del shell, use "-e" para hacer que el shell salga si el rev-parse falla, de modo que pueda obtener correctamente el estado de salida y el mensaje de error si no está en un directorio git.
"$(git rev-parse ...)"
lugar de hacks como ./$(git rev-parse ...)
.
readlink -f
no funciona igual en BSD. Vea este SO para soluciones alternativas. La respuesta Python probablemente funcionará sin instalar nada: python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$(git rev-parse --show-cdup)"
.
Como otros han señalado, el núcleo de la solución es usar git rev-parse --show-cdup
. Sin embargo, hay algunos casos extremos para abordar:
Cuando cwd ya es la raíz del árbol de trabajo, el comando produce una cadena vacía.
En realidad, produce una línea vacía, pero la tira de sustitución de comando se separa del salto de línea final. El resultado final es una cadena vacía.
La mayoría de las respuestas sugieren anteponer la salida ./
para que una salida vacía se convierta "./"
antes de alimentarla cd
.
Cuando GIT_WORK_TREE se establece en una ubicación que no es la principal del cwd, la salida puede ser una ruta absoluta.
Pretender ./
está mal 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 ubicación si cwd es el directorio raíz del sistema).
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 alrededor de la sustitución de comandos (y cualquier uso posterior del valor).
Como han señalado otras respuestas, podemos hacerlo cd "./$(git rev-parse --show-cdup)"
, pero esto se rompe en el segundo caso de borde (y el tercer caso de borde si dejamos las comillas dobles).
Muchos shells se tratan cd ""
como no operativos, por lo que para esos shells podríamos hacer cd "$(git rev-parse --show-cdup)"
(las comillas dobles protegen la cadena vacía como argumento en el primer caso de borde y preservan los espacios en blanco en el tercer caso de borde). POSIX dice el resultado decd ""
no está especificado, por lo que puede ser mejor evitar hacer esta suposición.
Una solución que funciona en todos los casos anteriores requiere una prueba de algún tipo. Hecho explícitamente, podría verse así:
cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"
No cd
se hace para el primer caso de borde.
Si es aceptable ejecutar cd .
para el primer caso límite, entonces el condicional se puede hacer en la expansión del parámetro:
cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
git root
' que usa la respuesta anterior?
En caso de que si está alimentando este camino al Git en sí, use :/
# 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)
Soluciones cortas que funcionan con submódulos, en ganchos y dentro del .git
directorio
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 árbol de trabajo de git (incluso dentro del .git
directorio), pero supone que se llama a los directorios del repositorio .git
(que es el valor predeterminado). Con submódulos, esto irá a la raíz del repositorio que contiene más externo.
Si desea llegar a la raíz del submódulo 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 comando en la raíz de su submódulo, debajo [alias]
de su .gitconfig
, agregue:
sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"
Esto te permite hacer fácilmente cosas como git sh ag <string>
Solución robusta que admite directorios .git
o nombres diferentes o externos $GIT_DIR
.
Tenga en cuenta que $GIT_DIR
puede apuntar a algún lugar externo (y no ser llamado .git
), de ahí la necesidad de una mayor verificación.
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 1 # git_root will print any errors
cd "$root"
}
Ejecutarlo mediante la tipificación git_root
(después de reiniciar el shell: exec bash
)
(root=$(git rev-parse --git-dir)/ && cd ${root%%/.git/*} && git rev-parse && pwd)
pero esto no cubre los correos electrónicos externos $GIT_DIR
que se nombran de otra manera.git
Para enmendar la respuesta "git config" solo un poco:
git config --global --add alias.root '!pwd -P'
y limpiar el camino. Muy agradable.
Si está buscando un buen alias para hacer esto y no explotar cd
si no está en un directorio git:
alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'
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
$ brew install git-extras
$ apt-get install git-extras
Este alias de shell funciona tanto si está en un subdirectorio git como en el nivel superior:
alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'
actualizado para usar la sintaxis moderna en lugar de backticks:
alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'
Todo lo demás falla en algún momento, ya sea yendo al directorio de inicio o simplemente fallando miserablemente. Esta es la forma más rápida y rápida de volver al GIT_DIR.
$GIT_DIR
se separa del .git
árbol de trabajo usando -Files y gitdir: SOMEPATH
. En consecuencia, esto también falla para los submódulos, donde $GIT_DIR
contiene .git/modules/SUBMODULEPATH
.
Aquí hay un script que he escrito que maneja ambos casos: 1) repositorio con un espacio de trabajo, 2) repositorio desnudo.
https://gist.github.com/jdsumsion/6282953
git-root
(archivo 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 exec
idea es más útil en repositorios no descubiertos. Sin embargo, este script en mi respuesta maneja el caso desnudo versus no desnudo correctamente, lo que podría ser útil para alguien, así que dejo esta respuesta aquí.
git submodule
s donde $GIT_DIR
contiene algo como /.git/modules/SUBMODULE
. También supone que el .git
directorio es parte del árbol de trabajo en el caso no desnudo.
$ git config alias.root '!pwd'
# then you have:
$ git root
[alias] findroot = "!f () { [[ -d ".git" ]] && echo "Found git in [
pwd ]" && exit 0; cd .. && echo "IN
pwd" && f;}; f"
git config --global alias.root '!pwd'
funciona. No pude detectar ningún caso en el que actúe de manera diferente a la variante no global. (Unix, git 1.7.10.4) Por cierto: se findroot
requiere /.git
para evitar una recursión sin fin.
Desde Git 2.13.0 , admite una nueva opción para mostrar la ruta del proyecto raíz, que funciona incluso cuando se utiliza desde un submódulo:
git rev-parse --show-superproject-working-tree
Si usa un marco de shell, es posible que ya haya un alias de shell disponible:
$ grt
en oh-my-zsh (68k) ( cd $(git rev-parse --show-toplevel || echo ".")
)$ git-root
en prezto (8.8k) (muestra la ruta a la raíz del árbol de trabajo)$ g..
zimfw (1k) (cambia el directorio actual al nivel superior del árbol de trabajo).Quería ampliar el excelente comentario de Daniel Brockman.
La definición le git config --global alias.exec '!exec '
permite hacer cosas como git exec make
porque, como man git-config
dice:
Si la expansión del alias tiene el prefijo de un signo de exclamación, se tratará como un comando de shell. [...] Tenga en cuenta que los comandos de shell se ejecutarán desde el directorio de nivel superior de un repositorio, que puede no ser necesariamente el directorio actual.
También es útil saber que $GIT_PREFIX
será la ruta al directorio actual en relación con el directorio de nivel superior de un repositorio. Pero, sabiendo que es solo la mitad de la batalla ™. La expansión variable de Shell hace que sea bastante difícil de usar. Entonces sugiero usar bash -c
así:
git exec bash -c 'ls -l $GIT_PREFIX'
Otros comandos incluyen:
git exec pwd
git exec make
En caso de que alguien necesite una forma de hacer esto compatible con POSIX, sin necesidad de git
ejecutable:
#$1: Path to child directory
git_root_recurse_parent() {
# Check if cwd is a git root directory
if [ -d .git/objects -a -d .git/refs -a -f .git/HEAD ] ; then
pwd
return 0
fi
# Check if recursion should end (typically if cwd is /)
if [ "${1}" = "$(pwd)" ] ; then
return 1
fi
# Check parent directory in the same way
local cwd=$(pwd)
cd ..
git_root_recurse_parent "${cwd}"
}
git_root_recurse_parent
Si solo desea la funcionalidad como parte de un script, elimine el shebang y reemplace la última git_root_recurse_parent
línea con:
git_root() {
(git_root_recurse_parent)
}
if
Se suponía que declaración verificaría si ha cambiado el directorio en la recursividad. Si permanece en el mismo directorio, se supone que está atascado en algún lugar (p /
. Ej. ) Y frena la recursividad. El error está solucionado y ahora debería funcionar como se esperaba. Gracias por mencionarlo.
Tuve que resolver esto yo mismo hoy. Lo resolvió en C # ya que lo necesitaba para un programa, pero supongo que puede reescribirse fácilmente. Considere 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;
}
bzr root
se usaba mucho en Bazargit rev-parse --git-dir
, como se explica en este comentario