Git
Chapters ▾ 2nd Edition

3.5 Branches no Git - Branches remotos

Branches remotos

Referências remotas são referências (ponteiros) em seus repositórios remotos, incluindo branches, tags e assim por diante. Você pode obter uma lista completa de referências remotas explicitamente com git ls-remote [remote] ou git remote show [remote] para branches remotos, bem como mais informações. No entanto, uma forma mais comum é aproveitar as branches de rastreamento remoto.

Branches de rastreamento remoto são referências ao estado de branches remotas. São referências locais que você não pode mover; eles são movidos automaticamente para você sempre que você fizer qualquer comunicação de rede. Branches de rastreamento remoto agem como marcadores para lembrá-lo de onde estavam as branches em seus repositórios remotos da última vez que você se conectou a eles.

Eles assumem a forma (remoto)/(branch). Por exemplo, se você quiser ver como era o branch master em seu branch remoto origin da última vez que você se comunicou com ele, você deve verificar o branch origin/master. Se você estava trabalhando em um problema com um parceiro e ele enviou um branch iss53, você pode ter seu próprio branch local iss53; mas o branch no servidor apontaria para o commit em origin/iss53.

Isso pode ser um pouco confuso, então vamos ver um exemplo. Digamos que você tenha um servidor Git em sua rede em git.ourcompany.com. Se você clonar a partir dele, o comando clone do Git automaticamente o nomeia como origin para você, puxa todos os seus dados, cria um ponteiro para onde seu branch master está e o nomeia origin/master localmente. O Git também fornece seu próprio branch master local começando no mesmo lugar que o branch master de origem, então você tem algo a partir do qual trabalhar.

Note
“origin” não é especial

Assim como o nome do branch “master” não tem nenhum significado especial no Git, tampouco o “origin”. Enquanto “master” é o nome padrão para um branch inicial quando você executa git init que é a única razão pela qual é amplamente usado,“origin” é o nome padrão para um repositório remoto quando você executa git clone. Se você executar git clone -o booyah em vez disso, terá booyah/master como seu branch remoto padrão.

Server and local repositories after cloning.
Figure 30. Repositório local e servidor após o clone

Se você fizer algum trabalho em seu branch master local e, nesse ínterim, outra pessoa enviar um push para git.ourcompany.com e atualizar seu branch master, então seus históricos avançam de forma diferente. Além disso, contanto que você fique fora de contato com o servidor de origem, o ponteiro origin/master não se move.

Local and remote work can diverge.
Figure 31. Repositório local e remoto podem divergir

Para sincronizar seu trabalho, você executa um comando git fetch origin. Este comando procura em qual servidor está a “origin” (neste caso, é git.nossaempresa.com), busca quaisquer dados que você ainda não tenha, e atualiza seu banco de dados local, movendo seu ponteiro origin/master para sua nova posição mais atualizada.

`git fetch` updates your remote references.
Figure 32. git fetch atualiza suas preferências remotas

Para demonstrar a existência de vários servidores remotos e como se parecem os branches remotos para esses projetos, vamos supor que você tenha outro servidor Git interno usado apenas para desenvolvimento por uma de suas equipes. Este servidor está em git.team1.ourcompany.com. Você pode adicioná-lo como uma nova referência remota ao projeto em que está trabalhando atualmente executando o comando git remote add conforme abordamos em [ch02-git-basics]. Nomeie este servidor remoto como teamone, que será o seu apelido para toda a URL.

Adding another server as a remote.
Figure 33. Adicionando outro servidor como remoto

Agora, você pode executar git fetch teamone para buscar tudo o que o servidor remoto teamone tem que você ainda não tem. Porque esse servidor tem um subconjunto dos dados que seu servidor origin tem agora, o Git não busca nenhum dado, mas define um branch remoto de rastreamento chamado teamone/master para apontar para o commit que teamone tem como seu branch master.

Remote tracking branch for `teamone/master`.
Figure 34. Branch remoto de rastreamento para teamone/master

Empurrando (Push)

Quando você deseja compartilhar um branch com o mundo, você precisa transferi-lo para um servidor remoto ao qual você tenha acesso de gravação. Seus branches locais não são sincronizados automaticamente com os branches remotos para os quais você escreve - você tem que empurrar explicitamente os branches que deseja compartilhar. Dessa forma, você pode usar branches privados para o trabalho que não deseja compartilhar e fazer o push apenas dos brnaches de tópicos nos quais deseja colaborar.

Se você tem um branch chamado serverfix que deseja trabalhar com outros, pode enviá-lo da mesma forma que fez o push do primeiro branch. Execute git push <remote> <branch>:

$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix

Este é um atalho. O Git expande automaticamente o branch serverfix para refs/heads/serverfix:refs/heads/serverfix, o que significa, “Pegue meu branch local serverfix e empurre-o para atualizar o branch serverfix remoto.” Veremos a parte refs/heads/ em detalhes em [ch10-git-internals], mas geralmente você pode deixá-la desativada. Você também pode fazer git push origin serverfix:serverfix, que faz a mesma coisa - “Pegue meu serverfix e torne-o o serverfix remoto.” Você pode usar esse formato para enviar um branch local para um branch remoto com um nome diferente. Se você não quiser que ele seja chamado de serverfix no remoto, você pode executar git push origin serverfix:awesomebranch para enviar seu branch local serverfix para o branch awesomebranch no projeto remoto.

Note
Não digite sua senha todo o tempo

Se você estiver usando uma URL HTTPS para fazer push, o servidor Git solicitará seu nome de usuário e senha para autenticação. Por padrão, ele solicitará essas informações no terminal para que o servidor possa dizer se você tem permissão para fazer push.

Se você não quiser digitá-lo toda vez que for fazer o push, você pode configurar um “credential cache”. O mais simples é mantê-lo na memória por alguns minutos, o que você pode configurar facilmente executando git config --global credential.helper cache.

Para obter mais informações sobre as várias opções de “credential cache” disponíveis, consulte Credential Storage.

Na próxima vez que um de seus colaboradores buscar no servidor, eles obterão uma referência de onde a versão do servidor do serverfix está no branch remoto origin/serverfix:

$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix

É importante notar que quando você faz uma busca que desativa novos branches remotos de rastreamento, você não tem automaticamente cópias locais editáveis deles. Em outras palavras, neste caso, você não tem um novo branch serverfix - você só tem um ponteiro origin/serverfix que você não pode modificar.

Para mesclar este trabalho em seu branch atual, você pode executar git merge origin/serverfix. Se você quiser seu próprio branch serverfix com o qual possa trabalhar, pode basear-se em seu branch remoto:

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Isso lhe dá um branch local no qual você pode trabalhar que inicia onde está o origin/serverfix.

Rastreando Branches

Fazer check-out de um branch local de um branch remoto cria automaticamente o que é chamado de “tracking branch” (e o branch que ele rastreia é chamado de “branch upstream”). “Tracking branch” são branches locais que têm um relacionamento direto com um branch remoto. Se você estiver em um branch de rastreamento e digitar git pull, o Git saberá automaticamente de qual servidor buscar o branch para fazer o merge.

Quando você clona um repositório, geralmente ele cria automaticamente um branch master que rastreia origin/master. No entanto, você pode configurar outros branches de rastreamento se desejar - aqueles que rastreiam branches em outros branches remotos ou não rastreiam o branch master. O caso simples é o exemplo que você acabou de ver, executando git checkout -b [branch] [remotename]/[branch]. Esta é uma operação suficiente para que o Git forneça a abreviação --track:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Na verdade, isso é tão comum que existe até um atalho para isso. Se o nome do branch que você está tentando verificar (a) não existe e (b) corresponde exatamente a um nome em apenas um repositório remoto, o Git criará um branch de rastreamento para você:

$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Para configurar um branch local com um nome diferente do branch remoto, você pode usar facilmente a primeira versão com um nome de branch local diferente:

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

Agora, seu branch local sf irá puxar automaticamente de origin/serverfix.

Se você já tem um branch local e deseja configurá-lo para um branch remoto que acabou de puxar, ou deseja alterar o branch upstream que está rastreando, você pode usar o método -u ou --set-upstream-to para git branch para configurá-lo explicitamente a qualquer momento.

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Note
O Atalho Upstream

Quando você tem um branch de rastreamento configurado, pode referenciar seu branch upstream com as abreviações @{upstream} ou @{u}. Então, se você está no branch master e está rastreando origin/master, você pode dizer algo como git merge @{u} ao invés de git merge origin/master se desejar.

Se você quiser ver quais branches de rastreamento você configurou, você pode usar a opção -vv para git branch. Isso listará seus branches locais com mais informações, incluindo o que cada filial está rastreando e se sua filial local está à frente, atrás ou ambos.

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
  master    1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
  testing   5ea463a trying something new

Portanto, aqui podemos ver que nosso branch iss53 está rastreando origin/iss53 e está “ahead” por dois, o que significa que temos dois commits localmente que não são enviados ao servidor. Também podemos ver que nosso branch master está rastreando origin/master e está atualizado. Em seguida, podemos ver que nosso branch serverfix está rastreando o branch server-fix-good em nosso servidor teamone e está à frente de três e atrás de um, o que significa que há um commit no servidor que não foi mesclado ainda e três commits localmente que não foram enviados por push. Finalmente, podemos ver que nosso branch testing não está rastreando nenhum branch remoto.

É importante observar que esses números são apenas desde a última vez que você fez um fetch em cada servidor. Este comando não chega aos servidores, ele está informando sobre o que armazenou localmente em cache. Se você quiser ficar totalmente atualizado com os números à frente e atrás, precisará buscar em todos os seus servidores remotos antes de executá-lo. Você poderia fazer isso assim:

$ git fetch --all; git branch -vv

Fazendo o Pull

While the git fetch command will fetch down all the changes on the server that you don’t have yet, it will not modify your working directory at all. It will simply get the data for you and let you merge it yourself. However, there is a command called git pull which is essentially a git fetch immediately followed by a git merge in most cases. If you have a tracking branch set up as demonstrated in the last section, either by explicitly setting it or by having it created for you by the clone or checkout commands, git pull will look up what server and branch your current branch is tracking, fetch from that server and then try to merge in that remote branch.

Generally it’s better to simply use the fetch and merge commands explicitly as the magic of git pull can often be confusing.

Embora o comando git fetch baixe todas as alterações no servidor que você ainda não tem, ele não modificará seu diretório de trabalho. Ele simplesmente obterá os dados para você e permitirá que você mesmo os mescle. No entanto, existe um comando chamado git pull que é essencialmente um git fetch seguido imediatamente por um git merge na maioria dos casos. Se você tiver um branch de rastreamento configurado conforme demonstrado na última seção, seja explicitamente configurando-o ou tendo-o criado para você pelos comandos clone ou checkout, git pull irá procurar qual servidor e branch seu branch atual está rastreando, buscará naquele servidor e, em seguida, tentará mesclar nesse branch remoto.

Geralmente é melhor usar os comandos fetch e merge explicitamente, já que o git pull muitas vezes pode ser confuso.

Removendo Branches remotos

Suponha que você terminou com um branch remoto - digamos que você e seus colaboradores terminaram com um recurso e o fundiram no branch master do seu servidor remoto (ou em qualquer branch em que sua linha de código estável esteja). Você pode deletar um branch remoto usando a opção --delete para git push. Se você deseja excluir seu branch serverfix do servidor, execute o seguinte:

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

Basicamente, tudo o que isso faz é remover o ponteiro do servidor. O servidor Git geralmente mantém os dados lá por um tempo até que seja removido definitivamente pelo Git, então, se ele foi excluído acidentalmente, geralmente é fácil de recuperar.