Como usar branches e merge no GIT
⚡Atenção⚡
Este artigo usa o universo da série Loki como uma metáfora divertida para explicar como o Git funciona ao utilizar comandos branches e merge. As comparações são criativas e não seguem regras científicas ou técnicas ao pé da letra.
Como usar branches e merge no Git: Introdução
Muito se fala sobre Git na hora de salvar projetos ou manter diferentes versões de um software. Inicialmente, quando pensamos em versões é natural associá-las com o lançamento de uma nova funcionalidade ou versão de segurança melhorada. E de fato, esse pensamento não é errôneo.
Mas, afinal, como de fato funciona o controle de versão no dia-a-dia de um programador?
Para entender melhor o conceito de versionamento, podemos nos apropriar de um assunto nada convencional: multiverso na série "Loki". A maneira como Loki lida com realidades distintas nos ajuda a compreender, de forma didática, o que o Git faz e como é possível unir essas linhas temporais alternativas em uma linha principal.
A série Loki
Na série Loki conhecemos a AVT (Autoridade de Variação Temporal) que é uma organização que controla uma única “Linha do Tempo Sagrada”. Tudo que foge do script pré-estabelecido é considerado uma "variante" e pode gerar uma ramificação. Se uma ramificação cresce demais, pode causar um evento de “incursão”. O próprio Loki da série é uma variante, uma versão alternativa que escapou com o Tesseract em Vingadores: Ultimato. Ele descobre que existem múltiplas versões de si mesmo — inclusive um Loki jacaré, criança e até um presidente. Isso reforça a ideia de ramificações independentes evoluindo de formas diferentes.
E o que o Git tem a ver com Loki?
É mais simples do que parece. Imagine que a AVT seja o Git que é responsável por controlar a linha do tempo principal do seu projeto. Nele foi adicionado uma nova funcionalidade, ou seja, em comparação com a série televisiva Loki, uma nova variante criou uma ramificação na qual chamaremos de branch. Essa nova branch é uma cópia exata do seu projeto que logo sofrerá alterações sem alterar a realidade da linha do tempo principal, a branch master. Já a incursão da série servirá de analogia para o entendimento do conceito merge, mas sem a finalidade destrutiva do projeto. Útil, não é? E isso é crucial, especialmente em aplicações sofisticadas que demandam colaboração de diversos desenvolvedores de software. Cada um poder trabalhar em diferentes pontos do projeto, criando suas próprias branches para novas funcionalidades, sem interferir na tarefa de outro. Ao final, essas ramificações podem ser integradas por meio do processo de merge — ou, como na analogia com a série Loki, realizando uma “incursão” controlada na linha do tempo principal.
Segundo a documentação oficial do Git: "Ramificação significa que você diverge da linha principal de desenvolvimento e continua a trabalhar sem alterar essa linha principal."
Git na prática
Para fins de entendimento será usado um exemplo simples de um projeto que contenha apenas um arquivo index.html
e será utilizado cada comando no terminal na pasta raíz do projeto para melhor entendimento. É importante também que você tenha instalado o git e o visual studio code em sua máquina.
- Comando: git init
Na pasta raiz do seu projeto utilize o comando git init
para inicializar o seu repositório.
Assim que o comando executar aparecerá: Initialized empty Git repository...
- Comando git status
O comando git status
nos permite verificar quais arquivos foram adicionados ou modificados. Os arquivos adicionados após o git init são considerados como untracked no repositório e os arquivos modificados são considerados Changes not staged for commit.
- Comando: git add
O projeto ainda não está com o seus arquivos rastreados. Para rastreá-los use o comando git add .
ou git add index.html
já que esse é único arquivo modificado.
- Comando: git commit
Para para completar esta etapa commitamos o projeto com o seguinte comando: git commit -m "first commit
. Onde "first commit" será a descrição desse commit.
Dando tudo certo aparecerá:
- Comando: git log
Usaremos o comando git log
para recebermos informações importantes e nos situar nas branches e merges do projeto a partir de agora.
Na imagem temos:
- Na primeira linha temos o HASH do commit em amarelo
- Na mesma linha temos o HEAD que está apontando para a branch master
- O autor que produziu o commit e seu email
- Temos a descrição do commit que informamos
1. Git Branch
Feito tudo isso, agora podemos criar nossa a primeira ramificação usando o comando git checkout -b new_tittle
ou git branch new_tittle
.
Explicação rápida do comando git checkout -b new_tittle
por partes:
- git checkout: serve para mudar para um branch
- -b: cria uma nova branch
- new_tittle: é o nome da branch a ser criada
Em resumo o comando criará a branch chamada new_tittle
e mudará para ela.
Se você usou git branch new_tittle
apenas será criada um branch com o nome new_tittle
sem mudar para ela.
Com o comando git checkout -b new_tittle
git informará: Switched to a new branch 'new_tittle', confirmando a criação e a troca. No canto inferior esquerdo do seu vsCode também informará em qual branch atual você está.
Se usarmos o comando git log
novamente veremos que alguns informações mudaram, pois o HEAD agora está apontando para a nova branch:
Ainda na branch new_tittle, adicionaremos a tag h1 no arquivo index.html
. Feito isso podemos usar novamente o comando git add .
, git commit -m "add new tittle"
para confirmarmos a alteração nesta ramificação. Agora nosso git log
nos mostra dois commits recentes com Hashs diferentes e também com a nova descrição add new tittle
no commit mais recente.
Se utilizarmos o comando git checkout master
e git checkout new_tittle
para alternar entre as branches percebemos que a tag h1 que criamos some e reaparece, pois estamos alternando entre ramificações.
2. Git Merge
Agora o que precisamos fazer é trazer as alterações realizadas na branch new_tittle
para a branch master
. Certifique-se de estar na brach master
para mandarmos o seguinte comando ao git merge new_tittle
.
O comando git merge
pega as alterações feitas em uma branch e integra essas mudanças na branch atual em que você está.
- Na primeira linha será informado que está tendo alteração na branch
master
trazendo as mudança danew_tittle
através dos respectivos Hashes. - Fast-forward incida que não foi preciso criar um commit de merge. O Git automaticamente avançou o ponteiro do branch para o commit mais recente, como se tivesse "andado em linha reta".
- O commit de merge é um commit especial criado pelo Git para juntar o histórico de duas branches que evoluíram em paralelo. Ou seja, quando a branch
new_tittle
estava sendo escrita um outro desenvolvedor fez um commit na branchmaster
.
Alguns tipos de conflitos no Merge
É comum em algum momento na vida do desenvolvedor encontrar conflitos no merge, esses possíveis conflitos são:
- O primeiro tipo de conflito que pode ocorrer no merge é quando duas branches diferentes alteram o mesmo arquivo e o git não saberá qual delas manter.
- Modificação de arquivo que ocorre quando um dos desenvolvedores pode por exemplo alterar o nome do arquivo no qual outro desenvolvedor esteja trabalhando e na hora de fazer o merge o git não identifica mais este arquivo.
- Mudança na estrutura do projeto que ocorre quando alguém move o arquivo para outro local e o git não consegue mais encontrá-lo.
Boas práticas no Git
As boas práticas no Git são hábitos e padrões que ajudam a manter o código limpo, organizado, seguro e fácil de colaborar. Elas são especialmente importantes em projetos com múltiplos desenvolvedores, mas também são úteis para quem trabalha sozinho e quer manter um bom histórico de desenvolvimento.
Duas práticas que são comumente utilizadas em projetos:
- Nunca trabalhar na branch master/main: isso evitará conflitos com merge e facilitará a revisão do código antes que alterações sejam mescladas e implatadas, promovendo a colaboração entre os desenvolvedores.
- Nomear branches: trará legibilidade e padronização nas mensagens permitindo gerar changelogs de maneira prática.
feat: adição de uma nova funcionalidade;
- Exemplo: feat/filtro_de_pesquisa
fix: a correção de um bug;
- Exemplo: fix/correção_filtro_de_pesquisa_pelo_primeiro_nome
hotfix: Correção urgente em produção
- Exemplo: hotfix/correção_autenticação_usuário
refactor: Refatoração de código (sem mudar o resultado final)
- Exemplo: refactor/tela_de_login_usuário
Conclusão
É fundamental que todo desenvolvedor aprenda a utilizar tanto merge quanto branches, pois são recursos que permitem uma melhor organização separando funcionalidades, correções e testes sem causar confusão no desenvolvimento do projeto.
Além disso, facilitam a participação da equipe, onde cada membro pode trabalhar em diferentes pontos do projeto, minimizando conflitos diretos. Elas também criam ambientes para testar uma nova funcionalidade de formar isolada reduzindo bugs em produção, viabilizando a manutenção e correção de falhas.
Há vantagens em manter um histórico organizado e compreensível garantindo revisões e mudanças no código.
As branches integram a base de metodologias ágeis, CI (Continuous Integration (Integração Contínua)) / CD Continuous Delivery (Entrega Contínua) ou Continuous Deployment (Implantação Contínua), colocando o programador no caminho de um desenvolvimento profissional e moderno.
Referências
Conflitos com merge: https://www.dio.me/articles/o-que-sao-conflitos-de-merge
Por que não trabalhar na main: https://cityofaustin-github-io.translate.goog/ctm-dev-workflow/protected-branches.html?_x_tr_sl=en&_x_tr_tl=pt&_x_tr_hl=pt&_x_tr_pto=sge#:~:text=Nunca se deve trabalhar neste,entre os desenvolvedores do CoA.&text=Habilite as seguintes configurações:,Incluir administradores
Padrões de nomenclatura para branches: https://medium.com/prolog-app/nossos-padrões-de-nomenclatura-para-branches-e-commits-fade8fd17106
Branch em poucas palavras: https://git-scm.com/book/pt-br/v2/Branches-no-Git-Branches-em-poucas-palavras
Marvel (Loki, série da Disney+)