DevOps & CI/CD

Guia Completo de Git Avançado: Rebase, Cherry-pick, Bisect e Recuperação de Histórico

16 min de leitura

Guia Completo de Git Avançado: Rebase, Cherry-pick, Bisect e Recuperação de Histórico

Git Avançado: Rebase, Cherry-pick, Bisect e Recuperação de Histórico Introdução ao Workflow Avançado Quando você trabalha em equipes grandes ou em projetos complexos, git básico (commit, push, pull) não é suficiente. Você precisa dominar ferramentas que permitem reescrever histórico, selecionar commits específicos, encontrar bugs e recuperar trabalho perdido. Este artigo é para quem já sabe usar git diariamente e quer evoluir para um nível profissional, dominando as operações que separam desenvolvedores que apenas usam git daqueles que realmente o dominam. O conhecimento dessas técnicas não é opcional em empresas que levam qualidade a sério. Elas resolvem problemas reais: um commit foi feito na branch errada? Use cherry-pick. O histórico está bagunçado? Use rebase. Qual commit introduziu o bug? Use bisect. Deletou a branch por acidente? Recupere com reflog. Vamos começar. --- Rebase: Reorganizando e Limpando Histórico O que é Rebase e Por que Importa Rebase é o conceito mais mal compreendido de git. Não é merge. Enquanto merge cria um

<h2>Git Avançado: Rebase, Cherry-pick, Bisect e Recuperação de Histórico</h2>

<h3>Introdução ao Workflow Avançado</h3>

<p>Quando você trabalha em equipes grandes ou em projetos complexos, git básico (commit, push, pull) não é suficiente. Você precisa dominar ferramentas que permitem reescrever histórico, selecionar commits específicos, encontrar bugs e recuperar trabalho perdido. Este artigo é para quem já sabe usar git diariamente e quer evoluir para um nível profissional, dominando as operações que separam desenvolvedores que apenas usam git daqueles que realmente o dominam.</p>

<p>O conhecimento dessas técnicas não é opcional em empresas que levam qualidade a sério. Elas resolvem problemas reais: um commit foi feito na branch errada? Use cherry-pick. O histórico está bagunçado? Use rebase. Qual commit introduziu o bug? Use bisect. Deletou a branch por acidente? Recupere com reflog. Vamos começar.</p>

<p>---</p>

<h2>Rebase: Reorganizando e Limpando Histórico</h2>

<h3>O que é Rebase e Por que Importa</h3>

<p>Rebase é o conceito mais mal compreendido de git. Não é merge. Enquanto merge cria um commit de fusão que preserva ambas as histórias, rebase <strong>reaplica seus commits em cima de outra branch</strong>, criando um histórico linear e limpo. Pense em rebase como &quot;mover sua base de trabalho para um novo ponto&quot;.</p>

<p>A primeira razão para usar rebase é estética: um histórico linear é mais fácil de ler e debugar. A segunda é prática: quando você trabalha em uma feature branch por dias enquanto main recebe outros commits, rebase garante que sua feature está construída em cima da versão mais recente do código. Isso é especialmente importante antes de fazer merge.</p>

<h3>Rebase Interativo: O Poder está aqui</h3>

<pre><code class="language-bash"># Você está na branch &#039;feature&#039; com 5 commits

Quer reorganizar, combinar ou editar 3 últimos commits

git rebase -i HEAD~3</code></pre>

<p>O comando acima abre um editor com algo assim:</p>

<pre><code>pick a1b2c3d Adiciona validação de email

pick d4e5f6g Corrige bug de formatação

pick h7i8j9k Adiciona testes unitários</code></pre>

<p>Você pode modificar para:</p>

<pre><code>pick a1b2c3d Adiciona validação de email

squash d4e5f6g Corrige bug de formatação

reword h7i8j9k Adiciona testes unitários</code></pre>

<ul>

<li><code>pick</code>: mantém o commit como está</li>

<li><code>squash</code> (ou <code>s</code>): combina este commit com o anterior e permite editar a mensagem</li>

<li><code>reword</code> (ou <code>r</code>): mantém as mudanças mas permite editar a mensagem</li>

<li><code>drop</code> (ou <code>d</code>): remove o commit completamente</li>

<li><code>fixup</code> (ou <code>f</code>): como squash mas descarta a mensagem do commit</li>

</ul>

<pre><code class="language-bash"># Exemplo real: você tem 3 commits e quer deixar apenas 1

git rebase -i HEAD~3

Edita: pick primeiro, squash segundo, squash terceiro

Resultado: 1 commit com todas as mudanças</code></pre>

<h3>Rebase sobre outra Branch</h3>

<p>Cenário comum: você criou feature a partir de main, mas main evoluiu enquanto você trabalhava. Você quer seus commits em cima da versão atual de main.</p>

<pre><code class="language-bash"># Você está em &#039;feature&#039;

git rebase main

Isso reaplica seus commits em cima de main

Se houver conflitos:

1. Resolva manualmente os arquivos

2. git add .

3. git rebase --continue

Se quiser cancelar:

git rebase --abort</code></pre>

<blockquote><p><strong>Regra de Ouro</strong>: Nunca faça rebase em commits que já foram pusheados para um repositório compartilhado. Rebase reescreve histórico. Se alguém já fez pull desses commits, você criará problemas. Use rebase apenas em branches locais ou branches que você controla sozinho.</p></blockquote>

<p>---</p>

<h2>Cherry-pick: Selecionando Commits Específicos</h2>

<h3>Quando e Por que Usar</h3>

<p>Cherry-pick é simples: você copia um commit específico de uma branch e o aplica em outra. Diferente de rebase que move uma sequência inteira, cherry-pick permite seletividade cirúrgica.</p>

<p>Casos de uso reais: um bug foi corrigido em develop mas precisa estar urgentemente em production; você commitou em feature por engano e precisa em main; uma hotfix foi feita em uma branch e precisa em várias outras. Em todos esses casos, cherry-pick é sua ferramenta.</p>

<h3>Cherry-pick Prático</h3>

<pre><code class="language-bash"># Você está em &#039;main&#039; e quer trazer o commit abc123d de &#039;develop&#039;

git cherry-pick abc123d

Se houver conflitos:

git cherry-pick --continue

ou desistir:

git cherry-pick --abort

Cherry-pick múltiplos commits em sequência

git cherry-pick abc123d def456e ghi789f</code></pre>

<p>Exemplo realista: seu repositório tem main (production) e develop. Um bug crítico foi corrigido em develop no commit <code>a3b2c1d</code>. Você precisa desse fix em production hoje.</p>

<pre><code class="language-bash"># Em main

git cherry-pick a3b2c1d

O commit é agora parte de main com um novo hash (porque mudou a parent)

Isso é esperado e correto</code></pre>

<h3>Cuidado com Cherry-pick</h3>

<pre><code class="language-bash"># Ruim: fazer cherry-pick de 50 commits de uma vez

git cherry-pick develop~50..develop

Bom: usar rebase se precisa de uma sequência inteira

git rebase develop</code></pre>

<p>Cherry-pick deixa rastros claros no histórico (o hash muda, mas a mensagem e o autor são preservados), o que é bom para auditoria. Mas se você está movendo muitos commits de uma vez, rebase é a ferramenta correta.</p>

<p>---</p>

<h2>Bisect: Encontrando o Commit que Quebrou Tudo</h2>

<h3>Binary Search no Histórico</h3>

<p>Imagine: seu código estava funcionando há 50 commits atrás, agora está quebrado. Você não sabe qual commit introduziu o bug. Procurar manualmente é insano. Aqui entra <code>git bisect</code>: uma busca binária que reduz 50 commits para descobrir em ~6 iterações.</p>

<p>Bisect funciona assim: você marca um commit como &quot;bom&quot; (sem o bug) e outro como &quot;ruim&quot; (com o bug), e git divide o espaço no meio, pedindo para você testar. Baseado na resposta, ele elimina metade dos commits suspeitos. Repete até encontrar o commit exato.</p>

<h3>Bisect Manual</h3>

<pre><code class="language-bash"># Iniciar bisect

git bisect start

Marcar o commit atual como ruim (tem o bug)

git bisect bad

Marcar um commit antigo como bom (não tem o bug)

git bisect good abc123d

Git agora te coloca em um commit no meio

Você testa se tem o bug ou não

Se este commit tem o bug:

git bisect bad

Se não tem:

git bisect good

Repita até git encontrar o commit exato

Quando terminar:

git bisect reset</code></pre>

<p>Exemplo com números. Digamos que você tem 64 commits. Bisect funciona assim:</p>

<pre><code>Commits: [bom] ........ [meio=commit 32] ........ [ruim]

Você testa: ainda é ruim

Commits: [bom] .... [meio=commit 16] .... [ruim]

Você testa: é bom

Commits: [bom] [meio=commit 24] [ruim]

... em ~6 testes você encontra o exato</code></pre>

<h3>Bisect Automatizado</h3>

<pre><code class="language-bash"># Se você tem um script/teste que pode detectar o bug automaticamente

git bisect start

git bisect bad HEAD

git bisect good abc123d

Comando automático que executa seu teste

git bisect run ./test_script.sh

test_script.sh retorna:

0 = sucesso (commit é bom)

1 = falha (commit é ruim)

125 = skip este commit</code></pre>

<pre><code class="language-bash">#!/bin/bash

test_script.sh

npm test

Retorna 0 se passar, 1 se falhar</code></pre>

<p>---</p>

<h2>Recuperação de Histórico: Reflog e Dangling Commits</h2>

<h3>Reflog: Seu Seguro contra Perdas</h3>

<p>Reflog (reference log) é um log de todas as mudanças nos ponteiros das branches localmente. Deletou uma branch por acidente? Fez um reset errado? Reflog tem tudo. É diferente do histórico normal de commits — é um histórico de &quot;onde você esteve&quot; no seu repositório.</p>

<pre><code class="language-bash"># Ver reflog

git reflog

Saída algo assim:

a1b2c3d HEAD@{0}: commit: Adiciona feature X

d4e5f6g HEAD@{1}: rebase -i (finish): returning to refs/heads/feature

h7i8j9k HEAD@{2}: rebase -i (start): checkout main

l0m1n2o HEAD@{3}: checkout: moving from main to feature</code></pre>

<p>Cada linha representa um movimento. <code>HEAD@{0}</code> é o estado atual, <code>HEAD@{1}</code> é um estado atrás, etc. Você pode usar reflog para ir para qualquer estado anterior.</p>

<h3>Recuperando uma Branch Deletada</h3>

<pre><code class="language-bash"># Você acidentalmente fez

git branch -D feature

Use reflog para ver onde estava

git reflog

Encontre algo como:

a1b2c3d HEAD@{5}: commit: Último commit da feature

Recupere criando uma nova branch no mesmo ponto

git branch feature a1b2c3d

Pronto, a branch está recuperada</code></pre>

<h3>Dangling Commits</h3>

<p>Commits não referenciados (não estão em nenhuma branch) aparecem como &quot;dangling&quot;. Reflog mantém referências a eles por padrão durante 90 dias.</p>

<pre><code class="language-bash"># Ver commits orfãos

git fsck --lost-found

Buscar commits perdidos

git log --all --graph --oneline --decorate

Se quiser recuperar um commit específico

git show a1b2c3d # veja o conteúdo

git branch recover-branch a1b2c3d # crie uma branch nele</code></pre>

<h3>Reset, Revert e Restore: Diferenças Críticas</h3>

<p>Essas três operações parecem fazer a mesma coisa, mas não fazem:</p>

<pre><code class="language-bash"># git reset: move o HEAD (reescreve histórico local)

git reset --soft HEAD~1 # desfaz commit, mantém mudanças staged

git reset --mixed HEAD~1 # desfaz commit, mantém mudanças unstaged (padrão)

git reset --hard HEAD~1 # desfaz commit, descarta mudanças (CUIDADO!)

git revert: cria um NOVO commit que desfaz as mudanças (seguro)

git revert abc123d # cria novo commit que inverte as mudanças do abc123d

git restore: descarta mudanças em arquivos específicos

git restore arquivo.txt # descarta mudanças não commitadas

git restore --source=abc123d arquivo.txt # restaura arquivo de um commit</code></pre>

<p><strong>Quando usar cada um:</strong></p>

<ul>

<li><code>reset</code>: você quer desfazer commits <strong>locais não pusheados</strong></li>

<li><code>revert</code>: você quer desfazer commits <strong>que foram pusheados</strong> (seguro para histórico compartilhado)</li>

<li><code>restore</code>: você quer desfazer edições em <strong>arquivos específicos</strong></li>

</ul>

<pre><code class="language-bash"># Exemplo: você commitou credenciais por acidente em abc123d

Opcão 1 (se ninguém fez pull):

git reset --hard HEAD~1

Opção 2 (se foi pusheado):

git revert abc123d

git push

Opção 3 (remover apenas um arquivo de um commit passado):

git restore --source=abc123d~1 credenciais.env

git add credenciais.env

git commit --amend # adiciona à mensagem anterior</code></pre>

<p>---</p>

<h2>Casos Práticos Integrados</h2>

<h3>Cenário 1: Limpando uma Feature Branch Bagunçada</h3>

<pre><code class="language-bash"># Você tem 8 commits em &#039;feature&#039; mas alguns são fixups/ajustes

Quer limpar antes de fazer merge em main

git checkout feature

git rebase -i main

Editor abre:

pick a1b2c3d Implementa login

pick d4e5f6g Adiciona validação email

pick h7i8j9k Corrige typo em login

pick l0m1n2o Testa login com mobile

...

Você edita para:

pick a1b2c3d Implementa login

squash h7i8j9k Corrige typo em login

pick d4e5f6g Adiciona validação email

squash l0m1n2o Testa login com mobile

pick ...

Resultado: 4 commits bem organizados em vez de 8 bagunçados

git push -f # força push (apenas em branches suas!)</code></pre>

<h3>Cenário 2: Hotfix em Production que precisa voltar para Develop</h3>

<pre><code class="language-bash"># main (production) tinha um bug urgente

Criou hotfix, commitmou fix abc123d, pushou para main

Agora precisa voltar o fix para develop também

git checkout develop

git cherry-pick abc123d

Se houver conflitos (código evoluiu diferente):

Resolve manualmente

git add .

git cherry-pick --continue

git push</code></pre>

<h3>Cenário 3: Encontrando qual deploy quebrou</h3>

<pre><code class="language-bash"># Sabia que breaks entre v1.2.3 e v1.3.0

v1.2.3 é bom, v1.3.0 é ruim

git bisect start

git bisect bad v1.3.0

git bisect good v1.2.3

Git coloca você em um commit no meio

Você testa sua aplicação

Se funciona:

git bisect good

Se quebra:

git bisect bad

Repete até descobrir o commit exato

Quando encontra:

Commit abc123d é o primeiro bad commit

Você pode revert ou cherry-pick um fix para ele</code></pre>

<p>---</p>

<h2>Conclusão</h2>

<p>Você aprendeu três lições fundamentais que elevam seu git de &quot;usuário&quot; para &quot;profissional&quot;:</p>

<ol>

<li><strong>Rebase e cherry-pick são ferramentas de poder responsável</strong>: eles reescrevem histórico (rebase) ou selecionam commits cirurgicamente (cherry-pick). Ambos deixam um repositório mais limpo e legível, mas exigem cuidado com branches compartilhadas. A regra é simples: rebase local, revert compartilhado.</li>

</ol>

<ol>

<li><strong>Bisect transforma &quot;encontrar o bug&quot; de uma tarefa manual exaustiva em um problema de busca binária que se resolve em minutos</strong>, mesmo com centenas de commits. É especialmente poderoso quando combinado com scripts automatizados que detectam o problema.</li>

</ol>

<ol>

<li><strong>Reflog, reset, revert e restore formam uma rede de segurança contra erros</strong>. Quase nada é permanentemente perdido em git — reflog segura seus commits órfãos, revert permite desfazer publicamente sem reescrever histórico, e reset/restore lidam com situações locais. Memorize a diferença entre essas operações; é exatamente onde mais gente erra.</li>

</ol>

<p>O domínio dessas técnicas não é vanidade — é profissionalismo. Projetos reais têm histórico bagunçado, bugs misteriosos e situações onde alguém commitou algo na branch errada às 3 da manhã. Você será a pessoa que resolve isso em 5 minutos em vez de 5 horas.</p>

<p>---</p>

<h2>Referências</h2>

<ul>

<li><a href="https://git-scm.com/docs/git-rebase" target="_blank" rel="noopener noreferrer">Git Official Documentation - git-rebase</a></li>

<li><a href="https://git-scm.com/docs/git-cherry-pick" target="_blank" rel="noopener noreferrer">Git Official Documentation - git-cherry-pick</a></li>

<li><a href="https://git-scm.com/docs/git-bisect" target="_blank" rel="noopener noreferrer">Git Official Documentation - git-bisect</a></li>

<li><a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History" target="_blank" rel="noopener noreferrer">Pro Git Book - Chapter 7: Git Tools</a></li>

<li><a href="https://www.atlassian.com/git/tutorials/advanced-overview" target="_blank" rel="noopener noreferrer">Atlassian Git Tutorials - Advanced Git</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

O que Todo Dev Deve Saber sobre Terraform Avançado: Módulos, Workspaces e Remote State
O que Todo Dev Deve Saber sobre Terraform Avançado: Módulos, Workspaces e Remote State

Entendendo Módulos no Terraform Um módulo no Terraform é um diretório contend...

O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais
O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais

Arquitetura Moderna na AWS: Da Orquestração de Contêineres ao Serverless A co...

ConfigMaps e Secrets em Kubernetes: Gerenciando Configuração na Prática
ConfigMaps e Secrets em Kubernetes: Gerenciando Configuração na Prática

ConfigMaps e Secrets em Kubernetes: Gerenciando Configuração Quando você trab...