Close

Conflitos Git merge

Os sistemas de controle de versão servem para gerenciar contribuições de vários autores (que são, com frequência, desenvolvedores). Às vezes, diversos desenvolvedores querem editar o mesmo conteúdo. Se o Desenvolvedor A tenta editar códigos ao mesmo tempo que o Desenvolvedor B, podem ocorrer conflitos. Para reduzir esses conflitos, os desenvolvedores vão trabalhar em ramificações isoladas. A principal responsabilidade do comando git merge é combinar ramificações separadas e resolver conflitos de edição.


Entendendo conflitos de merge


É comum que surjam conflitos quando duas pessoas alteram as mesmas linhas no mesmo arquivo. Ou então quando algum desenvolvedor exclui arquivos enquanto outra pessoa faz alterações. Nesses casos, o Git não pode determinar qual está correto. Os conflitos afetam apenas o desenvolvedor que conduz o merge e o resto da equipe não fica ciente deles. O Git marca os arquivos em conflito e interrompe o processo de merge. A partir daí, é responsabilidade dos desenvolvedores resolver o conflito.

Tipos de conflitos de merge


O merge pode entrar em estado de conflito em dois momentos diferentes. No começo ou durante o processo de merge. A seguir, a gente discute como enfrentar esses cenários de conflito.

O Git não consegue iniciar o merge

A inicialização do merge pode falhar se o Git vir que há mudanças no diretório de trabalho ou na área de staging do projeto atual. O Git não pode iniciar o merge, pois essas mudanças pendentes podem ser gravadas pelos commits que estão passando pelo processo de merge. Quando esse tipo de erro acontece, é por causa de conflitos com mudanças locais pendentes, não conflitos com outros desenvolvedores. O estado local vai precisar ser estabilizado por meio de git stash, git checkout, git commit ou git reset. A falha da inicialização do merge vai fazer com que a mensagem de erro a seguir seja exibida:

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)

O Git falha durante o merge

Falhas DURANTE merges indicam conflitos entre a ramificação local atual e a ramificação passando pelo processo de merge. Isso indica conflitos com o código de outro desenvolvedor. O Git vai tentar fazer merge dos arquivos, mas vai deixar você encontrar a solução manual para os arquivos com conflitos. Falhas no meio do merge fazem com que a mensagem de erro a seguir seja exibida:

Janela do console
Material relacionado

Log avançado do Git

Logotipo do Bitbucket
VER SOLUÇÃO

Aprenda a usar o Git com o Bitbucket Cloud

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

Como criar o conflito de merge


Para entender melhor os conflitos de merge, a próxima seção vai simular um conflito para você examinar e resolver mais tarde. O exemplo vai usar a interface Git de linha de comando parecida com o Unix para executar a simulação de exemplo.

$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[main (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt

Esse exemplo de código executa a sequência de comandos que faz as ações descritas a seguir.

  • Cria o diretório chamado git-merge-test, muda para esse diretório e faz a inicialização como o novo repositório Git.
  • Cria um novo arquivo de texto merge.txt com algum conteúdo nele.
  • Adiciona merge.txt ao repositório e faz o commit.

Agora, você tem o novo repositório com a ramificação main e o arquivo merge.txt com conteúdo dentro. A seguir, vamos criar a ramificação para usar como o merge do conflito.

$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

O processo da sequência de comando realiza as seguintes ações:

  • cria e faz check-out da ramificação chamada new_branch_to_merge_later
  • substitui o conteúdo em merge.txt
  • faz o commit do novo conteúdo

Com essa nova ramificação: new_branch_to_merge_later, a gente criou o commit que substitui o conteúdo do merge.txt

git checkout main
Switched to branch 'main'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[main 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)

Essa cadeia de comandos faz check-out da ramificação main, anexa conteúdo ao merge.txt e faz o commit. Assim o repositório de exemplo tem dois novos commits, um na ramificação main e outro na ramificação new_branch_to_merge_later. Agora, faça o git merge de new_branch_to_merge_later e veja o que acontece!

$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

BUM 💥. O conflito apareceu. Valeu por avisar a gente, Git!

Como identificar conflitos de merge


Como você viu no exemplo de procedimento, o Git produz saídas descritivas e avisa quando CONFLITOS ocorrem. É possível ter mais informações executando o comando 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 <file>..." to mark resolution)

both modified:   merge.txt

A saída do git status indica que há caminhos que não passaram pelo merge por causa de conflitos. O arquivo merge.txt agora aparece com estado modificado. Examine o arquivo e veja as modificações.

$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later

Aqui, a gente usou o comando cat para extrair o conteúdo do arquivo merge.txt..yaml. Podemos ver algumas novas adições estranhas

  • <<<<<<< HEAD
  • =======
  • >>>>>>> new_branch_to_merge_later

Pense nessas novas linhas como "divisores de conflitos". A linha ======= é o "centro" do conflito. Todo o conteúdo entre o centro e a linha <<<<<<< HEAD é o conteúdo que existe na ramificação principal atual, ao qual o ref. HEAD está apontando. Como alternativa, todo o conteúdo entre o centro e >>>>>>> new_branch_to_merge_later é o conteúdo presente na ramificação de merge.

Como resolver conflitos de merge usando a linha de comando


O modo mais direto de resolver conflitos de merge é editar o arquivo com conflitos. Abra o arquivo merge.txt no editor que você preferir. Como exemplo, a gente vai apenas remover todos os divisores com conflito. O conteúdo do arquivo merge.txt modificado deve se parecer com o seguinte:

this is some content to mess with
content to append
totally different content to merge later

Quando o arquivo tiver sido editado, use git add merge.txt para fazer stage do novo conteúdo que passou pelo merge. Para finalizar o merge, crie o commit executando:

git commit -m "merged and resolved the conflict in merge.txt"

O Git percebe que o conflito foi resolvido e cria o commit de merge para finalizar o processo.

Os comandos Git que podem ajudar a resolver conflitos de merge


Ferramentas gerais

git status

O comando de status é usado com frequência ao trabalhar com Git. Durante o merge, ele pode ajudar a identificar arquivos com conflito.

git log --merge

Passar o argumento --merge para o comando do git log vai produzir o log com a lista de commits com conflitos entre as ramificações.

git diff

O diff ajuda a encontrar diferenças entre os estados de repositórios/arquivos. Ele é útil para prever e prevenir conflitos de merge.

Ferramentas para quando o git não consegue iniciar o merge

git checkout

O checkout pode ser usado para desfazer mudanças em arquivos ou para alterar ramificações

git reset --mixed

O reset pode ser usado para desfazer mudanças no diretório de trabalho e na área de staging.

Ferramentas para quando surgem conflitos git durante o merge

git merge --abort

Executar o git merge com a opção --abort encerra o processo de merge e faz a ramificação voltar ao estado anterior ao merge.

git reset

O Git reset pode ser usado durante conflitos de merge para redefinir arquivos com conflitos para estados válidos

Resumo


Enfrentar conflitos de merge pode ser intimidador. Ainda bem que o Git oferece ferramentas poderosas para ajudar a navegar e a resolver conflitos. O Git pode lidar sozinho com a maioria dos merges com funções automáticas. Conflitos aparecem quando duas ramificações diferentes editam a mesma linha do mesmo arquivo ou quando arquivos são excluídos na ramificação, mas editados em outra. É comum que conflitos aconteçam ao trabalhar em ambientes de equipe.

Há muitas ferramentas que ajudam a resolver conflitos de merge. O Git tem várias ferramentas de linha de comando que a gente mencionou. Para saber mais informações sobre essas ferramentas, consulte as páginas independentes sobre git log, git reset, git status, git checkout e git reset. Além do Git, muitas ferramentas de terceiros oferecem funções de suporte simplificados para conflitos de merge.


Compartilhar este artigo

Leitura recomendada

Marque esses recursos para aprender sobre os tipos de equipes de DevOps ou para obter atualizações contínuas sobre DevOps na Atlassian.

Pessoas colaborando usando uma parede cheia de ferramentas

Blog do Bitbucket

Ilustração do DevOps

Caminho de aprendizagem de DevOps

Demonstrações de funções no Demo Den com parceiros da Atlassian

Como o Bitbucket Cloud funciona com o Atlassian Open DevOps

Inscreva-se para receber a newsletter de DevOps

Thank you for signing up