git pull mientras no está en un directorio git

308

Digamos que tengo un directorio /X/Y, que es un repositorio git. ¿Es posible llamar de alguna manera a un comando como git pulldesde adentro /X, pero dirigido al /X/Ydirectorio?

EDITAR: Supongo que me preguntaba específicamente: ¿es posible hacer esto usando el comando a git, pero sin tener que cambiar los directorios?

NOTA: He aceptado la respuesta de VonC ya que es mucho más elegante que las opciones anteriores. Para las personas que ejecutan Git anteriores a 1.8.5, consulte la respuesta de bstpierre a continuación .

Gavin Anderegg
fuente
2
Me gustaría agregar que cuando use git-pull dentro de un gancho no funcionará a menos que desactive GIT_DIR. Pertinente.
zpmorgan
A partir de git 1.8.5 (cuarto trimestre de 2013), podrá "utilizar un comando git, pero sin tener que cambiar los directorios". Vea mi respuesta a continuación
VonC

Respuestas:

453

A partir de git 1.8.5 (cuarto trimestre de 2013) , podrá "utilizar un comando Git, pero sin tener que cambiar los directorios".

Al igual que " make -C <directory>", " git -C <directory> ..." le dice a Git que vaya allí antes de hacer cualquier otra cosa .

Ver commit 44e1e4 de Nazri Ramliy :

Se requieren más pulsaciones de teclas para invocar el comando Git en un directorio diferente sin salir del directorio actual:

  1. (cd ~/foo && git status)
    git --git-dir=~/foo/.git --work-tree=~/foo status
    GIT_DIR=~/foo/.git GIT_WORK_TREE=~/foo git status
  2. (cd ../..; git grep foo)
  3. for d in d1 d2 d3; do (cd $d && git svn rebase); done

Los métodos que se muestran arriba son aceptables para las secuencias de comandos, pero son demasiado engorrosos para invocaciones rápidas de la línea de comandos.

Con esta nueva opción, lo anterior se puede hacer con menos pulsaciones de teclas:

  1. git -C ~/foo status
  2. git -C ../.. grep foo
  3. for d in d1 d2 d3; do git -C $d svn rebase; done

Desde Git 2.3.4 (marzo de 2015), y cometer 6a536e2 por Karthik Nayak ( KarthikNayak) , gittratará " git -C '<path>'" como un no-op cuando <path>esté vacío.

' git -C ""' muere inútilmente con el error " Cannot change to ''", mientras que el shell trata el cd "" 'como un no-op.
Tomando el comportamiento del shell como un precedente, enseñe gita tratar a -C "" 'como un no-op, también.


4 años después, Git 2.23 (Q3 2019) documenta que ' git -C ""' funciona y no cambia el directorio

Se ha comportado así desde 6a536e2 ( git: trata " git -C '<path>'" como un no-op cuando <path>está vacío, 2015-03-06, Git v2.3.4).

Eso significa que la documentación ahora (finalmente) incluye:

Si ' <path>' está presente pero vacío, por ejemplo -C "", el directorio de trabajo actual no se modifica.


Puede ver git -Cusado con Git 2.26 (Q1 2020), como un ejemplo.

Ver commit b441717 , commit 9291e63 , commit 5236fce , commit 10812c2 , commit 62d58cd , commit b87b02c , commit 9b92070 , commit 3595d10 , commit f511bc0 , commit f6041ab , commit f46c243 , commit 99c049b , commit 3738439 , commit 7717242 , commit 208b ) por Denton Liu ( Denton-L) .
(Fusión por Junio ​​C Hamano - gitster- en commit 381e8e9 , 05 de febrero de 2020)

t1507: en línea full_name()

Firmado por: Denton Liu

Antes estábamos corriendo test_must_fail full_name. Sin embargo, test_must_failsolo debe usarse en comandos git.
En línea full_name()para que podamos usar test_must_failel gitcomando directamente.

Cuando full_name()se introdujo en 28fb84382b ("Introducir <branch>@{upstream}notación", 10/09/2009, Git v1.7.0-rc0 - fusionar ), la git -Copción aún no estaba disponible (ya que se introdujo en 44e1e4d67d (" git: ejecutar en un directorio dado con la opción -C ", 09/09/2013, Git v1.8.5-rc0 - fusión listada en lote # 5 )).
Como resultado, la función auxiliar eliminó la necesidad de hacerlo manualmente cdcada vez. Sin embargo, dado que git -Cestá disponible ahora, podemos usar eso en su lugar y en línea full_name().

VonC
fuente
66
¡Vaya! Bien! Esto es mucho más elegante, así que lo marcaré como aceptado para futuros espectadores.
Gavin Anderegg
1
No funciona para mí: # git --version && git -C ~ / .m2 / checkout master git versión 1.8.3.4 (Apple Git-47) Opción desconocida: -C uso: git [--version] [--help ] [-c nombre = valor] [--exec-ruta [= <path>]] [--html-ruta] [--man-ruta] [--info-ruta] [-p | --paginate | --no-pager] [--no-replace-objects] [--bare] [--git-dir = <path>] [--work-tree = <path>] [--namespace = <name> ] <comando> [<args>]
Jan Galinski
77
@ JanGalinski Pero sí mencioné "Starting git 1.8.5". Entonces git 1.8.3.x aún no sabría acerca de esa opción.
VonC
2
En Ubuntu 12.04 tuve que instalar una versión más nueva de git. Lo hice así: apt-get install software-properties-common python-software-propertiesluego agregue el repositorio git add-apt-repository ppa:git-core/ppa. El último paso consiste en la actualización git: apt-get update && apt-get upgrade.
ph3nx
54

Editar :

Hay un error git pullo no puedes hacer lo que intentas hacer con ese comando. Usted puede , sin embargo, hacerlo con traer y fusión:

cd /X
git --git-dir=/X/Y/.git fetch
git --git-dir=/X/Y/.git --work-tree=/X/Y merge origin/master

Respuesta original :

Suponiendo que esté ejecutando bash o similar, puede hacerlo (cd /X/Y; git pull).

La página de manual de git especifica algunas variables (ver "El repositorio de git") que parecen ayudar, pero no puedo hacer que funcionen correctamente (con mi repositorio en / tmp / ggg2):

GIT_WORK_TREE=/tmp/ggg2 GIT_DIR=/tmp/ggg2/.git git pull
fatal: /usr/lib/git-core/git-pull cannot be used without a working tree.

Ejecutando el siguiente comando mientras mi cwd es / tmp actualiza ese repositorio, pero el archivo actualizado aparece en / tmp en lugar del árbol de trabajo / tmp / ggg2:

GIT_DIR=/tmp/ggg2/.git git pull

Vea también esta respuesta a una pregunta similar , que demuestra las banderas --git-diry --work-tree.

bstpierre
fuente
¿Intentaste usar solo GIT_WORK_TREE?
Arrowmaster
@Arrowmaster: sí, si haces eso, git no puede encontrar el .gitdirectorio.
bstpierre
Ah, claro, la página del manual dice que GIT_WORK_TREE no se usa si GIT_DIR no está configurado. Parece extraño que no funcione cuando se usan ambos.
Arrowmaster
@Arrowmaster: Tengo que preguntarme si hay un error aquí en alguna parte. Si lo hago git --git-dir=/tmp/ggg2/.git --work-tree=/tmp/ggg2 pull, recibo un mensaje de error. Pero si lo hago git --git-dir=/tmp/ggg2/.git --work-tree=. pullmientras estoy en / tmp, coloca los archivos actualizados en / tmp como debería.
bstpierre
@bstpierre: No tengo acceso a un sistema con git instalado en este momento, pero si lo hiciera, estaría probando otras alternativas en --work-treeeste momento --work-tree=/tmp/ggg2/y --work-tree=/tmp/ggg2/.ya que podría ser un problema con cómo analiza el camino.
Arrowmaster
32

Puede envolverlo en un script bash o alias git:

cd /X/Y && git pull && cd -
tomashin
fuente
1
Esto definitivamente hace el truco, pero me pregunto si hay alguna forma de usar el comando git sin cambiar los directorios. Estoy empezando a pensar que no hay.
Gavin Anderegg
1
y usar el pushd/popdpar en lugar decd/cd-
axd
O podría usar una subshell para evitar tener que devolver el CD:(cd xyz && git pull)
jarmod
30

Esta publicación es un poco antigua, por lo que podría haber un error y se solucionó, pero acabo de hacer esto:

git --work-tree=/X/Y --git-dir=/X/Y/.git pull origin branch

Y funcionó. Me tomó un minuto darme cuenta de que quería el archivo de puntos y el directorio padre (en una configuración estándar, siempre son padre / hijo pero no en TODAS las configuraciones, por lo que deben especificarse explícitamente.

samtresler
fuente
Me gusta esta solución porque funciona con directorios como \\ remotemachine \ C $ \ folder \ etc
twasbrillig
7

Como algunos de mis servidores están en versiones antiguas de Ubuntu LTS, no puedo actualizar fácilmente git a la última versión (que admite la opción -C como se describe en algunas respuestas).

Este truco funciona bien para mí, especialmente porque no tiene el efecto secundario de algunas otras respuestas que lo dejan en un directorio diferente desde donde comenzó.

pushd /X/Y
git pull
popd

O, haciéndolo como una frase:

pushd /X/Y; git pull; popd

Tanto Linux como Windows tienen comandos pushd y popd.

IvanD
fuente
5

Usando la combinación pushd, git pully popd, podemos lograr esta funcionalidad:

pushd <path-to-git-repo> && git pull && popd

Por ejemplo:

pushd "E:\Fake Directory\gitrepo" && git pull && popd
Raman Sahasi
fuente
esto es increíble. Funciona perfectamente
Stretch0
4

Puedes escribir un script como este:

cd /X/Y
git pull

Puedes llamarlo algo así gitpull.
Si prefiere que haga directorios arbitrarios en lugar de /X/Y:

cd $1
git pull

Luego puede llamarlo con gitpull /X/Z
Lastly, puede intentar encontrar repositorios. Tengo una ~/gitcarpeta que contiene repositorios, y puede usar esto para extraerlos todos.

g=`find /X -name .git`
for repo in ${g[@]}
do
    cd ${repo}
    cd ..
    git pull
done
jonescb
fuente
2
Si desea hacerlo desde la línea de comandos, sólo lo hacen en un subnivel: (cd /X/Y && git pull).
Cascabel
2

Para cualquiera como yo que intentara hacer esto a través de un comando drush (Drupal shell) en un servidor remoto, no podrá usar la solución que requiere que coloque un CD en el directorio de trabajo:

En su lugar, debe usar la solución que divide la extracción en una búsqueda y fusión:

drush @remote exec git --git-dir=/REPO/PATH --work-tree=/REPO/WORKDIR-PATH fetch origin
drush @remote exec git --git-dir=/REPO/PATH --work-tree=/REPO/WORKDIR-PATH merge origin/branch
dkinzer
fuente
1

Este podría ser un problema similar, pero también puede simplemente encadenar sus comandos. p.ej

En una linea

cd ~/Sites/yourdir/web;git pull origin master

O a través de SSH.

ssh [email protected] -t "cd ~/Sites/thedir/web;git pull origin master"
John Ballinger
fuente