Chapters ▾ 2nd Edition

10.5 Git Internals (Por Dentro do Git) - Refspec

Refspec

Ao longo deste livro, usamos mapeamentos simples de branches remotos para referências locais, mas eles podem ser mais complexos. Suponha que você estava acompanhando as últimas seções e criou um pequeno repositório Git local, e agora queria adicionar um remoto (remote) a ele:

$ git remote add origin https://github.com/schacon/simplegit-progit

Executar o comando acima adiciona uma seção ao arquivo .git/config do seu repositório, especificando o nome do remoto (origin), a URL do repositório remoto e a refspec a ser usada para a busca (fetching):

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/*:refs/remotes/origin/*

O formato do refspec é, primeiro, um + opcional, seguido por <src>:<dst>, onde <src> é o padrão para referências no lado remoto e <dst> é onde essas referências serão rastreadas localmente. O + diz ao Git para atualizar a referência, mesmo se não for um fast-forward.

No caso padrão que é automaticamente escrito por um comando git remote add origin, o Git busca todas as referências sob refs/heads/ no servidor e as escreve para refs/remotes/origin/ localmente. Então, se houver um branch master no servidor, você pode acessar o log daquele branch localmente por meio de qualquer um dos seguintes:

$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master

Eles são todos equivalentes, porque o Git expande cada um deles para refs/remotes/origin/master.

Se, em vez disso, você quiser que o Git faça o pull apenas do branch master a cada vez, e não de todos os outros branches no servidor remoto, você pode alterar a linha de fetch para se referir apenas àquele branch:

fetch = +refs/heads/master:refs/remotes/origin/master

Esse é apenas o refspec padrão para o comando git fetch para aquele remoto. Se você quiser fazer uma busca apenas uma vez, você também pode especificar o refspec específico na linha de comando. Para fazer pull do branch master do remoto para origin/mymaster localmente, você pode executar:

$ git fetch origin master:refs/remotes/origin/mymaster

Você também pode especificar múltiplos refspecs. Na linha de comando, você pode fazer pull de vários branches assim:

$ git fetch origin master:refs/remotes/origin/mymaster \
	 topic:refs/remotes/origin/topic
From git@github.com:schacon/simplegit
 ! [rejected]        master     -> origin/mymaster  (non fast forward)
 * [new branch]      topic      -> origin/topic

Neste caso, o pull do branch master foi rejeitado porque não foi listado como uma referência fast-forward. Você pode anular isso especificando o + na frente do refspec.

Você também pode especificar múltiplos refspecs para buscar no seu arquivo de configuração. Se você quiser buscar sempre os branches master e experiment a partir do remote origin, adicione duas linhas:

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/experiment:refs/remotes/origin/experiment

Desde o Git 2.6.0, você pode usar globs parciais no padrão para combinar múltiplos branches, então isso funciona:

fetch = +refs/heads/qa*:refs/remotes/origin/qa*

Ainda melhor, você pode usar namespaces (ou diretórios) para realizar o mesmo com mais estrutura. Se você tem uma equipe de controle de qualidade (QA) que envia uma série de branches, e você quer obter o branch master e qualquer um dos branches da equipe de QA, mas nada mais, você pode usar uma seção de configuração assim:

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*

Se você tiver um processo de fluxo de trabalho complexo que tem uma equipe de controle de qualidade (QA) submetendo branches (pushing), desenvolvedores submetendo branches e equipes de integração submetendo e colaborando em branches remotas, será possível classificá-las em um namespace com facilidade dessa forma.

Submetendo Refspecs (Pushing)

É bom que você possa buscar referências no namespace dessa forma, mas como a equipe de QA consegue colocar seus branches em um namespace qa/ em primeiro lugar? Você consegue isso usando refspecs para fazer o push.

Se a equipe de QA quiser enviar seu branch master para qa/master no servidor remoto, ela pode executar:

$ git push origin master:refs/heads/qa/master

Se eles quiserem que o Git faça isso automaticamente toda vez que executarem git push origin, eles podem adicionar um valor push ao seu arquivo de configuração:

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/*:refs/remotes/origin/*
	push = refs/heads/master:refs/heads/qa/master

Mais uma vez, isso fará com que um git push origin envie o branch master local para o branch remoto qa/master por padrão.

Note

Não é possível usar a especificação de ref para buscar em um repositório e enviar para outro. Para obter um exemplo de como fazer isso, consulte Mantenha o seu repositório público do GitHub atualizado.

Excluindo Referências

Você também pode usar o refspec para excluir referências do servidor remoto, executando algo assim:

$ git push origin :topic

Como o refspec é <src>:<dst>, ao deixar de fora a parte <src>, isso basicamente diz para transformar o branch topic no remoto em nada, o que a exclui.

Ou você pode usar a sintaxe mais nova (disponível desde o Git v1.7.0):

$ git push origin --delete topic