Rastrear todas as ramificações remotas do git como ramificações locais

175

O rastreamento de uma única filial remota como uma filial local é bastante direto.

$ git checkout --track -b ${branch_name} origin/${branch_name}

Empurrar todas as ramificações locais para o controle remoto, criando novas ramificações remotas conforme necessário também é fácil.

$ git push --all origin

Eu quero fazer o contrário. Se eu tiver um número X de ramificações remotas em uma única fonte:

$ git branch -r 
branch1
branch2
branch3
.
.
.

Posso criar ramificações de rastreamento local para todas essas ramificações remotas sem a necessidade de criar manualmente cada uma? Diga algo como:

$ git checkout --track -b --all origin

Eu pesquisei no Google e os RTMs, mas acabei ficando um bocado até agora.

Janson
fonte
3
Há uma maneira ainda mais simples para controlar um único ramo remoto como uma filial local:git checkout --track origin/branchname
Cerran
Não é exatamente o que você pediu, mas funciona para mim: obtenha as conclusões do git: github.com/git/git/blob/master/contrib/completion/… . Em seguida, digite git pull origin e aperte tab, para obter uma lista de ramificações remotas. Então continue digitando e pressione return.
Max Heiber

Respostas:

111

Usando o bash:

depois do git 1.9.1
for i in `git branch -a | grep remote | grep -v HEAD | grep -v master`; do git branch --track ${i#remotes/origin/} $i; done

créditos: Val Blant, elias e Hugo

antes do git 1.9.1

Nota: o código a seguir, se usado em versões posteriores do git (> v1.9.1), causa

  1. (bug) Todos os ramos criados para rastrear o mestre
  2. (aborrecimento) Todos os nomes de agências locais criados a serem prefixados com origin/
for remote in `git branch -r `; do git branch --track $remote; done

Atualize as ramificações, supondo que não haja alterações em suas ramificações de rastreamento local:

for remote in `git branch -r `; do git checkout $remote ; git pull; done

Ignore os avisos ambíguos de refname, o git parece preferir o ramo local como deveria.

Otto
fonte
2
Obrigado pelo aviso sobre os avisos de refname. Isso foi útil.
Paul
1
Obrigado Otto, eu suspeitava que o script seria a única solução. Você forneceu uma bem simples.
Janson
1
@ Jason ainda é hoje a única solução para scripts?
28412 cregox
1
@Cawas: você precisa criar manualmente as ramificações de rastreamento, mas git pullpossui uma --allopção que buscará + mesclará todas as ramificações rastreadas.
naught101
13
Isso não funcionou para mim no Git 1.9.1. "git branch --track <banch_name>" cria um novo branch <branch_name> que rastreia o mestre local da filial, em vez da ramificação remota que desejávamos. Portanto, esse script criou várias ramificações locais, todas apontando para o mestre local. Vou postar a solução abaixo.
Val Blant
183

A resposta dada por Otto é boa, mas todos os ramos criados terão "origem /" como o início do nome. Se você deseja apenas que a última parte (após o último /) seja o seu nome de filial resultante, use este:

for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done

Ele também tem o benefício de não fornecer avisos sobre referências ambíguas.

tjmcewan
fonte
O Git não adicionará "origem" ao nome da filial de rastreamento local.
Adam Dymitruk 11/08/10
14
@adymitruk: Na verdade, ele se comporta exatamente como eu disse para mim no OSX 10.6.4, usando o git 1.7.2.2 (o último estável a partir deste comentário). Otto até menciona avisos ambíguos de refname - os avisos não precisariam existir se "origin /" não fizesse parte do nome de cada filial local. Aqui está a saída do 'git branch' após executar o comando do Otto: [mestre, origem / HEAD, origem / gráficos, origem / mestre, origem / produção, origem / preparação]. E meu comando: [gráficos, mestre, produção, encenação].
tjmcewan
1
+ Editar: encontrado article.gmane.org/gmane.comp.version-control.git/112575 explicando o porquê.
Philip Oakley
8
Eu concordo - esta é uma solução melhor do que a que atualmente é a resposta "aceita".
Tobias.mcnulty
2
Em vez de grep -v master, que tal grep -v /HEAD? Este parece filtrar o ramo padrão, sem a necessidade de personalização
dashrb
22

A maioria das respostas aqui está complicando a análise da saída de git branch -r. Você pode usar o seguinte forloop para criar as ramificações de rastreamento em todas as ramificações no controle remoto dessa maneira.

Exemplo

Digamos que eu tenho esses ramos remotos.

$ git branch -r
  origin/HEAD -> origin/master
  origin/development
  origin/integration
  origin/master
  origin/production
  origin/staging

Confirme se não estamos rastreando nada além de mestre, localmente:

$ git branch -l    # or using just git branch
* master

Você pode usar esse liner para criar as ramificações de rastreamento:

$ for i in $(git branch -r | grep -vE "HEAD|master"); do 
    git branch --track ${i#*/} $i; done
Branch development set up to track remote branch development from origin.
Branch integration set up to track remote branch integration from origin.
Branch production set up to track remote branch production from origin.
Branch staging set up to track remote branch staging from origin.

Agora confirme:

$ git branch
  development
  integration
* master
  production
  staging

Para excluí-los:

$ git br -D production development integration staging 
Deleted branch production (was xxxxx).
Deleted branch development (was xxxxx).
Deleted branch integration (was xxxxx).
Deleted branch staging (was xxxxx).

Se você usar a -vvopção, git branchpoderá confirmar:

$ git br -vv
  development xxxxx [origin/development] commit log msg ....
  integration xxxxx [origin/integration] commit log msg ....
* master      xxxxx [origin/master] commit log msg ....
  production  xxxxx [origin/production] commit log msg ....
  staging     xxxxx [origin/staging] commit log msg ....

Repartição do loop for

O loop basicamente chama o comando git branch -r, filtrando qualquer ramo HEAD ou mestre na saída usando grep -vE "HEAD|master". Para obter os nomes apenas dos ramos menos a origin/substring, usamos a manipulação de strings do Bash ${var#stringtoremove}. Isto irá remover a seqüência, "stringtoremove" da variável $var. No nosso caso, estamos removendo a string origin/da variável $i.

NOTA: Como alternativa, você também pode git checkout --track ...fazer isso:

$ for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); do 
    git checkout --track $i; done

Mas eu particularmente não me importo com esse método, pois ele é alternado entre os ramos enquanto ele faz um checkout. Quando terminar, deixará você no último ramo que ele criou.

Referências

slm
fonte
1
Funciona perfeitamente com a versão git 2.3.2 (Apple Git-55)
Andrewd
22

Atualização Q1 2020: Mohsen Abasi propõe nos comentários , com base em 2014 SLM 's resposta , a alternativa mais simples:

for i in $(git branch -r | grep -vE "HEAD|master" | sed 's/^[ ]\+//'); 

E usa em $()vez de reticulares obsoletos .

Como mencionei em outra resposta antiga , o uso git for-each-refé provavelmente mais rápido .
E eu usaria o novo git switchcomando (Git 2.23+) , que substitui o confusogit checkout .

for i in $(git for-each-ref --format=%(refname:short) \
  --no-merged=origin/HEAD refs/remotes/origin); do \
    git switch --track $i; \
done

Dessa forma, não é grepnecessário.


Old (2011) resposta original:

Aqui está o meu one-liner que eu uso (em um shell bash, testado com o msysgit1.7.4):

Para copiar e colar:

remote=origin ; for brname in `git branch -r | grep $remote | grep -v master | grep -v HEAD | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'`; do git branch --set-upstream-to $remote/$brname $brname; done

Para mais legibilidade:

remote=origin ; // put here the name of the remote you want
for brname in `
    git branch -r | grep $remote | grep -v master | grep -v HEAD 
    | awk '{gsub(/^[^\/]+\//,"",$1); print $1}'
`; do 
    git branch --set-upstream-to $remote/$brname $brname; 
done
  • ele selecionará apenas ramificações upstream do controle remoto especificado na remotevariável (pode ser ' origin' ou qualquer nome que você tenha definido para um dos controles remotos do seu repositório atual do Git).
  • extrairá o nome do ramo: origin/a/Branch/Name => a/Branch/Nameatravés da awkexpressão
  • ele definirá a ramificação upstream através de --set-upstream-to(ou -u) , não --track:
    A vantagem é que, se a ramificação já existir, ela não falhará e não mudará a origem da ramificação, apenas definirá a branch.xxx.(remote|merge)configuração.

    branch.aBranchName.remote=origin
    branch.aBranchName.merge=refs/heads/a/Branch/Name
    

Esse comando criará ramificações locais para todas as ramificações remotas do upstream e definirá suas configurações remota e de mesclagem para essa ramificação remota.

VonC
fonte
5
Isso me dá "fatal: ramificação 'o que quer que seja' não existe" para cada ramificação que existe apenas no controle remoto e não possui uma ramificação local correspondente.
Chris Dodd
Eu acho que se um nome de filial contém / por exemplo: feature / rc-41-bckend, esta solução não funciona !!!!
Mohsen Abasi 10/03
@VonC Baseado na resposta de "slm": $ for i em $ (git branch -r | grep -vE "HEAD | master" | sed 's / ^ [] \ + //'); faça git checkout - siga $ i; feito
Mohsen Abasi 10/03
@MohsenAbasi Parece bom. Na minha resposta, mencionei o uso em --set-upstream-tovez de no --trackentanto.
VonC 10/03
@MohsenAbasi Incluí sua alternativa na resposta para obter mais visibilidade. Eu adicionei outra maneira possível de listar ramificações remotas e usar em git switchvez de git checkout. Mas a sua (muito boa) idéia permanece.
VonC 10/03
14

Você poderia escrever com bastante facilidade, mas não sei quando seria valioso. Esses ramos ficariam para trás rapidamente e você teria que atualizá-los o tempo todo.

As ramificações remotas serão automaticamente atualizadas, portanto, é mais fácil criar a ramificação local no ponto em que você realmente deseja trabalhar nela.

Dustin
fonte
2
Este é um bom ponto. O principal caso de uso em que estou pensando é configurar um ambiente de desenvolvimento local com base em um repositório remoto do git. Então, quando eu faço meu clone inicial, também quero rastrear todos os ramos remotos como estão naquele momento.
Janson
1
O prático git upatualiza todas as filiais locais.
Hugo Hugo
para mesclar dois repositórios e excluir o controle remoto
endólito
9
for i in `git branch -a | grep remote`; do git branch --track ${i#remotes/origin/} $i; done
Val Blant
fonte
4
Eu tive que adicionar um | grep -v HEADao pipeline para que ele funcionasse corretamente.
Elias Dorneles
9

sem nenhum script (em um diretório vazio):

$ git clone --bare repo_url .git
$ git config core.bare false
$ git checkout

depois disso, todas as ramificações remotas serão vistas como locais.


original (em russo) .

aleksandr barakin
fonte
Esta é a solução mais simples de longe e funcionou para mim no 2.21.0.windows.1
Rotsiser Mho
7

Se você deseja usar o PowerShell e seu controle remoto é chamado de origem. Então isso funciona.

git fetch    
git branch -r  | %{$_ -replace "  origin/"} | %{git branch --track $_ "origin/$_"}
BigMiner
fonte
Isso foi super útil, acabei usando uma ligeira variação para fazê-lo funcionar com meu git svn clone'drepositório:git branch -r | %{$_ -replace " origin/"} | %{git checkout -b $_ "origin/$_"}
Nate
Também fiz uma ligeira variação porque os meus ramos locais já existe:git branch -r | %{$_ -replace " origin/"} | %{git branch -u "origin/$_" $_}
ch271828n
3
for branch in `git branch -a | grep remotes | grep -v HEAD | grep -v master`; do  git branch --track ${branch##*/} $branch; done

Use isso e você não terá um aviso como: refname 'origin / dev' é ambíguo

bruziuz
fonte
3

Aqui está minha solução do comando BASH referente a @tjmcewan:

for remote in `git branch -r | grep -v /HEAD `; do git branch --track ${remote/"origin/"/""}; done

Meu objetivo é resolver o problema de que todas as ramificações criadas terão "origem /" como o início do nome, porque testei que $ variáveis ​​remotas ainda incluem "origem /":

for remote in `git branch -r | grep -v /HEAD`; do echo $remote ; done
Nick Tsai
fonte
Depois de testar o BASH de @tjmcewan, descobri que todos os nomes dos ramos rastreados sem 'origem /' no local, não sei por quê.
Nick Tsai
1
O primeiro comando cria ramificações que rastreiam "mestre". Não é isso que a maioria das pessoas pode querer.
Alexei Osipov
@AlexeiOsipov Thanks!
Nick Tsai
2

Para fazer o mesmo que a resposta de tjmcewan, mas no Windows, chame isso de um arquivo em lotes :

for /f "delims=" %%r in ('git branch -r ^| grep -v master') do git checkout --track %%r

Ou isso na linha de comando :

for /f "delims=" %r in ('git branch -r ^| grep -v master') do git checkout --track %r
Hugo
fonte
1

Do git 2.23 em diante:

for branch in `git branch -r | grep origin/`; do git switch -t -C ${branch#origin/} $branch; git pull; done

O -Csinalizador para git switchcria ou redefine se ele já existe.

documentação do switch git

AeroX
fonte
0

Caso você já tenha algumas filiais registradas e queira

  • confira todas as ramificações restantes do controle remoto
  • verifique se todas as filiais locais rastreiam as filiais remotas

você pode usar o seguinte script compatível com bash e zsh:

git branch -r | while read b; do if git branch | grep -q " ${b##*/}$"; then git branch --set-upstream ${b##*/} $b; else git branch --track ${b##*/} $b; fi; done
simonair
fonte
0
for rembranch in `git remote update 2>&1 > /dev/null ; git branch -r|egrep -wv "HEAD|master"`
do 
    git checkout --track -b `echo $rembranch|awk -F\/ '{print $2}'` $rembranch; 
done

Explicação:

linha 1: 'git branch -r' (seguido por 'git remote update' para atualizar as informações sobre alterações no remote) lista todas as ramificações remotas; 'egrep -vw' é usado para bater entradas com HEAD e mestre no resultado.

linha 3: acompanhe a ramificação remota nomeada enquanto a verifica localmente. Um awk simples é usado para evitar 'origin /' sendo o sufixo para ramificações locais.

ksvrgh
fonte
0

Usando o bash, se você quiser fazer check-out de todos os ramos:

for remote in `git branch -r`; do git checkout $(echo $remote | cut -d'/' -f 2); done

É importante observar que, quando você faz uma busca que desativa novas ramificações de rastreamento remoto, não possui automaticamente cópias editáveis ​​locais.

Jason Chen
fonte