puxar / empurrar de vários locais remotos

743

O resumo: existe uma maneira de fazer com que um repositório Git seja enviado e retirado de uma lista de repositórios remotos (em vez de uma única "origem")?

Por muito tempo: geralmente tenho uma situação em que estou desenvolvendo um aplicativo em vários computadores, com conectividade diferente - digamos, um laptop em trânsito, um computador "A" enquanto estou em um determinado local e outro computador "B" enquanto em outro. Além disso, o laptop pode ter conectividade apenas com "A" ou "B" e, às vezes, com os dois.

O que eu gostaria é que o git sempre "puxe" e "empurre" para todos os computadores aos quais pode se conectar atualmente, para que seja mais fácil pular de uma máquina para outra e continuar trabalhando sem problemas.

Zorzella
fonte
39
Nota para os novos visitantes, a partir de 2016: A maneira atualmente correta de fazer isso, sancionado pela primeira classe gitcaracterísticas, está incluído na malvineous 's resposta abaixo . A resposta aceita está incorreta.
ELLIOTTCABLE
@Zorzella: Você pode atualizar a resposta aceita sobre isso, é meio confuso do jeito que é atualmente.
Ntninja 10/04/19

Respostas:

503

Você pode configurar vários repositórios remotos com o git remotecomando:

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

Para buscar em todos os controles remotos configurados e atualizar ramos de rastreamento, mas não mesclar HEAD, faça:

git remote update

Se não estiver conectado atualmente a um dos controles remotos, isso levará um tempo ou causará um erro e seguirá para o próximo. Você precisará mesclar manualmente a partir dos repositórios buscados ou cherry-pick, dependendo de como deseja organizar a coleta de alterações.

Para buscar o ramo principal de alt e puxá-lo para sua cabeça atual, faça:

git pull alt master

Então, na verdade, git pullé quase uma abreviação de git pull origin HEAD(na verdade, ele procura no arquivo de configuração para determinar isso, mas você entendeu).

Para enviar atualizações por push, você deve fazer isso para cada repo manualmente.
Acho que um empurrão foi projetado com o fluxo de trabalho do repositório central em mente.

araqnid
fonte
então o que você está dizendo é que "git remote add foo ssh: //foo.bar/baz" cria uma forma abreviada, mas ainda preciso fazer um loop sobre eles com um "git pull" ou sobre eles com um "git mesclar "(qual é a sintaxe aqui, após uma" atualização de remoção do git "?) Esse nome abreviado também não funcionará para" git push "? Ou seja, não posso "git push foo" etc (loop)? Obrigado
Zorzella
8
"git pull" é basicamente "git fetch" seguido por "git merge". O "git remote update" faz várias chamadas de "git fetch" para você. Então, o que resta é fazer o bit "git merge". Você pode dizer "git merge origin / master" e ele mesclará a versão de origem do master em seu HEAD atual. O "git pull origin master" faz a mesma coisa, embora faça uma busca primeiro (e se você já fez a atualização remota do git, isso não terá mais nada a buscar, por isso é redundante). Sim, você pode dizer "git push foo" e enviará todas as ramificações correspondentes ao controle remoto chamado "foo".
Araqnid
IIUC, você não pode enviar para um repositório em funcionamento (afinal, você pode enviar alterações incompatíveis / não testadas / indesejadas). Devemos enviar para repositórios vazios e receber apenas atualizações quando recebermos. Portanto, a solução requer um repositório funcional e um bare em cada máquina?
Joeytwiddle #
2
Aparentemente, você também pode ter um único impulso para vários repos, verifique esta resposta para mais detalhes stackoverflow.com/questions/14290113/...
manei_cc
797

Fazer isso manualmente não é mais necessário , com versões modernas do git! Veja a solução da Malvineous , abaixo.

Reproduzido aqui:

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

Resposta original:

Isso é algo que venho usando há um bom tempo sem consequências ruins e sugerido por Linus Torvalds na lista de discussão do git .

A solução da araqnid é a mais adequada para trazer código para o seu repositório ... mas quando você, como eu, tem vários upstream autoritativos equivalentes (eu mantenho alguns dos meus projetos mais críticos clonados em um upstream privado, GitHub e Codaset), pode ser uma dor empurrar mudanças para cada uma, todos os dias.

Para encurtar a história, git remote addtodos os seus controles remotos individualmente ... git config -ee adicione um controle remoto mesclado. Supondo que você tenha este repositório 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 criar um controle remoto mesclado para "Paws"e "Codaset", posso adicionar o seguinte depois de todos:

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

Depois de fazer isso, quando for git push Origin Master, ele passará para ambos Paws/Mastere Codaset/Mastersequencialmente, tornando a vida um pouco mais fácil.

ELLIOTTCABLE
fonte
104
git config -eabre o .git/configarquivo no seu editor preferido.
Richard
3
Apenas no caso de. Confirmando que ter um controle remoto com 2 URLs ainda faz o trabalho em 1.7.12.4. Obrigado.
foobar
26
I chamado a "origem" remota "todos" para dar-lhe ligeiramente a semântica mais limpas
ErichBSchulz
1
@ JamesWomack, veja a resposta de @ Malvineous, abaixo. É "mais correto" agora, pois gita linha de comando da suporta isso nativamente, com git remote set-url ... --add.
ELLIOTTCABLE
1
Em [branch "Master"]conjunto remote = Origine git pullusará os dois controles remotos.
Bengt
264

Desde o git 1.8 (outubro de 2012), você pode fazer isso na linha de comando:

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

Em seguida git push, pressione o botão user1 @ repo1 e, em seguida, pressione user2 @ repo2.

Malvineous
fonte
19
Eu recomendo fortemente contra esta solução. Nós o usamos em nossa empresa e enfrentamos sérios problemas devido à falha de ganchos em um repositório, mas não no outro. Os conjuntos de alterações estavam presentes apenas em um repositório.
Michael Schmeißer
4
@ MichaelSchmeißer: Presumivelmente, você pode ver as mensagens de erro ao pressionar, corrigir o problema e pressionar novamente para que tudo volte a um estado limpo?
Malvineous
7
O problema é que a correção do push rejeitado envolve a alteração dos commit que já foram enviados para o outro repositório. Portanto, se alguém já baseou o trabalho nesses commits no momento em que são corrigidos, as coisas ficam realmente desagradáveis, como foi o caso em nosso escritório.
Michael Schmeißer
9
Ah, sim, isso pode ficar complicado. No entanto, para mim, parece que os ganchos precisam ser redesenhados. Um push com falha não quebra o git normalmente, portanto, a introdução de um novo ponto de falha (que também impede que você use um recurso bacana do git) provavelmente não é a melhor solução. É claro que eu digo isso sem saber o que são as suas necessidades ...
Malvineous
3
Não. Desde que escrevi minha pergunta, li outras postagens na Web e testei isso. Ao ler outras postagens, tenho a suspeita de que apenas a primeira linha é usada. Acabei de testar isso: na verdade, apenas o URL da primeira linha é inspecionado por git fetch. (Perante isto, eu não entendo o que a finalidade git remote set-url --addpode ser sem --push.)
IMZ - Ivan Zakharyaschev
34

Adicionei esses aliases ao meu ~ / .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
fonte
6
Isso é incrível! Acabei tendo um alias do Git: git config alias.pushall '!for i in git remote; do git push $i; done;'
Ciro Santilli
Acho que prefiro a solução de alias à criação de um novo controle remoto. Veja também stackoverflow.com/questions/41372919/…
donquixote
1
Pequenos ajustes sugeridos:alias pushall='for i in `git remote`; do echo "Pushing to " $i; git push $i; done;'
Scott C Wilson
25

Você pode adicionar controles remotos com:

git remote add a urla
git remote add b urlb

Para atualizar todos os repositórios, faça:

git remote update
FelipeC
fonte
15

Aqui está o meu exemplo com o script bash na .gitconfigseção alias

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

Adicionei dois pushurl separados à "origem" remota no arquivo .git congfig. Quando eu corro git push origin "branchName"Em seguida, ele percorre e empurra para cada URL. Não tenho certeza se existe uma maneira mais fácil de fazer isso, mas isso funciona para mim passar para o código-fonte do Github e para o código-fonte My.visualStudio ao mesmo tempo.

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

Tomei a liberdade de expandir a resposta de nona-urbiz; basta adicionar isso ao seu ~ / .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 você não fornecer nenhum argumento de ramificação para o git-pullall, o pull dos controles remotos não padrão falhará; deixou esse comportamento como ele é, pois é análogo ao git.

hsk81
fonte
3

Você precisará de um script para percorrê-los. O Git não fornece um "empurrar tudo". Teoricamente, você poderia fazer um push em vários threads, mas um método nativo não está disponível.

A busca é ainda mais complicada, e eu recomendo fazer isso linearmente.

Acho que sua melhor resposta é ter uma máquina que todo mundo faça pressão / puxar, se isso for possível.

Jeff Ferland
fonte
2
O problema é que, como descrevi, não existe uma caixa central sempre disponível. Se eu tenho que escrever um script looping, que assim seja, mas parece engraçado que um VC distribuído não iria me ajudar mais aqui ...
Zorzella
2
Sendo distribuído, assume que nem todo mundo está disponível ou que deseja ser empurrado. Também se relaciona com diferentes repositórios em diferentes estados e com a suposição de que outros estão trabalhando neles simultaneamente. A ordem de envio e retirada de um conjunto de repositórios afeta o estado de diferentes repositórios, e você teria que fazer várias passagens para que todos fossem realmente sincronizados. É por isso que não há "puxe / empurre tudo". Depois, há conflitos ...;)
Jeff Ferland
3

Para atualizar os controles remotos (ou seja, o pullcaso), as coisas ficaram mais fáceis.

A declaração de Linus

Infelizmente, não há nenhuma maneira de fingir isso com um apelido git.

na entrada referenciada na lista de correspondência Git na resposta do elliottcable não é mais verdadeira.

git fetchaprendi o --allparâmetro em algum lugar no passado, permitindo buscar todos os controles remotos de uma só vez.

Se nem todos forem solicitados, pode-se usar a --multipleopção para especificar vários controles remotos ou um grupo.

eckes
fonte
3

Eu queria trabalhar no VSO / TFS e enviar publicamente para o GitHub quando estiver pronto. Repo inicial criado no VSO privado. Quando chegou a hora de adicionar ao GitHub, fiz:

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

Trabalhou como um campeão ...

Para uma verificação de integridade, emita "git remote -v" para listar os repositórios associados a um projeto.

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)

Maneira simples, funcionou para mim ... Espero que isso ajude alguém.

Joe Healy
fonte
4
Correr git push -fsem uma razão, por exemplo, falha git pushou conhecimento exato do que se está fazendo, é uma má idéia e potencialmente prejudicial. Isso também não responde à pergunta, mas como adicionar um segundo controle remoto.
Karl Richter
2

adicione um alias ao gitconfig global (/home/user/.gitconfig) com o comando abaixo.

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

Depois de confirmar o código, dizemos

empurrão

para empurrar para a origem por padrão. Depois do apelido acima, podemos dizer

git pushall

e o código será atualizado para todos os controles remotos, incluindo o controle remoto de origem.

dhirajforyou
fonte
1

Adicionar o allcontrole remoto fica um pouco entediante, pois você precisa configurar em cada máquina que usa.

Além disso, todos os aliasesbash e fornecidos assumem que você possui o envio para todos os controles remotos. (Por exemplo: tenho uma bifurcação que mantenho no GitHub e GitLab. Tenho o controle remoto upstream adicionado, mas não tenho permissão para fazer isso.)git sshag

Aqui está um git alias que apenas envia para controles remotos com um URL de envio que inclui @.

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

Adicionando novo controle remoto

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

git remote -vv

Buscar formulário em vários locais

git fetch --all

Enviar para locais

git push -u upstream/dev
Dadaso Zanzane
fonte