28. Rebase

Metas

  • Usar o comando rebase ao invés do merge.

Revertemos o branch style para o ponto no histórico antes da primeira mesclagem. Há dois commits que estão no ramo main, mas não no ramo style: o novo arquivo README e a alteração conflitante no arquivo index.html. Desta vez, moveremos essas alterações para o ramo style usando o comando rebase em vez do merge.

01 Rebase do ramo style para o main

Execute

git switch style
git rebase main
git status

Resultado

$ git switch style
Already on 'style'
$ git rebase main
Rebasing (1/3)
Rebasing (2/3)
Auto-merging hello.html
CONFLICT (content): Merge conflict in hello.html
error: could not apply 903eb1d... Included stylesheet into hello.html
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 903eb1d... Included stylesheet into hello.html
$ git status
interactive rebase in progress; onto 85c14e9
Last commands done (2 commands done):
   pick 555372e Added css stylesheet
   pick 903eb1d Included stylesheet into hello.html
Next command to do (1 remaining command):
   pick 0ee0113 Renamed hello.html; moved style.css
  (use "git rebase --edit-todo" to view and edit)
You are currently rebasing branch 'style' on '85c14e9'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   hello.html

no changes added to commit (use "git add" and/or "git commit -a")

Há um conflito novamente! Observe que o conflito está em hello.html e não em index.html como da última vez. Isso ocorre porque o rebase estava no processo de aplicar as alterações de style sobre a ramificação main. O arquivo hello.html ainda não foi renomeado no main, portanto, ainda tem o nome antigo.

Ao fazer a mesclagem, teríamos um conflito "reverso". Durante a mesclagem, as alterações da ramificação main seriam aplicadas sobre a ramificação style. A ramificação style tem o arquivo renomeado, portanto, o conflito estaria em index.html.

Arquivo: hello.html

<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
  <head>
<<<<<<< HEAD
    <title>Hello World Page</title>
=======
    <link type="text/css" rel="stylesheet" media="all" href="style.css" />
>>>>>>> 903eb1d (Included stylesheet into hello.html)
  </head>
  <body>
    <h1>Hello, World!</h1>
    <p>Let's learn Git together.</p>
  </body>
</html>

02 Resolver o conflito

O conflito em si pode ser resolvido da mesma forma que fizemos anteriormente. Primeiro, editamos o arquivo hello.html para atender às nossas expectativas.

Arquivo: hello.html

<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
  <head>
    <title>Hello World Page</title>
    <link type="text/css" rel="stylesheet" media="all" href="style.css" />
  </head>
  <body>
    <h1>Hello, World!</h1>
    <p>Let's learn Git together.</p>
  </body>
</html>

Mas depois disso, não precisamos confirmar as alterações. Podemos simplesmente adicionar o arquivo ao índice e continuar o processo de rebase. É por isso que adoro o rebase! Ele me permite corrigir conflitos sem criar um monte de conflitos de mesclagem feios.

Por uma questão de simplicidade, podemos adicionar todos os arquivos usando ., que representa o caminho do diretório atual. O Git interpreta isso como "adicionar todos os arquivos no diretório atual e seus subdiretórios".

Execute

git add .
git rebase --continue

Aqui, muito provavelmente, o Git abrirá o editor novamente, para que possamos alterar a mensagem do commit. Podemos deixar a mensagem como está. Ao salvar as alterações, o Git concluirá o processo de rebase e poderemos prosseguir com os comandos a seguir:

Execute

git status
git log --all --graph

Resultado

$ git add .
$ git rebase --continue
[detached HEAD 23149b5] Included stylesheet into hello.html
 1 file changed, 1 insertion(+)
Rebasing (3/3)

Successfully rebased and updated refs/heads/style.
$ git status
On branch style
nothing to commit, working tree clean
$ git log --all --graph
* 39a1e0f 2023-11-28 | Renamed hello.html; moved style.css (HEAD -> style) [Alexander Shvets]
* 23149b5 2023-11-28 | Included stylesheet into hello.html [Alexander Shvets]
* b9e6de1 2023-11-28 | Added css stylesheet [Alexander Shvets]
* 85c14e9 2023-11-28 | Added meta title (main) [Alexander Shvets]
* ee16740 2023-11-28 | Added README [Alexander Shvets]
* 9288a33 2023-11-28 | Added copyright statement with email [Alexander Shvets]
* b7614c1 2023-11-28 | Added HTML header (tag: v1) [Alexander Shvets]
* 46afaff 2023-11-28 | Added standard HTML page tags (tag: v1-beta) [Alexander Shvets]
* 78433de 2023-11-28 | Added h1 tag [Alexander Shvets]
* 5836970 2023-11-28 | Initial commit [Alexander Shvets]

03 Merge VS Rebase

O resultado do comando rebase parece muito com o do merge. O branch style atualmente contém todas as suas mudanças, além das mudanças do branch main. A árvore de commits, porém, está um pouco diferente. A árvore de commit do branch style foi reescrita para fazer o branch main parte do histórico de commits. Isso faz com que a cadeia de commits seja mais linear e legível.

04 Quando usar o comando rebase e quando usar o comando merge?

Use o comando rebase:

  • Quando você obtém alterações de um repositório remoto e deseja aplicá-las ao seu branch local.
  • Se você quiser manter o histórico de commits linear e fácil de ler.

Não use o comando rebase:

  • Se o branch atual for público e compartilhado. A reescrita dessas ramificações atrapalhará o trabalho de outros membros da equipe.
  • Quando o histórico exato do branch de commit for importante (porque o comando rebase reescreve o histórico de commits).

Considerando as recomendações acima, prefiro usar o rebase para branches locais de curto prazo e o comando merge para branches no repositório público.