tirar / empujar desde múltiples ubicaciones remotas

743

En resumen: ¿hay alguna manera de hacer que un repositorio de git empuje y extraiga de una lista de repositorios remotos (en lugar de un solo "origen")?

El largo: a menudo tengo una situación en la que estoy desarrollando una aplicación en varias computadoras, con conectividad diferente, por ejemplo, una computadora portátil mientras estoy en tránsito, una computadora "A" mientras estoy en un lugar determinado y otra computadora "B" mientras que en otro. Además, la computadora portátil puede tener conectividad solo con "A" o "B", y algunas veces con ambas.

Lo que me gustaría es que git siempre "jale" y "empuje" a todas las computadoras a las que se puede conectar actualmente, por lo que es más fácil saltar de una máquina a otra y continuar trabajando sin problemas.

Zorzella
fuente
39
Nota para los nuevos visitantes, a partir de 2016: la forma correcta de hacer esto, sancionada por características de primera clase git, se incluye en la respuesta de malvineous a continuación . La respuesta aceptada es incorrecta.
ELLIOTTCABLE
@Zorzella: ¿Puedes actualizar la respuesta aceptada sobre esto? Es un poco confuso la forma en que está actualmente.
ntninja

Respuestas:

503

Puede configurar múltiples repositorios remotos con el git remotecomando:

git remote add alt alt-machine:/path/to/repo

Para obtener todos los controles remotos configurados y actualizar las ramas de seguimiento, pero no fusionarse HEAD, haga lo siguiente:

git remote update

Si no está conectado actualmente a uno de los controles remotos, tomará un tiempo de espera o arrojará un error, y pasará al siguiente. Tendrá que fusionarse manualmente desde los repositorios recuperados o cherry-pick, según cómo desee organizar la recopilación de cambios.

Para obtener la rama maestra de alt y colocarla en tu cabeza actual, haz lo siguiente:

git pull alt master

De hecho, git pulles casi una forma abreviada de git pull origin HEAD(en realidad, se ve en el archivo de configuración para determinar esto, pero se entiende la idea).

Para enviar actualizaciones, debe hacer eso en cada repositorio manualmente.
Creo que un impulso fue diseñado teniendo en cuenta el flujo de trabajo del repositorio central.

araqnid
fuente
así que lo que estás diciendo es que "git remote add foo ssh: //foo.bar/baz" crea una forma abreviada, pero todavía necesito recorrerlos con un "git pull", o recorrerlos con un "git fusionar "(¿cuál es la sintaxis aquí, después de una" actualización de eliminación de git "?) ¿Este nombre abreviado no funcionará también para" empuje de git "? Es decir, ¿no puedo "git push foo", etc. (bucle)? Gracias
Zorzella
8
"git pull" es básicamente "git fetch" seguido de "git merge". "git remote update" solo hace un montón de llamadas de "git fetch" por ti. Entonces, lo que queda es hacer el bit "git merge". Puede decir "git merge origin / master" y fusionará la versión de origen de master en su HEAD actual. "git pull origin master" hace lo mismo, aunque primero buscará (y si ya ha realizado la actualización remota de git, no tendrá nada más que buscar, por lo que es redundante). Sí, puede decir "git push foo" y empujará todas las ramas coincidentes al control remoto llamado "foo".
araqnid
IIUC no puede empujar a un repositorio que funcione (después de todo, puede estar empujando cambios incompatibles / no probados / no deseados). Debemos ingresar a los repositorios vacíos y solo recibir actualizaciones cuando lo hagamos. Entonces, ¿la solución requiere un repositorio que funcione y uno desnudo en cada máquina?
joeytwiddle
2
Aparentemente, también puede tener un solo impulso para varios repositorios, consulte esta respuesta para obtener más detalles stackoverflow.com/questions/14290113/…
manei_cc
797

¡Hacer esto manualmente ya no es necesario , con versiones modernas de git! Ver la solución de Malvineous , a continuación.

Reproducido aquí:

git remote set-url origin --push --add <a remote>
git remote set-url origin --push --add <another remote>

Respuesta original:

Este algo que he estado usando durante bastante tiempo sin malas consecuencias y sugerido por Linus Torvalds en la lista de correo de git .

La solución de araqnid es la adecuada para llevar el código a su repositorio ... pero cuando, como yo, tiene múltiples fuentes ascendentes autoritativas equivalentes (mantengo algunos de mis proyectos más críticos clonados tanto en una cadena ascendente privada, GitHub y Codaset), Puede ser un dolor empujar cambios a cada uno, todos los días.

En pocas palabras, git remote addtodos sus controles remotos individualmente ... y luego git config -ey agregue un control remoto combinado. Suponiendo que tenga este repositorio config:

[remote "GitHub"]
    url = [email protected]:elliottcable/Paws.o.git
    fetch = +refs/heads/*:refs/remotes/GitHub/*
[branch "Master"]
    remote = GitHub
    merge = refs/heads/Master
[remote "Codaset"]
    url = [email protected]:elliottcable/paws-o.git
    fetch = +refs/heads/*:refs/remotes/Codaset/*
[remote "Paws"]
    url = [email protected]:Paws/Paws.o.git
    fetch = +refs/heads/*:refs/remotes/Paws/*

... para crear un control remoto combinado para "Paws"y "Codaset", puedo agregar lo siguiente después de todo eso:

[remote "Origin"]
    url = [email protected]:Paws/Paws.o.git
    url = [email protected]:elliottcable/paws-o.git

Una vez que haya hecho esto, cuando git push Origin Masterlo haga, presionará a ambos Paws/Mastery Codaset/Mastersecuencialmente, haciendo la vida un poco más fácil.

ELLIOTTCABLE
fuente
104
git config -eabre el .git/configarchivo en su editor preferido.
Richard
3
Por si acaso. Confirmando que tener un control remoto con 2 URL todavía hace el trabajo en 1.7.12.4. Gracias.
foobar
26
Llamé al "origen" remoto "todo" para darle una semántica ligeramente más limpia
ErichBSchulz
1
@JamesWomack vea la respuesta de @ Malvineous a continuación. Ahora es "más correcto", ya que gitla línea de comandos lo admite de forma nativa, con git remote set-url ... --add.
ELLIOTTCABLE
1
En [branch "Master"]conjunto remote = Originy git pullusará ambos controles remotos.
Bengt
264

Desde git 1.8 (octubre de 2012) puede hacerlo desde la línea de comandos:

git remote set-url origin --push --add user1@repo1
git remote set-url origin --push --add user2@repo2
git remote -v

Luego git pushempujará al usuario1 @ repo1, luego empujará al usuario2 @ repo2.

Malvinoso
fuente
19
No recomiendo esta solución. Lo hemos usado en nuestra empresa y hemos tenido serios problemas con los ganchos que fallan en un repositorio, pero no en el otro. Los conjuntos de cambios solo estaban presentes en un repositorio.
Michael Schmeißer
44
@ MichaelSchmeißer: ¿Presumiblemente podría ver los mensajes de error al presionar, solucionar el problema y luego presionar nuevamente para que todo vuelva a un estado limpio?
Malvineous
77
El problema es que arreglar el impulso rechazado implica cambiar los commits que ya se han enviado al otro repositorio. Entonces, si alguien ya basó el trabajo en esos compromisos para el momento en que se arreglan, las cosas se ponen realmente desagradables, como fue el caso en nuestra oficina.
Michael Schmeißer
99
Ah sí, eso podría ser complicado. Sin embargo, para mí eso parece que los ganchos necesitan ser rediseñados. Un impulso fallido no rompe git normalmente, por lo que la introducción de un nuevo punto de falla (que también evita que uses una función ingeniosa de git) probablemente no sea la mejor solución. Por supuesto, digo esto sin saber cuáles son sus requisitos ...
Malvineous
3
No. Desde que escribí mi pregunta, leí otras publicaciones web y luego probé esto. Al leer otras publicaciones, tengo la sospecha de que solo se utiliza la primera línea. Acabo de probar esto: de hecho, solo se inspecciona la URL de la primera línea git fetch. (Teniendo en cuenta esto, no entiendo cuál es el propósito de git remote set-url --addpuede estar sin --push.)
imz - Ivan Zakharyaschev
34

Agregué estos alias a mi ~ / .bashrc:

alias pushall='for i in `git remote`; do git push $i; done;'
alias pullall='for i in `git remote`; do git pull $i; done;'
Nona Urbiz
fuente
66
¡Esto es asombroso! Terminé teniendo un alias de Git: git config alias.pushall '!for i in git remote; do git push $i; done;'
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Creo que prefiero la solución de alias a crear un nuevo control remoto. Ver también stackoverflow.com/questions/41372919/…
donquixote
1
Pequeño ajuste sugerido:alias pushall='for i in `git remote`; do echo "Pushing to " $i; git push $i; done;'
Scott C Wilson el
25

Puede agregar controles remotos con:

git remote add a urla
git remote add b urlb

Luego, para actualizar todos los repositorios:

git remote update
FelipeC
fuente
15

Aquí está mi ejemplo con script bash dentro de la .gitconfigsección de alias

[alias]
        pushall = "!f(){ for i in `git remote`; do git push $i; done; };f"
troex
fuente
7

Agregué dos pushurl separados al "origen" remoto en el archivo .git congfig. Cuando corro git push origin "branchName"Entonces correrá y empujará a cada url. No estoy seguro de si hay una manera más fácil de lograr esto, pero esto funciona para mí para empujar al código fuente de Github y empujar al código fuente My.visualStudio al mismo tiempo.

[remote "origin"]
  url = "Main Repo URL"
  fetch = +refs/heads/*:refs/remotes/origin/*
  pushurl = "repo1 URL"
  pushurl = "reop2 URl"
dstineback
fuente
4

Me tomé la libertad de ampliar la respuesta de nona-urbiz; simplemente agregue esto a su ~ / .bashrc:

git-pullall () { for RMT in $(git remote); do git pull -v $RMT $1; done; }    
alias git-pullall=git-pullall

git-pushall () { for RMT in $(git remote); do git push -v $RMT $1; done; }
alias git-pushall=git-pushall

Uso:

git-pullall master

git-pushall master ## or
git-pushall

Si no proporciona ningún argumento de bifurcación para git-pullall, la extracción de los controles remotos no predeterminados fallará; dejó este comportamiento tal como está, ya que es análogo a git.

hsk81
fuente
3

Necesitará un script para recorrerlos. Git no proporciona un "empujar todo". Teóricamente, podría hacer un empuje en múltiples hilos, pero un método nativo no está disponible.

Fetch es aún más complicado, y recomendaría hacerlo linealmente.

Creo que su mejor respuesta es tener una máquina que todos empujen / tiren, si eso es posible.

Jeff Ferland
fuente
2
El problema es que, como describí, no hay un cuadro central siempre disponible. Si tengo que escribir un script bash bucle, que así sea, pero se siente curioso que un VC distribuido no me ayudaría más aquí ...
Zorzella
2
Al distribuirse, se supone que no todos están disponibles, o que se les quiere presionar. También se relaciona con diferentes repositorios en diferentes estados, y la suposición de que otros están trabajando en ellos simultáneamente. El orden que empuja y tira de un conjunto de repositorios afecta el estado de los diferentes repositorios, y tendría que hacer varios pases para que todos estén realmente sincronizados. Es por eso que no hay "pull / push all". Luego están los conflictos ...;)
Jeff Ferland
3

Para actualizar los controles remotos (es decir, el pullcaso), las cosas se han vuelto más fáciles.

La declaración de Linus.

Lamentablemente, ni siquiera hay forma de fingir esto con un alias git.

en la entrada referenciada en la lista de correo de Git en la respuesta de elliottcable ya no es cierto.

git fetch aprendí el --all parámetro en algún lugar del pasado que permite obtener todos los controles remotos de una sola vez.

Si no se solicitan todos, uno podría usar el --multipleinterruptor para especificar múltiples controles remotos o un grupo.

Eckes
fuente
3

Quería trabajar en VSO / TFS, luego presionar públicamente a GitHub cuando esté listo. Repo inicial creado en VSO privado. Cuando llegó el momento de agregar a GitHub, lo hice:

git remote add mygithubrepo https://github.com/jhealy/kinect2.git
git push -f mygithubrepo master

Trabajó como un campeón ...

Para una verificación de cordura, emita "git remote -v" para enumerar los repositorios asociados con un proyecto.

C:\dev\kinect\vso-repo-k2work\FaceNSkinWPF>git remote -v
githubrepo      https://github.com/jhealy/kinect2.git (fetch)
githubrepo      https://github.com/jhealy/kinect2.git (push)
origin  https://devfish.visualstudio.com/DefaultCollection/_git/Kinect2Work (fetch)
origin  https://devfish.visualstudio.com/DefaultCollection/_git/Kinect2Work (push)

De manera simple, funcionó para mí ... Espero que esto ayude a alguien.

Joe Healy
fuente
44
Correr git push -fsin una razón, por ejemplo, fallar git pusho saber exactamente lo que uno está haciendo, es una mala idea y potencialmente dañina. Esto tampoco responde la pregunta, sino cómo agregar un segundo control remoto.
Karl Richter
2

agregue un alias a gitconfig global (/home/user/.gitconfig) con el siguiente comando.

git config --global alias.pushall '!f(){ for var in $(git remote show); do echo "pushing to $var"; git push $var; done; }; f'

Una vez que confirma el código, decimos

git push

para empujar al origen por defecto. Después del alias anterior, podemos decir

git pushall

y el código se actualizará a todos los controles remotos, incluido el control remoto de origen.

dhirajforyou
fuente
1

Agregar el all control remoto se vuelve un poco tedioso ya que debe configurarlo en cada máquina que usa.

Además, los aliasbash y siempre que todos asuman que tienes empujarán a todos los controles remotos. (Ej: tengo una bifurcación de eso que mantengo en GitHub y GitLab. Tengo el upstreamgit sshag agregado el control remoto , pero no tengo permiso para presionarlo).

Aquí hay un git alias que solo empuja a controles remotos con una URL de inserción que incluye @.

psall    = "!f() { \
    for R in $(git remote -v | awk '/@.*push/ { print $1 }'); do \
    git push $R $1; \
    done \
    }; f"
go2null
fuente
-3

Agregar nuevo control remoto

git remote add upstream https://github.com/example-org/example-repo.git

git remote -vv

Obtener múltiples ubicaciones

git fetch --all

Empuje a ubicaciones

git push -u upstream/dev
Dadaso Zanzane
fuente