Como entender e resolver conflitos no Git

Aí está, a palavra que todo desenvolvedor odeia ver: conflito. ? Simplesmente não há como contornar o conflito ocasional de mesclagem ao trabalhar com Git (ou outros sistemas de controle de versão).

Mas, ao falar com desenvolvedores, muitas vezes ouço que há uma sensação de ansiedade ou desconforto em torno do tópico de conflitos de mesclagem.

Lidar com conflitos geralmente continua sendo um lugar escuro e misterioso: uma situação em que as coisas estão muito quebradas e não está claro como sair dela (sem piorar as coisas).

Embora seja verdade que os conflitos de mesclagem são uma parte inevitável da vida do desenvolvedor, o desconforto nessas situações é totalmente opcional.

Minha intenção com este artigo é esclarecer este tópico: como e quando os conflitos normalmente ocorrem, o que eles realmente são e como resolvê-los - ou desfazê-los.

Quando você entender essas coisas corretamente, será capaz de lidar com os conflitos de mesclagem de uma maneira muito mais relaxada e confiante. ?

Como e quando os conflitos ocorrem

O nome já diz: "conflitos de mesclagem" podem ocorrer no processo de integração de commits de uma fonte diferente.

Lembre-se, porém, de que a "integração" não se limita apenas a "mesclar ramos". Também pode acontecer ao rebasing ou rebasing interativo, ao realizar uma escolha seletiva ou um pull, ou mesmo ao reaplicar um Stash.

Todas essas ações realizam algum tipo de integração - e é aí que os conflitos de mesclagem podem acontecer.

Mas é claro, essas ações não resultam em um conflito de fusão sempre (graças a Deus!). Idealmente, você deve se encontrar nessas situações apenas raramente. Mas quando exatamente os conflitos ocorrem?

Na verdade, os recursos de fusão do Git são uma de suas maiores vantagens: a fusão de branches funciona sem esforço na maioria das vezes, porque o Git geralmente é capaz de descobrir as coisas por conta própria.

Mas há situações em que mudanças contraditórias foram feitas - e onde a tecnologia simplesmente não consegue decidir o que é certo ou errado. Essas situações simplesmente exigem uma decisão de um ser humano.

O verdadeiro clássico é quando a mesma linha de código exata foi alterada em dois commits, em dois branches diferentes. O Git não tem como saber qual mudança você prefere! ?

Existem algumas outras situações semelhantes - por exemplo, quando um arquivo foi modificado em uma ramificação e excluído em outra - mas são um pouco menos comuns.

A GUI do desktop Git "Torre" , por exemplo, tem uma ótima maneira de visualizar esses tipos de situações:

Como saber quando ocorreu um conflito

Não se preocupe: o Git dirá a você claramente quando um conflito ocorrer. ?  

Primeiro, ele o deixará saber imediatamente na situação , por exemplo, quando uma fusão ou rebase falha devido a um conflito:

$ git merge develop Auto-merging index.html CONFLICT (content): Merge conflict in index.html CONFLICT (modify/delete): error.html deleted in HEAD and modified in develop. Version develop of error.html left in tree. Automatic merge failed; fix conflicts and then commit the result.

Como você pode ver no exemplo acima, quando tentei realizar uma mesclagem, criei um conflito de mesclagem - e o Git comunica o problema de forma muito clara e rápida:

  • Ocorreu um conflito no arquivo "index.html".
  • Outro conflito no arquivo "error.html" ocorreu.
  • E, finalmente, por causa dos conflitos, a operação de mesclagem falhou.

Essas são as situações em que temos que nos aprofundar no código e ver o que precisa ser feito.

No caso improvável de você ter esquecido essas mensagens de aviso quando o conflito aconteceu, o Git também informa sempre que você executar git status:

$ git status On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add/rm ..." as appropriate to mark resolution) deleted by us: error.html both modified: index.html

Em outras palavras: não se preocupe em não perceber conflitos de mesclagem. Git garante que você não pode ignorá-los.

Como Desfazer um Conflito no Git e Começar de Novo

Conflitos de mesclagem vêm com um certo ar de urgência. E com razão: você terá que lidar com eles antes de continuar com seu trabalho.

Mas embora ignorá-los não seja uma opção, "lidar com conflitos de mesclagem" não significa necessariamente que você tenha que resolvê-los. Desfazê- los também é possível!

Vale a pena repetir: você sempre tem a opção de desfazer um conflito de mesclagem e retornar ao estado anterior. Isso é verdade mesmo quando você já começou a resolver os arquivos em conflito e se encontra em um beco sem saída.

Nessas situações, é ótimo ter em mente que você sempre pode recomeçar e retornar a um estado de limpeza antes mesmo de o conflito acontecer.

Para isso, a maioria dos comandos vem com uma --abortopção, por exemplo git merge --aborte git rebase --abort:

$ git merge --abort $ git status On branch main nothing to commit, working tree clean

Isso deve lhe dar a confiança de que você realmente não pode errar. Você sempre pode abortar, retornar a um estado limpo e reiniciar.

Como os conflitos realmente se parecem no Git

Agora, com a certeza de que nada pode quebrar, vamos ver como é realmente um conflito sob o capô. Isso desmistificará esses pequenos insetos e, ao mesmo tempo, ajudará você a perder o respeito por eles e a ganhar confiança em si mesmo.

Como exemplo, vamos examinar o conteúdo do arquivo (atualmente em conflito) "index.html" em um editor:

Git was kind enough to mark the problem area in the file, enclosing it in <<<<<<< HEAD and >>>>>>> [other/branch/name]. The content that comes after the first marker originates from our current working branch. Finally, a line with ======= characters separates the two conflicting changes.

How to Solve a Conflict in Git

Our job as developers now is to clean up these lines: after we're finished, the file has to look exactly as we want it to look.

It might be necessary to talk to the teammate who wrote the "other" changes and decide which code is actually correct. Maybe it's ours, maybe it's theirs - or maybe a mixture between the two.

This process - cleaning up the file and making sure it contains what we actually want - doesn't have to involve any magic. You can do this simply by opening your text editor or IDE and starting to making your changes.

Often, however, you'll find that this is not the most efficient way. That's when dedicated tools can save time and effort:

  • Git GUI Tools: Some of the graphical user interfaces for Git can be helpful when solving conflicts. The Tower Git GUI, for example, offers a dedicated "Conflict Wizard" that helps visualize and solve the situation:
  • Dedicated Merge Tools: For more complicated conflicts, it can be great to have a dedicated "Diff & Merge Tool" at hand. You can configure your tool of choice using the "git config" command. (Consult your tool's documentation for detailed instructions.) Then, in case of a conflict, you can invoke it by simply typing git mergetool. As an example, here's a screenshot of "Kaleidoscope" on macOS:

After cleaning up the file - either manually or in a Git GUI or Merge Tool - we have to commit this like any other change:

  • By using git add on the (previously) conflicted file, we inform Git that the conflict has been solved.
  • When all conflicts have been solved and added to the Staging Area, you need to complete the resolution by creating a regular commit.

How to Become More Confident and Productive

Many years ago, when I started using version control, merge conflicts regularly freaked me out: I was afraid that, finally, I had managed to break things for good. ?

Only when I took the time to truly understand what was going on under the hood was I able to deal with conflicts confidently and efficiently.

The same was true, for example, when dealing with mistakes: only once I learned how to undo mistakes with Git was I able to become more confident and productive in my work.

I highly recommend taking a look at the free "First Aid Kit for Git", a collection of short videos about how to undo and recover from mistakes with Git.

Have fun becoming a better programmer!

About the Author

Tobias Günther é o CEO da Tower, o popular cliente de desktop Git que ajuda mais de 100.000 desenvolvedores em todo o mundo a serem mais produtivos com o Git.