pull / push da più postazioni remote


743

In breve: c'è un modo per fare in modo che un repository git spinga e tiri da un elenco di repository remoti (piuttosto che una singola "origine")?

Il lungo: ho spesso una situazione in cui sto sviluppando un'app su più computer, con connettività diversa - ad esempio un laptop durante il trasporto, un computer "A" mentre sono in una determinata posizione e un altro computer "B" mentre su un altro. Inoltre, il laptop potrebbe avere connettività solo con "A" o "B", e talvolta entrambi.

Quello che mi piacerebbe è che Git "tiri" sempre e "spinga" verso tutti i computer a cui è attualmente in grado di connettersi, quindi è più facile passare da una macchina all'altra e continuare a lavorare senza problemi.


39
Nota per i nuovi visitatori, a partire dal 2016: Il modo in cui attualmente corretto per fare questo, sancito dalla prima classe gitcaratteristiche, è incluso nel malvineous 's risposta qui sotto . La risposta accettata non è corretta
ELLIOTTCABLE

@Zorzella: puoi aggiornare la risposta accettata su questo, è un po 'confusa com'è attualmente.
ntninja,

Risposte:


503

È possibile configurare più repository remoti con il git remotecomando:

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

Per recuperare da tutti i telecomandi configurati e aggiornare i rami di tracciamento, ma non unirli in HEAD, eseguire:

git remote update

Se al momento non è collegato a uno dei telecomandi, ci vorrà del tempo o genererà un errore e passerà al successivo. Dovrai unire manualmente dai repository recuperati o cherry-pick, a seconda di come desideri organizzare la raccolta delle modifiche.

Per recuperare il ramo principale da alt e tirarlo nella tua testa attuale, fai:

git pull alt master

Quindi in effetti git pullè quasi una scorciatoia git pull origin HEAD(in realtà cerca nel file di configurazione per determinare questo, ma hai l'idea).

Per inviare aggiornamenti, è necessario farlo manualmente per ciascun repository.
Penso che una spinta sia stata progettata pensando al flusso di lavoro del repository centrale.


quindi quello che stai dicendo è che "git remote add foo ssh: //foo.bar/baz" crea una forma abbreviata, ma ho ancora bisogno di passarci sopra con un "git pull", o passare su di essi con un "git merge "(qual è la sintassi qui, dopo un" git remove update "?) Questo nome abbreviato non funziona anche per" git push "? Cioè non posso "git push foo" ecc (loop)? Grazie
Zorzella,

8
"git pull" è fondamentalmente "git fetch" seguito da "git merge". "git remote update" fa solo un sacco di chiamate "git fetch" per te. Quindi ciò che resta è fare il bit "git merge". Puoi dire "git merge origin / master" e unirà la versione di origin di master nel tuo HEAD attuale. "git pull origin master" fa la stessa cosa, anche se prima eseguirà un recupero (e se hai già eseguito l'aggiornamento remoto di git, non avrà altro da recuperare, quindi è ridondante). Sì, puoi dire "git push foo" e spingerà tutti i rami corrispondenti sul telecomando chiamato "foo".
araqnid,

IIUC non è possibile eseguire il push in un repository funzionante (dopo tutto, è possibile che si stiano spingendo modifiche incompatibili / non testate / indesiderate). Dobbiamo spingere in repository nudi e ricevere aggiornamenti solo quando estraiamo. Quindi la soluzione richiede un repository funzionante e un nudo su ogni macchina?
joeytwiddle,

2
A quanto pare si può anche avere una semplice pressione per diverse operazioni pronti contro termine, controllare questa risposta per maggiori dettagli stackoverflow.com/questions/14290113/...
manei_cc

797

Non è più necessario farlo manualmente , con le versioni moderne di git! Vedi la soluzione di Malvineous , di seguito.

Riprodotto qui:

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

Risposta originale:

Questo qualcosa che sto usando da un bel po 'senza conseguenze negative e suggerito da Linus Torvalds sulla mailing list di git .

La soluzione di araqnid è quella giusta per portare il codice nel tuo repository ... ma quando tu, come me, hai molteplici upstream autorevoli equivalenti (tengo alcuni dei miei progetti più critici clonati su entrambi a monte, GitHub e Codaset), può essere un dolore spingere i cambiamenti a ciascuno, ogni giorno.

Per farla breve, git remote addtutti i telecomandi singolarmente ... e poi git config -ee aggiungi un telecomando unito. Supponendo di avere questo repository config:

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

... per creare un telecomando-unito per "Paws"e "Codaset", dopo tutto ciò posso aggiungere:

[remote "Origin"]
    url = git@github.com:Paws/Paws.o.git
    url = git@codaset.com:elliottcable/paws-o.git

Una volta fatto questo, quando git push Origin Masterlo farò, spingerà verso entrambi Paws/Mastere in Codaset/Mastersequenza, rendendo la vita un po 'più facile.


104
git config -eapre il .git/configfile nel tuo editor preferito.
Richard

3
Nel caso in cui. Confermando che avere un telecomando con 2 URL continuerà a funzionare su 1.7.12.4. Grazie.
foobar

26
Ho chiamato "l'origine" remota "tutto" per dargli una semantica leggermente più pulita
ErichBSchulz,

1
@JamesWomack vedi la risposta di @ Malvineous, di seguito. Ora è "più corretto", poiché gitla riga di comando lo supporta nativamente, con git remote set-url ... --add.
ELLIOTTCABLE

1
Sotto [branch "Master"]set remote = Origine git pullutilizzerà entrambi i telecomandi.
Bengt,

264

Da git 1.8 (ottobre 2012) puoi farlo dalla riga di comando:

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

Quindi git pushpasserà a user1 @ repo1, quindi a user2 @ repo2.


19
Sconsiglio vivamente questa soluzione. L'abbiamo usato nella nostra azienda e abbiamo avuto seri problemi con gli hook non funzionanti in un repository, ma non nell'altro. I changeset erano quindi presenti solo in un repository.
Michael Schmeißer,

4
@ MichaelSchmeißer: Presumibilmente potresti vedere i messaggi di errore quando spingi, risolvi il problema, quindi premi di nuovo per riportare tutto in uno stato pulito?
Malvineous,

7
Il problema è che la correzione della push respinta comporta la modifica dei commit che sono già stati trasferiti all'altro repository. Quindi, se qualcuno ha già basato il lavoro su tali impegni prima che vengano risolti, le cose diventano davvero brutte, come nel nostro ufficio.
Michael Schmeißer,

9
Ah sì, potrebbe essere complicato. Tuttavia a me sembra che i ganci debbano essere riprogettati. Una spinta fallita non interrompe normalmente git, quindi l'introduzione di un nuovo punto di errore (che impedisce anche di utilizzare una funzionalità git elegante) non è probabilmente la soluzione migliore. Ovviamente lo dico senza sapere quali sono i tuoi requisiti ...
Malvineous,

3
No. Da quando ho scritto la mia domanda, ho letto altri post sul web e poi ho provato questa cosa. Dalla lettura di altri post, ho il sospetto che venga utilizzata solo la prima riga. Ho appena provato questo: infatti, solo l'URL della prima riga viene ispezionato da git fetch. (Dato questo, non capisco di cosa git remote set-url --addpossa essere lo scopo senza --push.)
imz - Ivan Zakharyaschev,

34

Ho aggiunto questi alias al mio ~ / .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;'

6
Questo è bellissimo! Ho finito per avere un alias Git: git config alias.pushall '!for i in git remote; do git push $i; done;'
Ciro Santilli 22 冠状 病 六四 事件 法轮功

Penso di preferire la soluzione alias alla creazione di un nuovo telecomando. Vedi anche stackoverflow.com/questions/41372919/...
Donquixote

1
Piccolo suggerimento suggerito:alias pushall='for i in `git remote`; do echo "Pushing to " $i; git push $i; done;'
Scott C Wilson,

25

Puoi aggiungere telecomandi con:

git remote add a urla
git remote add b urlb

Quindi per aggiornare tutti i repository fai:

git remote update

15

Ecco il mio esempio con lo script bash nella .gitconfigsezione alias

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

7

Ho aggiunto due pushurl separati alla "origine" remota nel file .git congfig. Quando corro, git push origin "branchName"allora scorrerà e passerà a ciascun URL. Non sono sicuro che ci sia un modo più semplice per farlo, ma questo funziona per me stesso per spingere al codice sorgente di Github e spingere al codice sorgente My.visualStudio allo stesso tempo.

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

4

Mi sono preso la libertà di espandere la risposta da nona-urbiz; aggiungi questo al tuo ~ / .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

Se non fornisci alcun argomento branch per git-pullall, il pull dai telecomandi non predefiniti fallirà; ha lasciato questo comportamento così com'è, poiché è analogo a git.


3

Avrai bisogno di uno script per eseguirne il ciclo. Git non fornisce un "push all". Teoricamente potresti fare un push in più thread, ma un metodo nativo non è disponibile.

Il recupero è ancora più complicato e consiglierei di farlo in modo lineare.

Penso che la tua migliore risposta sia avere una macchina su cui tutti facciano un push / pull, se possibile.


2
Il problema è che, come ho descritto, non esiste una scatola centrale sempre disponibile. Se devo scrivere uno script bash in loop, così sia, ma è strano che un VC distribuito non mi aiuti di più qui ...
Zorzella,

2
Essendo distribuito, si presume che non tutti siano disponibili o che desiderino essere spinti a farlo. Si riferisce anche al fatto che diversi repository si trovano in stati diversi e il presupposto che altri stanno lavorando su di essi contemporaneamente. L'ordine che fai push e pull da un set di repository influenza lo stato di diversi repository e dovresti fare più passaggi per sincronizzarli tutti. Questo è il motivo per cui non esiste "pull / push all". Poi ci sono conflitti ...;)
Jeff Ferland,

3

Per aggiornare i telecomandi (ad esempio il pullcaso), le cose sono diventate più facili.

La dichiarazione di Linus

Purtroppo, non c'è nemmeno modo di fingere questo con un alias git.

nella voce referenziata della mailing list Git nella risposta di elliottcable non è più vero.

git fetchimparato il --allparametro da qualche parte in passato che consente di recuperare tutti i telecomandi in una volta sola.

Se non tutti sono richiesti, è possibile utilizzare l' --multipleinterruttore per specificare più telecomandi o un gruppo.


3

Volevo lavorare in VSO / TFS, quindi spingere pubblicamente su GitHub quando pronto. Repos iniziale creato in VSO privato. Quando è arrivato il momento di aggiungere a GitHub ho fatto:

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

Ha funzionato come un campione ...

Per un controllo di integrità, emettere "git remote -v" per elencare i repository associati a un progetto.

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)

Modo semplice, ha funzionato per me ... Spero che questo aiuti qualcuno.


4
Correre git push -fsenza un motivo, ad esempio il fallimento git pusho sapere esattamente cosa si sta facendo, è una cattiva idea potenzialmente dannosa. Anche questo non risponde alla domanda, ma come aggiungere un secondo telecomando.
Karl Richter,

2

aggiungi un alias a gitconfig globale (/home/user/.gitconfig) con il comando seguente.

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

Una volta che commetti il ​​codice, diciamo

git push

per spingere all'origine per impostazione predefinita. Dopo alias sopra, possiamo dire

git pushall

e il codice verrà aggiornato a tutti i telecomandi, incluso l'origine remota.


1

L'aggiunta del alltelecomando diventa un po 'noiosa in quanto è necessario impostare su ogni macchina che si utilizza.

Inoltre, l' bashe git alias purché tutto si presuppone che spingerà a tutti i telecomandi. (Es .: ne ho un fork sshagche mantengo su GitHub e GitLab. Ho aggiunto il telecomando upstream , ma non ho il permesso di spingerlo.)

Ecco un git alias che spinge solo ai telecomandi con un URL push che include @.

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

-3

Aggiunta di un nuovo telecomando

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

git remote -vv

Recupera modulo da più posizioni

git fetch --all

Spingere in posizioni

git push -u upstream/dev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.