Artigo original: The Ultimate Guide to Git Merge and Git Rebase
Traduzido e adaptado por Daniel Rosa

Boas-vindas ao nosso guia definitivo para os comandos git merge e git rebase. Este tutorial ensinará a você tudo o que você precisa saber sobre combinar várias branches usando o Git.

Git Merge

O comando git merge fará a junção das alterações feitas à base de código em uma branch separada à sua branch atual como um novo commit.

A sintaxe do comando é a seguinte:

git merge NOME-DA-BRANCH

Por exemplo, se você está trabalhando atualmente em uma branch chamada dev e gostaria de fazer o merge de alterações feitas em uma branch chamada new-features, o comando teria esta sintaxe:

git merge new-features

Observação: se houver alterações cujo commit não foi realizado em sua branch atual, o Git não permitirá fazer o merge até que todas as alterações de sua branch atual sejam passadas por commit. Para lidar com essas alterações, você pode:

Criar uma nova branch e fazer o commit das alterações

git checkout -b novo-nome-da-branch
git add .
git commit -m "<sua mensagem de commit>"

Faça o stash das alterações

git stash               # adiciona as mudanças ao stash
git merge new-features  # faz o merge
git stash pop           # obtém as alterações de sua árvore de trabalho

Abandonar todas as alterações

git reset --hard        # remove todas as alterações pendentes

Git Rebase

Fazer o rebase de uma branch no Git é uma maneira de mover toda uma branch para outro ponto da árvore. O exemplo mais simples é mover uma branch mais para cima na árvore. Digamos que temos uma branch que esteja divergente da branch master/main no ponto A:

        /o-----o---o--o-----o--------- branch
--o-o--A--o---o---o---o----o--o-o-o--- master/main

Ao fazer o rebase, podemos movê-la assim:

                                   /o-----o---o--o-----o------ branch
--o-o--A--o---o---o---o----o--o-o-o master/main

Para fazer o rebase, certifique-se de ter todos os commits que deseja usar no rebase em sua branch master/main. Confira a branch da qual você quer fazer o rebase e digite git rebase master/main (onde master/main é a branch na qual você quer fazer o rebase).

Também é possível fazer um rebase em uma branch diferente. Então, por exemplo, uma branch que foi baseada em outra branch (vamos chamá-la de feature) passa pelo rebase na branch master/main:

                            /---o-o branch
           /---o-o-o-o---o--o------ feature
----o--o-o-A----o---o--o-o-o--o--o- master/main

Após git rebase master/main branch ou git rebase master/main, quando você conferir a branch, terá o seguinte:

           /---o-o-o-o---o--o------ feature
----o--o-o-A----o---o--o-o-o--o--o- master/main
                                  \---o-o branch

Git rebase interativo no console

Para usar git rebase no console com uma lista de commits que você pode selecionar, editar ou excluir do rebase:

  • Digite git rebase -i HEAD~5, com o último número sendo o número de commits anteriores mais recentes que você quer revisar.
  • No vim, pressione esc, e i para começar a editar o teste.
  • No lado esquerdo, você pode sobrescrever o pick com um dos comandos abaixo. Se quiser fazer o squash de um commit em outro commit anterior e descarte a mensagem de commit, digite f no lugar do pick do commit.
  • Salve e saia de seu editor de texto.
  • Quando o rebase for interrompido, faça os ajustes necessários, depois use git rebase --continue até que o rebase tenha êxito.
  • Se o rebase tiver sucesso, você precisará fazer o force push de suas alterações com git push -f para adicionar a versão colocada em rebase em seu repositório remoto.
  • Se houver um conflito de merge, há várias maneiras de se consertar isso, incluindo seguir as sugestões deste guia (em inglês). Uma maneira é abrir os arquivos em um editor de texto e excluir as partes do código que você não quer. Depois, use git add <nome do arquivo> seguido por git rebase --continue. Você pode saltar o commit com o conflito inserindo git rebase --skip e parar o rebase executando git rebase --abort em seu console.
pick 452b159 <mensagem deste commit>
pick 7fd4192 <mensagem deste commit>
pick c1af3e5 <mensagem deste commit>
pick 5f5e8d3 <mensagem deste commit>
pick 5186a9f <mensagem deste commit>

# Rebase 0617e63..5186a9f em 0617e63 (30 comandos)
#
# Comandos:
# p, pick = usa o commit
# r, reword = usa o commit, mas interrompe para editar a mensagem do commit.
# e, edit = usa o commit, mas interrompe para consertar ou adicionar o commit.
# s, squash = usa o commit, une no commit anterior e interrompe para editar a mensagem de commit.
# f, fixup = como em "squash", mas descarta a mensagem de log desse commit e, portanto, não interrompe.
# x, exec = executa o comando (o resto da linha) usando shell
# d, drop = remove o commit
#
# Essas linhas podem ser reordenadas; eles são executados de cima para baixo. 
#
# Se você remover uma linha aqui ESSE COMMIT SERÁ PERDIDO.
#
# Porém, se remover tudo, o rebase será cancelado.
#
# Observe que os commits vazios estão comentados para não aparecerem

Conflitos de merge

Um conflito de merge ocorre quando fazemos commits em branches separados que alteram a mesma linha de modos que causam conflito. Se isso acontecer, o Git não saberá qual versão do arquivo deve ser mantida e enviará uma mensagem de erro semelhante a esta:

CONFLICT (content): Merge conflict in resumé.txt Automatic merge failed; fix conflicts and then commit the result.

Se examinar o arquivo resumé.txt em seu editor de código, poderá ver onde o conflito aconteceu:

<<<<<<< HEAD
Address: 808 South Street
=======
Address: 505 North Street
>>>>>>> updated_address

O Git adicionou algumas linhas a mais ao arquivo:

  • <<<<<<< HEAD
  • =======
  • >>>>>>> updated_address

Pense nos  ======= como a linha divisória do conflito. Tudo o que está entre <<<<<<< HEAD e ======= é o conteúdo da branch atual para o qual a referência HEAD está apontando. Por outro lado, tudo entre  ======= e >>>>>>> updated_address é o conteúdo na branch de que se está fazendo o merge, ou seja, updated_address (o endereço atualizado).

Git merge x Git rebase

git merge e git rebase são comandos muito úteis. Um não é "melhor" que o outro. Porém, há algumas diferenças bastante importantes entre os dois comandos que você e sua equipe devem levar em consideração.

Sempre que git merge é executado, um commit de merge a mais é criado. Sempre que estiver trabalhando em seu repositório local, fazer muitos commits de merge pode tornar confuso o histórico de commits. Uma maneira de se evitar o commit de merges é usar git rebase e, seu lugar.

git rebase é um recurso muito poderoso. Dito isso, saiba que ele também é arriscado se não for usado da maneira correta. git rebase altera o histórico de commits. Por isso, use-o com cuidado. Se o rebase for feito no repositório remoto, ele pode criar diversos problemas quando outros desenvolvedores tentarem fazer o pull das alterações mais recentes do código do repositório remoto. Lembre-se de executar o git rebase somente em um repositório local.

Isso era o que você precisava saber sobre os comandos merge e rebase, com a melhor forma de se utilizar a ambos.