Entendendo os branches remotos no Git
16 Jun 2020O Git foi pensado para ser ágil quando o assunto é criar, comparar, trocar e unificar branches, inclusive você é estimulado a usá-los sempre que possível.
Um branch no Git é um ponteiro para um commit, sim, somente um ponteiro. Isto torna as operações com branches muito rápidas. Tudo o que o git precisa saber é o commit inicial e percorrer seus ancestrais para formar o workind directory.
Existem dois tipos de branches: locais e remotos. Antes de falarmos sobre branches remotos, vamos entender como funcionam os branches locais.
Branches locais
Por padrão um branch chamado master
é criado quando um novo repositório é iniciado com o comando git init
. Vamos supor que você criou seu repositório e fez dois commits, assim você terá a estrutura abaixo.
master
↓
1 -- 2
A primeira forma de criar um novo branch é com o comanto git branch <nome>
. Vamos criar um branch chamado novo-botao
.
git branch novo-botao
git checkout novo-botao
Neste momento você tem a seguinte estrutura no seu repositório.
master
↓
1 -- 2
↑
novo-botao
Mas como o git sabe em qual branch você está trabalhando? Através da mesma técnica dos branches: um ponteiro.
Existe um ponteiro chamado HEAD
que assim como um branch, aponta para um commit. O ponteiro HEAD
aponta para o commit atual do seu workind directory
, já o branch aponta para o último commit naquele branch.
Saiba mais sobre o
working directory
em As três árvores do Git
master ← HEAD
↓
1 -- 2
↑
novo-botao
Este comando git branch
cumpre o que promete: cria um novo branch, e somente isto. Portanto é necessário usar o comando git checkout <nome>
para trocar de branch.
master
↓
1 -- 2
↑
novo-botao ← HEAD
Você pegar um atalho e criar um branch e ao mesmo tempo o acessar. Use o argumento
-p
no comandocheckout
, assim o comando ficarágit checkout -b <nome>
.
Você mudou para o novo branch e já pode começar a registar seus commits.
master
↓
1 -- 2
\
3 -- 4
↑
HEAD → novo-botao
Não é incomum surgir a necessidade de parar o trabalho atual por um momento para trabalhar em outro assunto mais urgente. Então você muda para o branch master
para não misturar as alterações.
git checkout master
master ← HEAD
↓
1 -- 2
\
3 -- 4
↑
novo-botao
A partir do momento em que registar alguma alteração no branch master
, as duas histórias ficarão divergentes e cada vez que acessar um branch, você terá arquivos diferentes no seu working directory, pois ambos branches tem alterações diferentes.
HEAD → master
↓
1 -- 2 -- 5 -- 6
\
3 -- 4
↑
novo-botao
Terminado seu trabalho na master
, você volta para o branch novo-botão
e registra mais um commit.
master
↓
1 -- 2 -- 5 -- 6
\
3 -- 4 -- 5
↑
HEAD → novo-botao
Você terminou seu trabalho no branch novo-botao
e quer colocar estas alterações no branch master para serem publicadas.
Unificando histórias
O comando mais comum para unir duas histórias (ou branches se preferir) é o merge
, com este comando você, a pardir do branch que está no momento, indica qual branch será unificado.
Se quiser colocar as alterações de novo-botao
no branch master
você precisa mudar para o branch master
e em seguida solicitar a união do novo-botao
ao Git.
git checkout master
git merge novo-botao
E nasceu um tipo especial de commit: o commit de merge. A diferença deste commit para um commit comum é que este tem dois ancestrais, um em master
e outro em novo-botao
.
Geralmente um commit de merge tem apenas a referência para seus ancestrais, mas também pode conter alterações neste commit, comom a resolução de um conflito.
HEAD → master
↓
1 -- 2 -- 5 -- 6 -- 7*
\ /
3 -- 4 -- 5
↑
novo-botao
Com o trabalho finalizado em novo-botao
, você pode removê-lo com o comando git branch -d novo-botao
.
Tudo isto aconteceu localmente (outro superpoder que torna o Git rápido), mas em um cenário comum você estará sincronizando seu trabalho em um repositório comum para outras pessoas, que também irão sincronizar o trabalho delas.
Neste momento os branches remotos começam a brilhar mas antes você precisa conhecer o conceito de repositórios remotos.
Repositórios remotos
O Git é um controle de versão distribuído, portanto as alterações acontecem localmente por padrão e você pode sincronizar seu repositório com qualquer outro (com histórico em comum), inclusive mais de um repositório.
Com isto aparace o conceito de repositórios remotos. Internamente, o Git armazena o endereço de outro repositório (geralmente um endereço http ou ssh) e para que você o identifique de forma fácil, é vinculado a um apelido. Quando um repositório é clonado, o Git apelida este repositório de origin
.
Ao obter os commits de um repositório remoto, um tipo especial de branch é criado para identificar os branches do reposistório remoto. Estes branches são somente leitura e tem o formato <remoto>/<nome>
.
Como o Git cria o repositório remoto chamado origin
, a branch master
deste repositório tem o nome de origin/master
.
Lembra que o Git trabalha localmente por padrão? Assim depois de sincronizar os commits do repositório remoto com seu repositório local, você pode efetuar comparações e até obter o histórico deste repositório, com todas operações sendo locais, fantástico não?
Agora que você já sabe sobre o novo tipo de branch, vamos ilustrar sua estrutura?
Branches remotos
Quando começa a trabalhar em um repositório compartilhado, você geralmente faz um clone do repositório com o comando git clone <endereço>
.
Imagine que o repositório remoto tem a estrutura abaixo.
master
↓
1 -- 2 -- 3
Ao cloná-lo, você terá a seguinte estrutura localmente.
HEAD → origin/master
↓
master
↓
1 -- 2 -- 3
E outra pessoa também clonou o repositório e registrou seus commits no repositório local dela.
REMOTO
master
↓
1 -- 2 -- 3
VOCÊ
origin/master
↓
master
↓
1 -- 2 -- 3
OUTRA PESSOA
origin/master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6
↑
HEAD → master
Um cenário muito comum é outras pessoas sincronizarem suas alterações antes de você, deixando o repositório REMOTO diferente do que você havia obtido.
REMOTO
master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6
VOCÊ
origin/master
↓
master
↓
1 -- 2 -- 3
O ideal é você obter os commits do repositório remoto constantemente, mas para não perder o raciocínio do trabalho você registra seus commits normalmente.
REMOTO
master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6
VOCÊ
HEAD → master
↓
1 -- 2 -- 3 -- 7 -- 8 -- 9
Ao tentar enviar suas alterações com o comando git push origin
, o git irá te avisar de que existem alterações não sincronizadas, então você executa o comando git pull origin
.
O comando pull
é feito em duas etapas, a primeira é executar o comando fetch
seguido do comando merge
.
Na prática seria o equivalente a
git fetch origin
egit merge origin/master
Na etapa do fetch
interno seu repositório local tem as alterações do repositório principal, identificadas pelo branch especial origin/master
.
VOCÊ
origin/master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6
\
7 -- 8 -- 9
↑
HEAD → master
Ao ser executado na sequência o comando merge
unifica as duas histórias que se divergiram, através de um commit de merge (aquele que tem dois ancestrais).
VOCÊ
HEAD
↓
origin/master master
↓ ↓
1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 10*
\ /
7 --- 8 --- 9 ---
Feito o merge
, você já pode enviar suas alterações para o repositório remoto com o comando git push origin
novamente.
REMOTO
master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 10*
\ /
7 --- 8 --- 9 ---
VOCÊ
HEAD → origin/master → master
↓
1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 10*
\ /
7 --- 8 --- 9 ---
Conclusão
Neste texto vimos o que são branches, como criar um e como unificar as histórias que se divergem através do comando merge
, tudo isso de forma local (sem necessitar de uma conexão de rede).
Descobrimos o que são repositórios remotos, como são armazenados pelo Git e o tipo especial de branches que são criados no seu repositório local. Para sincronizar os repositórios, aprendemos sobre os comandos pull
e push
.
Gostou? Deixe um comentário sobre o que achou. Se tiver alguma dúvida, comente aqui que terei o prazer de te ajudar.
Até mais.