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:
Material relacionado
Log avançado do Git
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
Próximo tópico
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.