Resolvendo conflitos em Git
Resolver conflitos pode ser uma tarefa árdua e complicada quando se trata de projetos git. Nesse artigo você vai aprender um passo-a-passo infalível para resolver conflitos.
Caso você já saiba o que são conflitos e queira apenas ver a lista de passos e comandos para resolver um conflito sugiro que pule para a conclusão clicando aqui.
O que é um conflito em git
Quando um projeto tem várias pessoas trabalhando ao mesmo tempo, é possível que duas pessoas precisem fazer alterações no mesmo pedaço de um arquivo. Quando mais de uma pessoa altera o mesmo pedaço de um arquivo em branches diferentes é nesse momento que os conflitos aparecem.
O conflito simboliza que duas ou mais alterações aconteceram no mesmo pedaço de um arquivo e o git não sabe qual das alterações manter.
Como um conflito se forma
Na imagem abaixo temos um diagrama que eu carinhosamente apelidei de “anatomia de um conflito” que mostra os passos até que um conflito se forme. Vale salientar que normalmente, durante o ciclo de desenvolvimento de projetos, as alterações são maiores a por vezes em maior quantidade.
0 - No nosso projeto temos um README.md
que foi adicionado pelo commit inicial no repositório. Depois da criação desse arquivo, duas alterações precisam ser feitas para adicionar mais algumas informações ao mesmo arquivo e duas pessoas vão fazer essa alteração;
1 - Cada pessoa então criou um branch a partir da main
para trabalhar nas suas alterações, esses novos branches foram criados mais ou menos ao mesmo tempo, ou seja, eles possuem um mesmo ponto de partida;
2 - Durante algum tempo cada pessoa trabalha na sua branch implementando a sua alteração, que nesse caso é adicionar a linha “pessoa x esteve aqui!” no arquivo de README.md
sendo x o identificador da pessoa;
3 - A pessoa 1 faz um pull request e tem esse pull request aprovado e seu merge na main
;
4 - A pessoa 2 por sua vez, faz o seu pull request para main
, só que esse pull request não pode ser feito merge pois apresenta conflitos.
Formando um conflito na prática
Para demonstrar como isso se apresenta, eu criei um repositório com um cenário parecido ao descrito na seção anterior que você pode encontrar aqui. O arquivo inicial foi criado e as duas branches, uma para cada pessoa, também já foram criadas a partir da main
, veja:
Em seguida fiz as alterações para cada pessoa, no branch pessoa1
adicionei a descrição “Pessoa 1 esteve aqui!” na última linha do README.md
e de forma similar fiz o mesmo processo para o branch pessoa2
. Então, abri os dois pull requests:
Revisei e dei o merge no pull request da pessoa1
:
E então voltei para o PR da pessoa2
e pude notar a indicação de que o pull request continha um conflito, veja:
E agora com o conflito quentinho em mãos é hora de resolvê-lo.
Resolvendo um conflito no Git
Antes de começar é importante notar que este tipo de conflito é possível resolver também pela interface do GitHub, mas o foco aqui são os comandos, então vamos lá!
A primeira coisa importante é decidir em qual branch resolver o conflito, uma regra que geralmente funciona é resolver os conflitos no branch que apresenta as alterações, neste caso, o branch em questão é o pessoa2
, com isso você deve atualizar o seu repositório local, e este branch em particular com os ajustes da main, para isso faça:
git checkout pessoa2
git pull origin main
Isso irá trazer o conflito para a sua máquina te dando um aviso informando que existem conflitos, que você deve resolver o conflito e fazer um commit com o resultado:
Se você abrir o README.md
num editor de código irá notar a presença de marcadores indicado por sucessivos sinais de maior que (>
), sinais de menor que (>
) e sinais de igual (=
), aqui um exemplo do conflito mostrado no Vim:
Também é possível que você use o VS Code que mostra o conflito de uma forma mais amigável já que ele marca visualmente, com cores diferentes, cada mudança de origem diferente e ainda te d’a’ opções de como resolver o conflito aceitando parte das mudanças, ou as duas, ou nenhuma delas:
Para entender o que cada botão apresentado pelo VS Code quer dizer, vamos dissecar um pouco esse formato de representação. Um conflito pode ser dividido em duas partes:
- As nossas alterações: aquelas que estão no branch corrente também chamadas de alterações atuais (current change);
- As alterações dos outros: aquelas que trouxemos para a máquina local ao fazer
git pull
também chamadas de alterações que estão chegando ou de entrada (incoming changes).
Nesse formato, cada bloco é delimitado por um sinal de maior ou menor até o bloco de sinais de igual repetidos, então por exemplo nesse caso temos os seguintes blocos.
Aquele com as alterações atuais:
<<<<<<< HEAD
Pessoa 2 esteve aqui!
=======
E aquele com as alterações que estão chegando:
=======
Pessoa 1 esteve aqui!
>>>>>>> 3c20251a794ec572e2c3202017d843e2d8769843
Como queremos deixar ambas alterações, podemos apenas apagar as linhas com os marcadores salvar o arquivo, se você estiver usando editores mais simples. No VS Code podemos apertar em “Accept both changes” e continuar com os comandos a seguir. Após aceitar todas as mudanças, manualmente ou usando os botões no VS Code, você deve ter um arquivo assim:
Lembre-se de salvar o arquivo. Em seguida volte para o terminal, se você rodar o comando git status
vai ver que o arquivo README.md
se mostra com alterações.
Agora você pode adicionar esse arquivo em staging com o seguinte comando:
git add README.md
E fazer o commit das alterações da forma que preferir. Note que ao fazer o commit, se você usar editores para escrever a mensagem de commit, é possível que essa mensagem já venha pré-preenchida como na imagem abaixo:
Você pode personalizar a mensagem ou deixá-la como está e, ao terminar de fazer o commit, enviar essas alterações para o GitHub com um git push
:
Agora se você recarregar a página do pull request deverá ver que o conflito foi resolvido, observe:
E podemos finalmente dar merge neste pull request! Vitória! 🎉🎉
Conclusão
Você agora entende como os conflitos se formam e também sabe todos os passos envolvidos em resolver conflitos.
Aqui está a lista simples de todos os comandos e passos para resolver conflitos, lembre de substituir as notações <>
de acordo:
git checkout <nome do branch com conflito>
git pull origin main
- abra o arquivo com conflito e os resolva
- salve o arquivo
git add <nome do arquivo alterado>
git commit
git push
Espero que esse artigo te ajude a resolver os conflitos de git que você encontrar daqui pra frente. 😉
Leitura extra
Seguem mais umas dicas de documentações em português para você aprender sobre resolução de conflitos no git