[Git] Entendendo as Estratégias de Merge Fast-Forward e Three-Way

Neste post irei tentar explicar de forma simples com alguns exemplos e figuras como funcionam as duas estratégias que o Git utiliza ao realizar um merge entre dois branches.

Como exemplo, imagine que em um repositório aconteceram três commits anteriormente e um bug foi descoberto depois do último commit.

Para corrigir esse bug, um branch chamado bugfix foi criado e, feita a correção, um commit com o código estável foi realizado nesse mesmo branch.

Deixemos o repositório nesse estado e vamos assumir o controle. Precisamos fazer com que o branch master seja atualizado para o commit mais recente realizado no branch bugfix. Para isso, iremos fazer checkout no master, executar o comando merge e observar a estratégia utilizada pelo Git.

$ git checkout master
$ git merge bugfix
Updating bc29da..fd61a7
Fast-forward

Nesse caso, o único trabalho do Git foi aplicar as alterações feitas no commit do bugfix e atualizar o branch master para o último commit, por isso o nome fast-forward. É importante notar que, nessa estratégia, nunca acontecerão conflitos de merge, por que os commits mais recentes no outro branch são totalmente baseados no commit para o qual o master aponta, ou seja, o branch é descendente do master.

Portanto, a única situação onde podem acontecer conflitos de merge é na junção de dois branches que apontam para commits divergentes na história de versionamento. Como exemplo, imagine que enquanto o bug estava sendo corrigido no branch bugfix, um commit foi realizado no master. Quando o commit do bugfix for executado, os dois branches divergirão na história do repositório:

Vamos fazer checkout no branch master e realizar um merge com o bugfix e ver o que acontece.

$ git checkout master
$ git merge bugfix
Mesclagem automática...
Merge made by the 'recursive' strategy.

Na estratégia recursiva(tecnicamente conhecida como three-way), o Git compara os dois branches mais o commit que é ancestral comum dos dois(nesse caso, bc29da) e, se não houver nenhum conflito(como alterações na mesma linha), aplica as mudanças introduzidas pelos dois branches em um novo commit.

Para ficar mais claro, imagine que os dois branches em questão(master e bugfix) alteraram o seguinte arquivo:

script com bug
bug corrigido no branch bugfix
mensagem alterada no branch master

O resultado do merge dos dois branches será o seguinte:

Por motivos de simplicidade, supomos que não houve nenhum conflito na execução do merge em nenhum exemplo. Caso houvesse algum, a única diferença nesse tutorial seria que o commit da junção dos dois branches não seria realizado automaticamente, ou seja, depois de executar o merge, teríamos que resolver os conflitos primeiro e depois executar o commit.