Recebi a seguinte dúvida:

Preciso levar um repositório de um team project para outro, então clonei na minha máquina e apontei para um outro remote, e fiz o push… porém as branch’s do repositório de origem não foram para o destino, o que fazer?

Quando você faz um clone de um repositório, o Git não está fazendo o tracking de todas as branch’s remotas, é preciso baixar elas para poder fazer o push de tudo. Mas se o meu repositório tem dezenas delas, como executar de uma maneira rápida? Usando o poder do Powershell.

Para pegar todas as branch’s é fácil:

git branch -a

2016-04-05 02_34_08-posh~git ~ code-cracker [master]

Onde o -a lista tanto branch’s locais como remotas.

Dai se poderia interar na coleção de strings:

git branch -a | % {$_ (...)

E então era trabalhar com elas para chegar aos nomes das branch’s e poder executar um checkout.

Porém, consultando o Giovanni Bassi, ele me chamou a atenção para o comando: git ls-remote.

git ls-remote

Este comando lista as referências do repositório remoto, se executarmos no repositório do code-cracker teremos uma longa lista de branch’s (1), pull request’s (2) e tag’s (3):

2016-04-05 02_45_41-posh~git ~ code-cracker [master]

O objetivo é levar as branch’s para o outro repositório, então vamos usar:

git ls-remote --heads origin

2016-04-05 02_53_55-posh~git ~ code-cracker [master]

-match e $matches

Agora que temos uma coleção de referências, vamos buscar filtrar somente o nome das branch’s.

Para isso faremos uso do operador de comparação do Powershell -match. Passando o pattern, baseado em RegEx, ‘refs/heads/(.*)’, iremos testar, se a referência na coleção é qualquer coisa que tenha no início da string refs-barra-heads-barra.

git ls-remote --heads origin | % { $_ -match 'refs/heads/(.*)' }

2016-04-05 03_23_27-posh~git ~ code-cracker [master]

Executando a linha acima, teremos a confirmação de que todas batem com o padrão. Mas… o objetivo não é esse ao usar o -match. O legal é que o Powershell irá criar uma coleção dos matches, com nome de variável $matches, sempre! Essa variável é um hashtable key-value, ou chave-valor, é possível chamá-la na sessão digitando o seu nome:

$matches

2016-04-05 03_31_12-posh~git ~ code-cracker [master]

Portanto se quisermos só o nome da branch, basta pegar o conteúdo no índice 1!

O que é preciso fazer agora é passar essa coleção para a próxima execução de comando, mas ignorando a resposta da iteração, ou seja os True. Para isso usamos out-null, porém, repassamos os matches para serem processados no próximo pipe, o comando fica assim:

git ls-remote --heads origin | % { $_ -match 'refs/heads/(.*)' | out-null; $matches[1] }

2016-04-05 03_39_27-posh~git ~ code-cracker [master]

git checkout

Agora só é preciso iterar na coleção de nomes, fazendo o checkout das branch’s.

git ls-remote --heads origin | % { $_ -match 'refs/heads/(.*)' | out-null; $matches[1] } | % { git checkout $_ }

2016-04-05 03_41_27-posh~git ~ code-cracker [vnext]

Só mandar o push para o outro remote!

Emmanuel Brandão