<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Git on kenji.blog</title><link>http://kenji.blog/pt/categories/git/</link><description>Recent content in Git on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>pt</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 09:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/pt/categories/git/index.xml" rel="self" type="application/rss+xml"/><item><title>【Comandos Git】A diferença entre rebase e merge e como usá-los corretamente na prática</title><link>http://kenji.blog/pt/p/git-rebase-vs-merge-practical-guide/</link><pubDate>Sun, 13 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/git-rebase-vs-merge-practical-guide/</guid><description>&lt;img src="http://kenji.blog/p/git-rebase-vs-merge-practical-guide/img/eyecatch.jpg" alt="Featured image of post 【Comandos Git】A diferença entre rebase e merge e como usá-los corretamente na prática" />&lt;h1 id="1-introdução-por-que-merge-ou-rebase-é-um-dilema-eterno">1. Introdução: Por que &amp;ldquo;merge ou rebase&amp;rdquo; é um dilema eterno
&lt;/h1>&lt;p>Git é um sistema de controle de versão indispensável no desenvolvimento de software moderno. Quando vários desenvolvedores alteram uma base de código simultaneamente, o poderoso modelo de branches do Git entra em ação. No entanto, no desenvolvimento em equipe, a discussão sobre &amp;ldquo;qual usar: &lt;code>merge&lt;/code> ou &lt;code>rebase&lt;/code>&amp;rdquo; é um tópico que sempre atormenta os desenvolvedores, de iniciantes a veteranos.&lt;/p>
&lt;p>Neste artigo, desvendaremos a diferença entre os mecanismos de &lt;code>git merge&lt;/code> e &lt;code>git rebase&lt;/code>, explorando a estrutura interna do Git, como o DAG (Grafo Acíclico Direcionado) e as propriedades matemáticas dos hashes de commit. Além disso, explicaremos detalhadamente como usá-los corretamente na prática, com fluxos de trabalho específicos. Ao compreender as operações matemáticas que o Git realiza nos bastidores, e não apenas introduzir comandos, você perderá o medo de conflitos e poderá construir um histórico limpo e rastreável.&lt;/p>
&lt;hr>
&lt;h1 id="2-estrutura-interna-do-git-hashes-de-commit-e-modelo-de-objetos">2. Estrutura interna do Git: Hashes de commit e modelo de objetos
&lt;/h1>&lt;p>Para entender como o Git integra o histórico, primeiro precisamos saber como ele armazena dados. O Git não armazena apenas as diferenças (patches) de alterações de arquivos, mas sim um instantâneo (snapshot) de todo o sistema de arquivos em um determinado momento.&lt;/p>
&lt;h2 id="21-propriedades-criptográficas-dos-hashes-de-commit">2.1 Propriedades criptográficas dos hashes de commit
&lt;/h2>&lt;p>Cada commit no Git é identificado de forma única por um número hexadecimal de 40 dígitos gerado pela função de hash SHA-1 (Secure Hash Algorithm 1), calculada com base no seu conteúdo. Um objeto de commit é composto pelos seguintes elementos:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Ponteiro para o objeto Tree&lt;/strong>: O instantâneo da estrutura de diretórios e arquivos (Blob) naquele momento&lt;/li>
&lt;li>&lt;strong>Ponteiro para o commit pai&lt;/strong>: O valor do hash de um ou mais commits pais (o primeiro commit não tem pai e um commit de merge tem dois ou mais pais)&lt;/li>
&lt;li>&lt;strong>Informações do autor (Author)&lt;/strong>: A pessoa que escreveu o código e a data/hora&lt;/li>
&lt;li>&lt;strong>Informações do committer (Committer)&lt;/strong>: A pessoa que criou/aplicou o commit e a data/hora&lt;/li>
&lt;li>&lt;strong>Mensagem de commit&lt;/strong>: Texto explicando a intenção da alteração&lt;/li>
&lt;/ol>
&lt;p>Matematicamente, o valor do hash $H(C)$ para um objeto de commit $C$ é definido da seguinte forma:&lt;/p>
$$
H(C) = \text{SHA-1}( \text{tree} \parallel \text{parent} \parallel \text{author} \parallel \text{committer} \parallel \text{message} )
$$&lt;p>Aqui, $\parallel$ representa a concatenação de dados. Devido às propriedades da função de hash, mudar até mesmo um único caractere na mensagem de commit, ou ter um commit pai diferente, gerará um valor de hash completamente diferente. Ou seja, &lt;strong>os commits são imutáveis (Immutable)&lt;/strong>. Quando dizemos que o &lt;code>rebase&lt;/code>, que será explicado mais adiante, &amp;ldquo;reescreve o histórico&amp;rdquo;, na verdade ele &amp;ldquo;cria novos commits com conteúdos semelhantes, mas com hashes diferentes&amp;rdquo;.&lt;/p>
&lt;p>O tamanho do espaço de hash é $2^{160}$ e a probabilidade $P$ de ocorrer uma colisão (dois commits diferentes com o mesmo valor de hash) pode ser aproximada usando a teoria do Paradoxo do Aniversário (onde $n$ é o número de commits):&lt;/p>
$$
P(\text{collision}) \approx 1 - \exp\left(-\frac{n^2}{2 \times 2^{160}}\right)
$$&lt;p>Essa probabilidade é extremamente baixa e, na prática, é quase impossível que os hashes de commit do Git colidam.&lt;/p>
&lt;hr>
&lt;h1 id="3-teoria-dos-grafos-e-dag-o-modelo-matemático-do-histórico-do-git">3. Teoria dos grafos e DAG: O modelo matemático do histórico do Git
&lt;/h1>&lt;p>O histórico de commits do Git é modelado como um &amp;ldquo;Grafo Acíclico Direcionado (DAG - Directed Acyclic Graph)&amp;rdquo; na teoria dos grafos.&lt;/p>
&lt;h2 id="31-o-que-é-um-dag-grafo-acíclico-direcionado">3.1 O que é um DAG (Grafo Acíclico Direcionado)
&lt;/h2>&lt;p>Em um grafo $G = (V, E)$, $V$ é o conjunto de commits (vértices) e $E$ é o conjunto de arestas direcionadas que indicam as relações pai-filho entre os commits. No Git, a direção das arestas vai &amp;ldquo;do commit filho para o commit pai&amp;rdquo;. Isso ocorre porque um novo commit contém um ponteiro para um commit passado.&lt;/p>
&lt;pre class="mermaid">
graph BT
A[&amp;#34;Commit A (Inicial)&amp;#34;]
B[&amp;#34;Commit B&amp;#34;]
C[&amp;#34;Commit C (Main)&amp;#34;]
D[&amp;#34;Commit D (Feature)&amp;#34;]
E[&amp;#34;Commit E (Merge)&amp;#34;]
B --&amp;gt; A
C --&amp;gt; B
D --&amp;gt; B
E --&amp;gt; C
E --&amp;gt; D
&lt;/pre>
&lt;p>A maior característica do DAG é a &amp;ldquo;ausência de ciclos (loops)&amp;rdquo;. Isso garante que algoritmos que rastreiam o histórico de commits nunca entrem em um loop infinito e alcancem com segurança o fim (o commit inicial).&lt;/p>
&lt;h2 id="32-ordenação-topológica-e-a-ordem-do-histórico">3.2 Ordenação topológica e a ordem do histórico
&lt;/h2>&lt;p>Quando o histórico é exibido usando comandos como &lt;code>git log&lt;/code>, o DAG é ordenado como uma lista unidimensional usando o algoritmo de Ordenação Topológica (Topological Sort). Para qualquer aresta direcionada $u \to v$ no DAG ($u$ é filho de $v$), ele é reorganizado para que $u$ venha antes de $v$ na lista.&lt;/p>
&lt;hr>
&lt;h1 id="4-mecanismos-e-tipos-de-git-merge">4. Mecanismos e tipos de git merge
&lt;/h1>&lt;p>O comando mais básico para integrar alterações de uma branch é o &lt;code>git merge&lt;/code>. No entanto, dependendo do estado atual, o Git escolhe automaticamente estratégias de merge diferentes.&lt;/p>
&lt;h2 id="41-merge-fast-forward---ff">4.1 Merge Fast-Forward (&amp;ndash;ff)
&lt;/h2>&lt;p>Se a branch de destino (ex: &lt;code>main&lt;/code>) for um ancestral direto da branch de origem (ex: &lt;code>feature&lt;/code>), o Git executará um merge &amp;ldquo;Fast-Forward&amp;rdquo; (avanço rápido). Esta operação não cria um novo commit; ela simplesmente avança o ponteiro da branch.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
merge feature
&lt;/pre>
&lt;p>Um merge Fast-Forward mantém o histórico em linha reta, mas tem a desvantagem de perder o contexto de &amp;ldquo;quais commits agrupavam o desenvolvimento de uma única funcionalidade (feature)&amp;rdquo;.&lt;/p>
&lt;h2 id="42-merge-non-fast-forward---no-ff">4.2 Merge Non-Fast-Forward (&amp;ndash;no-ff)
&lt;/h2>&lt;p>Ao especificar explicitamente &lt;code>git merge --no-ff&lt;/code>, o Git sempre criará um novo &amp;ldquo;commit de merge&amp;rdquo;, mesmo que um Fast-Forward seja possível. Um commit de merge é um commit especial que tem dois pais.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
commit id: &amp;#34;Trabalho Principal 1&amp;#34;
merge feature type: NORMAL
&lt;/pre>
&lt;p>A vantagem desse método é que a existência e a história da branch da funcionalidade permanecem claras no DAG. Se ocorrer um problema, é possível desfazer (reverter) com segurança a funcionalidade inteira de uma vez, executando &lt;code>git revert -m 1 &amp;lt;hash do commit de merge&amp;gt;&lt;/code>.&lt;/p>
&lt;h2 id="43-algoritmo-3-way-merge-merge-de-3-vias">4.3 Algoritmo 3-Way Merge (Merge de 3 vias)
&lt;/h2>&lt;p>Se a branch de destino e a branch de origem tiverem seus próprios commits independentes, o Git executará um merge de 3 vias. Neste caso, o Git explora o DAG e encontra o &amp;ldquo;ancestral comum mais baixo&amp;rdquo; (LCA - Lowest Common Ancestor) das duas branches.&lt;/p>
&lt;p>A complexidade computacional $T_{\text{LCA}}$ do algoritmo para encontrar o LCA pode ser executada em tempo linear em relação ao número de vértices $|V|$ e arestas $|E|$:&lt;/p>
$$
T_{\text{LCA}} = \mathcal{O}(|V| + |E|)
$$&lt;p>O Git compara três estados: o &amp;ldquo;estado do LCA&amp;rdquo;, o &amp;ldquo;estado da branch atual&amp;rdquo; e o &amp;ldquo;estado da outra branch&amp;rdquo;. Se as alterações não entrarem em conflito, ele gerará um commit de merge automaticamente.&lt;/p>
&lt;hr>
&lt;h1 id="5-mecanismo-do-git-rebase-e-reconstrução-do-histórico">5. Mecanismo do git rebase e reconstrução do histórico
&lt;/h1>&lt;p>Enquanto o &lt;code>git merge&lt;/code> &amp;ldquo;integra&amp;rdquo; o histórico, o &lt;code>git rebase&lt;/code> &amp;ldquo;reconstrói (reorganiza)&amp;rdquo; o histórico.&lt;/p>
&lt;h2 id="51-o-processo-por-trás-do-rebase">5.1 O processo por trás do Rebase
&lt;/h2>&lt;p>Quando você faz o rebase da branch &lt;code>feature&lt;/code> na branch &lt;code>main&lt;/code> (&lt;code>git rebase main&lt;/code>), as operações internas são as seguintes:&lt;/p>
&lt;ol>
&lt;li>Encontra o ancestral comum (LCA) entre a branch &lt;code>feature&lt;/code> e a branch &lt;code>main&lt;/code>.&lt;/li>
&lt;li>Salva as diferenças (diffs) dos commits, do LCA até o topo da branch &lt;code>feature&lt;/code>, em uma área temporária.&lt;/li>
&lt;li>Move o ponteiro da branch &lt;code>feature&lt;/code> para o topo da branch &lt;code>main&lt;/code>.&lt;/li>
&lt;li>Aplica sequencialmente (Cherry-Pick) as diferenças salvas na nova base (o topo da &lt;code>main&lt;/code>), criando novos commits um por um.&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Commit A&amp;#34;] --&amp;gt; B[&amp;#34;Commit B&amp;#34;]
B --&amp;gt; C[&amp;#34;Commit C (Main)&amp;#34;]
B --&amp;gt; D[&amp;#34;Commit D (Feature Antigo)&amp;#34;]
D -.-&amp;gt; E[&amp;#34;Commit D&amp;#39; (Novo Feature)&amp;#34;]
C --&amp;gt; E
style D stroke-dasharray: 5 5, fill: #f9f9f9, color: #999
&lt;/pre>
&lt;p>O ponto crucial aqui é que o commit gerado pelo rebase, $D'$, tem um &lt;strong>commit pai diferente do commit original $D$, portanto, ele tem um valor de hash completamente diferente&lt;/strong> (consulte a definição da função de hash $H(C)$ mencionada anteriormente).&lt;/p>
&lt;h2 id="52-interactive-rebase-rebase-interativo">5.2 Interactive Rebase (Rebase Interativo)
&lt;/h2>&lt;p>Ao usar &lt;code>git rebase -i&lt;/code> (ou &lt;code>--interactive&lt;/code>), você pode manipular o histórico de commits como quiser. Esta é a ferramenta mais poderosa para organizar seu histórico local.&lt;/p>
&lt;ul>
&lt;li>&lt;code>pick&lt;/code>: Mantém o commit como está.&lt;/li>
&lt;li>&lt;code>reword&lt;/code>: Altera apenas a mensagem do commit.&lt;/li>
&lt;li>&lt;code>edit&lt;/code>: Pausa para modificar o conteúdo do commit.&lt;/li>
&lt;li>&lt;code>squash&lt;/code>: Funde este commit com o commit anterior, combinando também suas mensagens.&lt;/li>
&lt;li>&lt;code>fixup&lt;/code>: Semelhante ao &lt;code>squash&lt;/code>, mas descarta a mensagem deste commit.&lt;/li>
&lt;li>&lt;code>drop&lt;/code>: Remove o commit completamente.&lt;/li>
&lt;/ul>
&lt;p>Matematicamente, se uma branch tem $N$ commits, as variações de histórico linear (permutações) $P$ que podem ser geradas pela reordenação no rebase são:&lt;/p>
$$
P = N!
$$&lt;p>O Git dá aos desenvolvedores $N!$ opções, permitindo-lhes manter o histórico lógico e elegante.&lt;/p>
&lt;hr>
&lt;h1 id="6-a-regra-de-ouro-do-rebase-the-golden-rule-of-rebase">6. A Regra de Ouro do Rebase (The Golden Rule of Rebase)
&lt;/h1>&lt;p>Embora o &lt;code>rebase&lt;/code> seja muito poderoso, existe uma regra absoluta:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;Nunca faça rebase em um histórico público compartilhado.&amp;rdquo;&lt;/strong>
&lt;em>(Never rebase public history)&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;h2 id="61-por-que-você-não-deve-fazer-rebase-em-um-histórico-público">6.1 Por que você não deve fazer rebase em um histórico público?
&lt;/h2>&lt;p>O Git é distribuído. Os commits que você enviou para o &lt;code>origin/main&lt;/code> também foram clonados nos repositórios locais de outros desenvolvedores. Se você fizer rebase de commits já enviados, reescrever o histórico e sobrescrever à força com &lt;code>git push --force&lt;/code>, o que acontecerá?&lt;/p>
&lt;p>O DAG no repositório local de outros desenvolvedores divergiria fundamentalmente do DAG remoto. Quando outros desenvolvedores executarem &lt;code>git pull&lt;/code>, o Git tentará forçar o merge de grupos de commits com históricos diferentes, gerando um número massivo de conflitos e commits duplicados (mesmo conteúdo, mas hashes diferentes), deixando o repositório em pânico.&lt;/p>
&lt;p>O rebase só deve ser executado em &lt;strong>&amp;ldquo;branches locais que você ainda não compartilhou com ninguém&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="7-resolução-de-conflitos-e-git-rebase---continue">7. Resolução de conflitos e git rebase &amp;ndash;continue
&lt;/h1>&lt;p>Se várias pessoas alterarem a mesma parte do mesmo arquivo, ocorrerá um conflito. O processo de resolução de conflitos é diferente entre &lt;code>merge&lt;/code> e &lt;code>rebase&lt;/code>.&lt;/p>
&lt;h2 id="71-resolução-de-conflitos-no-merge">7.1 Resolução de conflitos no Merge
&lt;/h2>&lt;p>Com o &lt;code>git merge&lt;/code>, a resolução de conflitos ocorre &lt;strong>apenas uma vez&lt;/strong>. Antes de criar o commit de merge final, você corrige todas as partes conflitantes de uma só vez.&lt;/p>
&lt;h2 id="72-resolução-de-conflitos-no-rebase">7.2 Resolução de conflitos no Rebase
&lt;/h2>&lt;p>Com o &lt;code>git rebase&lt;/code>, como os commits são reaplicados um por um, &lt;strong>podem ocorrer conflitos em cada commit&lt;/strong>.&lt;/p>
&lt;p>Se ocorrer um conflito durante um rebase, o Git irá pausar o processo. O fluxo de resolução é o seguinte:&lt;/p>
&lt;ol>
&lt;li>Abra seu editor ou IDE (como VS Code) e resolva manualmente os marcadores de conflito (&lt;code>&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code>, &lt;code>======&lt;/code> e &lt;code>&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code>).&lt;/li>
&lt;li>Adicione os arquivos modificados ao índice:
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add &amp;lt;arquivo_modificado&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>Retome o processo de rebase sem criar um novo commit:
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Se você quiser cancelar o rebase e retornar ao estado original, execute o seguinte comando:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --abort
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>(&lt;em>Se a resolução do conflito não for necessária e você quiser pular aquele commit específico, use &lt;code>git rebase --skip&lt;/code>&lt;/em>)&lt;/p>
&lt;hr>
&lt;h1 id="8-uso-correto-na-prática-workflow-prático">8. Uso correto na prática (Workflow prático)
&lt;/h1>&lt;p>Então, como devemos escolher entre &lt;code>merge&lt;/code> e &lt;code>rebase&lt;/code> no desenvolvimento real? Aqui apresentamos a abordagem mais padrão e segura.&lt;/p>
&lt;h2 id="81-cenário-1-organizar-o-histórico-de-trabalho-local-uso-do-rebase">8.1 [Cenário 1] Organizar o histórico de trabalho local (Uso do Rebase)
&lt;/h2>&lt;p>Imagine que, ao desenvolver em uma branch de funcionalidade, muitos commits pequenos (&amp;ldquo;correção de erro de digitação&amp;rdquo;, &amp;ldquo;salvamento temporário&amp;rdquo;, etc.) se acumularam. Antes de abrir um Pull Request (PR), você usa o rebase interativo para organizá-los em unidades significativas.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Execute enquanto estiver na branch feature&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (O editor será aberto. Use squash ou fixup para limpar o histórico)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso criará um histórico de commits limpo e fácil para os revisores entenderem sua intenção.&lt;/p>
&lt;h2 id="82-cenário-2-acompanhar-as-atualizações-da-branch-main-uso-do-rebase">8.2 [Cenário 2] Acompanhar as atualizações da branch main (Uso do Rebase)
&lt;/h2>&lt;p>Se o desenvolvimento demorar e alterações de outras pessoas continuarem sendo mescladas na branch &lt;code>main&lt;/code>, sua branch &lt;code>feature&lt;/code> ficará desatualizada. Neste caso, faça o rebase da sua branch &lt;code>feature&lt;/code> na branch &lt;code>main&lt;/code> mais recente.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Obtenha as informações mais recentes da main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Faça o rebase da branch feature na versão mais recente da main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase origin/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso mantém o histórico linear e evita conflitos em merges futuros. Também evita a criação de commits de merge desnecessários (&amp;ldquo;Merge branch &amp;lsquo;main&amp;rsquo; into feature&amp;rdquo;).&lt;/p>
&lt;h2 id="83-cenário-3-integrar-uma-funcionalidade-concluída-uso-do-merge">8.3 [Cenário 3] Integrar uma funcionalidade concluída (Uso do Merge)
&lt;/h2>&lt;p>O desenvolvimento na branch &lt;code>feature&lt;/code> está concluído e é hora de integrá-lo à branch &lt;code>main&lt;/code>. Aqui, usamos &lt;strong>&lt;code>git merge --no-ff&lt;/code>&lt;/strong> (equivalente a escolher &amp;ldquo;Create a merge commit&amp;rdquo; em um Pull Request do GitHub).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge --no-ff feature -m &lt;span class="s2">&amp;#34;Merge feature: Implementação da funcionalidade de login de usuário&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso deixa um ponto de conexão histórico (commit de merge) no DAG da branch &lt;code>main&lt;/code> dizendo que &amp;ldquo;uma funcionalidade foi mesclada aqui&amp;rdquo;. Ao olhar para o histórico mais tarde, será mais fácil rastrear o código por funcionalidade.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusão">9. Conclusão
&lt;/h1>&lt;p>Na operação do Git, as abordagens extremas de &amp;ldquo;fazer tudo com Merge&amp;rdquo; ou &amp;ldquo;manter tudo linear com Rebase&amp;rdquo; têm seus prós e contras.&lt;/p>
&lt;p>A melhor prática no mundo real é uma abordagem híbrida: &lt;strong>&amp;ldquo;organize o histórico privado local de forma elegante com rebase e deixe o contexto no histórico público de integração com merge &amp;ndash;no-ff&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Local (Espaço de trabalho pessoal)&lt;/strong>: Use o &lt;code>rebase&lt;/code> para eliminar commits desnecessários e acompanhar a linha principal mais recente para manter um histórico linear.&lt;/li>
&lt;li>&lt;strong>Global (Espaço de trabalho compartilhado)&lt;/strong>: Use &lt;code>merge --no-ff&lt;/code> para registrar a existência da branch de funcionalidade como um commit de merge no DAG, facilitando a reversão e o rastreamento.&lt;/li>
&lt;/ul>
&lt;p>Ao compreender a matemática e a arquitetura por trás da estrutura DAG e da função hash, os comandos Git passam da simples memorização para um &amp;ldquo;design de histórico intencional&amp;rdquo;. Seguindo a Regra de Ouro do Rebase, vamos selecionar os comandos adequados à situação e construir um histórico de commits limpo, legível e de fácil manutenção para toda a equipe.&lt;/p></description></item><item><title>Erros comuns de iniciantes no Git e comandos de solução (resolução de conflitos, etc.)</title><link>http://kenji.blog/pt/p/git-beginners-mistakes-and-solutions/</link><pubDate>Sat, 12 Sep 2026 17:00:00 +0900</pubDate><guid>http://kenji.blog/pt/p/git-beginners-mistakes-and-solutions/</guid><description>&lt;img src="http://kenji.blog/p/git-beginners-mistakes-and-solutions/img/eyecatch.jpg" alt="Featured image of post Erros comuns de iniciantes no Git e comandos de solução (resolução de conflitos, etc.)" />&lt;h1 id="erros-comuns-de-iniciantes-no-git-e-comandos-de-solução-resolução-de-conflitos-etc">Erros comuns de iniciantes no Git e comandos de solução (resolução de conflitos, etc.)
&lt;/h1>&lt;h2 id="1-introdução-por-que-cometemos-erros-no-git">1. Introdução: Por que cometemos erros no Git?
&lt;/h2>&lt;p>No desenvolvimento de software, o Git tornou-se tão indispensável quanto o ar ou a água. No entanto, para muitos iniciantes (e às vezes até para os mais experientes), o Git pode parecer uma &amp;ldquo;terrível caixa preta mágica&amp;rdquo;. Commits que desaparecem, grandes quantidades de alterações empurradas para a branch errada, ou mensagens de erro de conflito nunca vistas enchendo a tela&amp;hellip; Ao cair nessas &amp;ldquo;armadilhas do Git&amp;rdquo;, o progresso do trabalho é completamente interrompido e, no pior dos casos, você é tomado pelo medo de acabar destruindo o código-fonte.&lt;/p>
&lt;p>Por que o Git é tão difícil e propenso a erros? O maior motivo é que &amp;ldquo;as pessoas decoram comandos superficiais e os usam sem entender o que está acontecendo dentro do Git&amp;rdquo;. Embora o Git seja baseado em uma filosofia de design robusta como um sistema de controle de versão distribuído (DVCS), sua interface (CLI) nem sempre é intuitiva.&lt;/p>
&lt;p>Neste artigo, categorizamos muitos &amp;ldquo;deslizes (erros comuns)&amp;rdquo; que os iniciantes no Git frequentemente encontram na prática, e apresentamos os comandos específicos de solução para cada um deles. No entanto, não será apenas uma lista de comandos (cheat sheet). Iremos explorar a fundo, com um volume de mais de 10.000 caracteres, &amp;ldquo;por que esses erros ocorrem&amp;rdquo; e &amp;ldquo;como os dados se movem internamente no Git ao executar esse comando&amp;rdquo;, utilizando a estrutura do diretório &lt;code>.git&lt;/code>, a base matemática do algoritmo Diff em segundo plano e diagramas no Mermaid.&lt;/p>
&lt;p>Ao terminar de ler este artigo, você deverá estar livre do sentimento de &amp;ldquo;o Git assusta&amp;rdquo; e, em vez disso, estará convencido de que &amp;ldquo;não há parceiro mais confiável do que o Git&amp;rdquo;. Então, vamos mergulhar no mundo profundo do Git.&lt;/p>
&lt;hr>
&lt;h2 id="2-o-abismo-do-git-entendendo-a-estrutura-interna-do-diretório-git">2. O abismo do Git: Entendendo a estrutura interna do diretório &lt;code>.git&lt;/code>
&lt;/h2>&lt;p>O primeiro passo para facilitar muitas resoluções de problemas é saber como o Git armazena os dados. A pasta oculta &lt;code>.git&lt;/code> presente no diretório raiz do seu projeto é o próprio coração do Git. O Git não é apenas um sistema que registra sequencialmente as diferenças (patches) de arquivos, mas gerencia os dados como um &lt;strong>fluxo de snapshots&lt;/strong>.&lt;/p>
&lt;h3 id="21-modelo-de-objetos-blob-tree-commit">2.1 Modelo de objetos: Blob, Tree, Commit
&lt;/h3>&lt;p>O Git usa principalmente três objetos para representar o estado do repositório. Esses objetos são armazenados em &lt;code>.git/objects&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Blob (Binary Large Object)&lt;/strong>
É o objeto que armazena o próprio conteúdo do arquivo. Informações como nome do arquivo ou permissões não estão incluídas aqui. Sequências de bytes puras são compactadas com zlib e identificadas por um valor de hash SHA-1 (40 caracteres hexadecimais).&lt;/li>
&lt;li>&lt;strong>Tree&lt;/strong>
É o objeto que representa a estrutura de diretórios. O objeto Tree contém ponteiros (valores de hash SHA-1) para outros objetos Tree (subdiretórios) ou objetos Blob (arquivos), bem como seus nomes de arquivos e permissões de acesso. Desempenha um papel semelhante a um diretório UNIX.&lt;/li>
&lt;li>&lt;strong>Commit&lt;/strong>
Mantém um ponteiro para o objeto Tree de nível superior do repositório em um determinado momento, metadados (autor, data e hora do commit, mensagem do commit) e um ponteiro para o commit imediatamente anterior (commit pai).&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
graph TD
Commit1[&amp;#34;Commit (Hash: 9f8a)&amp;#34;] --&amp;gt; Tree1[&amp;#34;Tree (Hash: 4b82)&amp;#34;]
Tree1 --&amp;gt; Blob1[&amp;#34;Blob (Hash: 8d7e) : index.js&amp;#34;]
Tree1 --&amp;gt; Tree2[&amp;#34;Tree (Hash: 3a2c) : src/&amp;#34;]
Tree2 --&amp;gt; Blob2[&amp;#34;Blob (Hash: 5f1b) : app.js&amp;#34;]
&lt;/pre>
&lt;h3 id="22-a-verdadeira-natureza-do-head-e-das-referências-refs">2.2 A verdadeira natureza do HEAD e das Referências (Refs)
&lt;/h3>&lt;p>Ao trabalhar com o Git, a palavra &lt;code>HEAD&lt;/code> é vista com frequência. Esta é uma &lt;strong>referência simbólica (Symbolic Reference)&lt;/strong> que aponta para a branch (ou commit) atualmente verificada (checked out).
Se você abrir o arquivo &lt;code>.git/HEAD&lt;/code> em um editor de texto, verá uma string escrita assim:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">ref: refs/heads/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Isso significa que &amp;ldquo;o estado atual está na ponta da branch &lt;code>main&lt;/code>&amp;rdquo;. E se você abrir &lt;code>.git/refs/heads/main&lt;/code>, encontrará um hash SHA-1 de 40 caracteres, que aponta para o objeto Commit mais recente.
A branch do Git é simplesmente um ponteiro leve (arquivo) que aponta para um commit específico. Sabendo desse fato, o medo de &amp;ldquo;se eu deletar a branch, todos os meus arquivos sumirão?&amp;rdquo; desaparece.&lt;/p>
&lt;hr>
&lt;h2 id="3-decifrando-o-git-com-matemática-algoritmo-diff-e-função-hash">3. Decifrando o Git com matemática: Algoritmo Diff e função Hash
&lt;/h2>&lt;p>Quando o Git detecta conflitos ou exibe diferenças em arquivos, algoritmos avançados estão em execução internamente.&lt;/p>
&lt;h3 id="31-algoritmo-diff-de-myers">3.1 Algoritmo Diff de Myers
&lt;/h3>&lt;p>O algoritmo de detecção de diferença padrão do Git é o algoritmo idealizado por Eugene W. Myers. Quando temos dois arquivos de texto $A$ e $B$, o problema de encontrar o &amp;ldquo;menor procedimento de edição (inserções e exclusões)&amp;rdquo; para transformar $A$ em $B$ pode ser modelado como o problema do caminho mais curto na teoria dos grafos.&lt;/p>
&lt;p>Deixe os comprimentos das strings serem $N, M$, respectivamente, e a soma seja $V = N + M$. No algoritmo de Myers, procuramos a distância de edição (Edit Distance) $D$. A complexidade de tempo desse algoritmo é expressa pela seguinte fórmula:&lt;/p>
$$ \mathcal{O}(V \cdot D) $$&lt;p>Aqui, se as diferenças entre os arquivos forem pequenas (ou seja, $D$ é pequeno), o algoritmo será executado muito rápido $\mathcal{O}(V)$. No entanto, se os arquivos forem completamente diferentes, teremos $D \approx V$, e a pior complexidade computacional será $\mathcal{O}(V^2)$.&lt;/p>
&lt;h3 id="32-patience-diff-e-histogram-diff">3.2 Patience Diff e Histogram Diff
&lt;/h3>&lt;p>Embora o algoritmo de Myers seja aprimorado, ele pode gerar diferenças que não são intuitivas (não fazem sentido) para os humanos quando, por exemplo, a ordem das funções ou classes for significativamente alterada. Para resolver isso, o Git implementou o &lt;code>Patience Diff&lt;/code> e o &lt;code>Histogram Diff&lt;/code>.&lt;/p>
&lt;p>O Patience Diff se concentra em &amp;ldquo;linhas únicas que aparecem apenas uma vez em ambos os arquivos&amp;rdquo; e encontra a maior subsequência comum (Longest Common Subsequence: LCS) delas. Se o número de elementos únicos for $U$, o cálculo da LCS pode ser resolvido com a seguinte complexidade computacional:&lt;/p>
$$ \mathcal{O}(U \log U) $$&lt;p>Quando você acha difícil resolver um conflito, usar &lt;code>git diff --histogram&lt;/code> ou especificar esse algoritmo na estratégia de merge (&lt;code>git merge -s recursive -X histogram&lt;/code>) é uma alternativa.&lt;/p>
&lt;h3 id="33-sha-1-e-a-probabilidade-de-colisão">3.3 SHA-1 e a probabilidade de colisão
&lt;/h3>&lt;p>O Git gerencia todos os objetos usando valores de hash SHA-1. O tamanho do espaço de hash é $2^{160}$. Aproximando a probabilidade de colisão de hash (conteúdos diferentes tendo o mesmo valor de hash) usando o Paradoxo do Aniversário (Birthday Paradox), o número de objetos $k$ necessário para que a probabilidade de colisão $p$ chegue a 50% é o seguinte:&lt;/p>
$$ k \approx \sqrt{2 \ln(2)} \cdot 2^{80} \approx 1.2 \times 2^{80} $$&lt;p>Esse é um número astronômico e, no desenvolvimento de software normal, a probabilidade de uma colisão não intencional é virtualmente zero. Portanto, o Git opera confiando no valor do hash como uma &amp;ldquo;ID única absoluta&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="4-estudo-de-caso-1-fiz-o-commit-na-branch-errada">4. Estudo de caso 1: Fiz o commit na branch errada!
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Sem perceber que estava trabalhando na branch &lt;code>main&lt;/code>, você escreveu todo o código da nova funcionalidade e, para piorar, até executou um &lt;code>git commit&lt;/code>. A intenção original era criar uma branch chamada &lt;code>feature/login&lt;/code> e trabalhar lá!&lt;/p>
&lt;h3 id="solução-git-reset-e-criação-de-branch">Solução: &lt;code>git reset&lt;/code> e criação de branch
&lt;/h3>&lt;p>No Git, os commits são objetos independentes e as branches são apenas ponteiros. Portanto, o problema pode ser resolvido instantaneamente com a operação: &amp;ldquo;criar uma nova branch e retroceder o ponteiro da branch atual&amp;rdquo;.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Crie uma nova branch apontando para o commit atual (o commit feito por engano)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git branch feature/login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Retroceda o ponteiro da branch main para o commit anterior (HEAD~1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># O uso do --keep permite que você redefina de forma segura, mantendo as alterações não confirmadas no diretório de trabalho.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git reset --keep HEAD~1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Mude para a branch correta&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout feature/login
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="ilustração-o-que-aconteceu-internamente">Ilustração: O que aconteceu internamente?
&lt;/h3>&lt;p>Vamos visualizar o movimento do ponteiro da branch neste momento usando o &lt;code>gitGraph&lt;/code> do Mermaid.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;Initial commit&amp;#34;
commit id: &amp;#34;Bugfix&amp;#34;
commit id: &amp;#34;Mistaken Commit&amp;#34; type: HIGHLIGHT
branch feature/login
checkout feature/login
checkout main
&lt;/pre>
&lt;p>Inicialmente, &lt;code>main&lt;/code> e &lt;code>HEAD&lt;/code> apontavam para &amp;ldquo;Mistaken Commit&amp;rdquo;, mas com &lt;code>git branch feature/login&lt;/code>, um novo ponteiro é criado lá. Após isso, apenas o ponteiro &lt;code>main&lt;/code> retorna à posição de &amp;ldquo;Bugfix&amp;rdquo; por causa do &lt;code>git reset&lt;/code>. Os objetos em si não foram excluídos.&lt;/p>
&lt;hr>
&lt;h2 id="5-estudo-de-caso-2-quero-desfazer-um-commit-já-feito-por-push">5. Estudo de caso 2: Quero desfazer um commit já feito por push!
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Você fez o commit de um código cheio de bugs escrito durante a madrugada e, além disso, publicou-o no repositório remoto com &lt;code>git push origin main&lt;/code>. Você percebe o bug grave e empalidece.&lt;/p>
&lt;h3 id="solução-1-cancelar-o-histórico-com-git-revert-recomendadoseguro">Solução 1: Cancelar o histórico com &lt;code>git revert&lt;/code> (Recomendado/Seguro)
&lt;/h3>&lt;p>No desenvolvimento em equipe, é estritamente proibido alterar o histórico de commits que já foram enviados usando &lt;code>git reset&lt;/code> ou afins. Isso causará inconsistência com os repositórios locais de outros desenvolvedores. A abordagem correta é &lt;strong>&amp;ldquo;criar um novo commit inverso que desfaça completamente as alterações do commit errado&amp;rdquo;&lt;/strong>. Este é o &lt;code>git revert&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Crie um commit que desfaça o commit mais recente&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git revert HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>main 7f3a8b2&lt;span class="o">]&lt;/span> Revert &lt;span class="s2">&amp;#34;Mensagem do commit incorreto&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="m">1&lt;/span> file changed, &lt;span class="m">1&lt;/span> insertion&lt;span class="o">(&lt;/span>+&lt;span class="o">)&lt;/span>, &lt;span class="m">10&lt;/span> deletions&lt;span class="o">(&lt;/span>-&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Faça o push para o remoto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;Commit A&amp;#34;
commit id: &amp;#34;Commit B (Mistake)&amp;#34;
commit id: &amp;#34;Revert Commit B&amp;#34; type: REVERSE
&lt;/pre>
&lt;p>O histórico continua avançando e apenas o estado do código volta ao que era.&lt;/p>
&lt;h3 id="solução-2-alterar-o-histórico-com-git-push---force-with-lease">Solução 2: Alterar o histórico com &lt;code>git push --force-with-lease&lt;/code>
&lt;/h3>&lt;p>Se você acabou de fazer push para uma branch que só você usa, alterar o histórico pode ser tolerado.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Redefina o commit localmente e corrija&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git reset --hard HEAD~1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git commit -m &lt;span class="s2">&amp;#34;Correct implementation&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Substituição forçada do histórico remoto&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git push origin feature/login --force-with-lease
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O &lt;code>--force-with-lease&lt;/code> é um push forçado seguro para evitar o acidente de sobrescrever acidentalmente o trabalho de outras pessoas.&lt;/p>
&lt;hr>
&lt;h2 id="6-estudo-de-caso-3-quero-mudar-para-outra-branch-no-meio-do-trabalho-a-mágica-do-stash">6. Estudo de caso 3: Quero mudar para outra branch no meio do trabalho (A mágica do Stash)
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Durante a implementação de um novo recurso na branch &lt;code>feature/A&lt;/code>, o código-fonte ainda está pela metade e nem sequer compila. De repente, seu chefe ordena: &amp;ldquo;Há um bug crítico no ambiente de produção da branch &lt;code>main&lt;/code>, corrija-o agora mesmo!&amp;rdquo;&lt;/p>
&lt;h3 id="solução-salvar-o-trabalho-com-git-stash">Solução: Salvar o trabalho com &lt;code>git stash&lt;/code>
&lt;/h3>&lt;p>O &lt;code>git stash&lt;/code> é um comando que salva temporariamente as alterações não confirmadas (uncommitted) em uma área temporária.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Salve o trabalho atual&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git stash push -m &lt;span class="s2">&amp;#34;WIP: feature A partially implemented&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Torne possível mudar para a branch main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ... (Faça a correção do bug crítico, commit e push) ...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Volte para a branch original quando terminar o trabalho&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout feature/A
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Restaure as alterações salvas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git stash pop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ao executar o &lt;code>git stash&lt;/code>, o Git gera internamente dois objetos de commit especiais e os salva em uma referência chamada &lt;code>refs/stash&lt;/code>. Ou seja, o Stash, afinal de contas, é apenas &amp;ldquo;um commit temporário sem nome&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-estudo-de-caso-4-o-estado-aterrorizante-de-detached-head">7. Estudo de caso 4: O estado aterrorizante de &amp;ldquo;Detached HEAD&amp;rdquo;
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Você executou &lt;code>git checkout 9f8a7b6&lt;/code> porque queria verificar o código em um ponto específico do passado. Então, apareceu &lt;code>You are in 'detached HEAD' state.&lt;/code>. Você fez um commit mesmo assim, mas quando mudou de branch, o commit desapareceu!&lt;/p>
&lt;h3 id="o-mecanismo-do-detached-head">O mecanismo do Detached HEAD
&lt;/h3>&lt;p>Normalmente, o &lt;code>HEAD&lt;/code> aponta para uma branch como &lt;code>refs/heads/main&lt;/code>. No entanto, se você fizer o checkout diretamente em um commit específico, o &lt;code>HEAD&lt;/code> passará a apontar diretamente para o objeto Commit. Isso é chamado de &lt;strong>Detached HEAD (HEAD separado)&lt;/strong>.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Commit A&amp;#34;] --&amp;gt; B[&amp;#34;Commit B&amp;#34;]
B --&amp;gt; C[&amp;#34;Commit C&amp;#34;]
C --&amp;gt; D[&amp;#34;Commit D&amp;#34;]
BranchMain[&amp;#34;Branch: main&amp;#34;] --&amp;gt; D
HEAD[&amp;#34;HEAD&amp;#34;] --&amp;gt; B
style HEAD fill:#f9f,stroke:#333,stroke-width:4px
&lt;/pre>
&lt;p>Mesmo que você adicione commits neste estado, nenhuma branch rastreará esse novo commit. No instante em que você mudar para outra branch, o novo commit se perderá.&lt;/p>
&lt;h3 id="solução-salvar-como-uma-nova-branch">Solução: Salvar como uma nova branch
&lt;/h3>&lt;p>Pode ser resolvido criando uma nova branch no local onde você está agora.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Crie uma nova branch na posição atual do HEAD e mude para ela&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout -b feature/recovered-work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="8-estudo-de-caso-5-resolução-de-conflitos-em-merge-e-rebase">8. Estudo de caso 5: Resolução de conflitos em Merge e Rebase
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Ao executar &lt;code>git merge&lt;/code> ou &lt;code>git rebase&lt;/code>, foi exibido &lt;code>CONFLICT (content)&lt;/code> e o processo foi interrompido.&lt;/p>
&lt;h3 id="a-diferença-entre-merge-e-rebase">A diferença entre Merge e Rebase
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Merge&lt;/strong>
Executa um merge de 3 vias (3-way merge) usando os commits mais recentes de duas branches e seu ancestral comum, criando um commit de merge.&lt;/li>
&lt;li>&lt;strong>Rebase&lt;/strong>
Salva temporariamente os commits da branch atual e os reaplica na ponta do alvo. O histórico se torna uma linha reta.&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;M1&amp;#34;
commit id: &amp;#34;M2&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;F1&amp;#34;
commit id: &amp;#34;F2&amp;#34;
checkout main
commit id: &amp;#34;M3&amp;#34;
merge feature
&lt;/pre>
&lt;h3 id="método-para-resolução-de-conflitos">Método para resolução de conflitos
&lt;/h3>&lt;p>Marcadores como os abaixo são inseridos nos arquivos em que ocorreu um conflito.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span> &lt;span class="nx">HEAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.production.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">=======&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.staging.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="nx">feature&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="nx">api&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O procedimento de resolução é extremamente simples.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Exclua os marcadores e corrija para o código correto.&lt;/strong>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">NODE_ENV&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;production&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">?&lt;/span> &lt;span class="s2">&amp;#34;https://api.production.example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://api.staging.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>&lt;strong>Adicione os arquivos resolvidos à área de staging (preparação).&lt;/strong>
&lt;code>git add&lt;/code> tem o papel de &amp;ldquo;informar ao Git que o conflito foi resolvido&amp;rdquo;.
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ git add index.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>&lt;strong>Conclua o processo.&lt;/strong>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># No caso de um merge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git commit -m &lt;span class="s2">&amp;#34;Resolve merge conflict in index.js&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># No caso de um rebase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Se você entrar em pânico, poderá cancelar a qualquer momento com &lt;code>$ git merge --abort&lt;/code> ou &lt;code>$ git rebase --abort&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="9-estudo-de-caso-6-o-histórico-de-commits-está-uma-bagunça-git-rebase--i">9. Estudo de caso 6: O histórico de commits está uma bagunça! &lt;code>git rebase -i&lt;/code>
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Muitos commits pequenos ocorreram, como &amp;ldquo;Correção de erro de digitação&amp;rdquo;, &amp;ldquo;Correção novamente&amp;rdquo;, &amp;ldquo;Adição de testes&amp;rdquo;. Se você mesclar com &lt;code>main&lt;/code> assim mesmo, o histórico ficará sujo.&lt;/p>
&lt;h3 id="solução-rebase-interativo">Solução: Rebase Interativo
&lt;/h3>&lt;p>Usando &lt;code>git rebase -i&lt;/code> (interactive), você pode alterar a ordem dos commits anteriores, mesclar (squash) vários commits em um só ou corrigir mensagens de commit.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Organize os últimos 3 commits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git rebase -i HEAD~3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>O editor será aberto e as seguintes informações serão exibidas.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick 1a2b3c4 Correção de erro de digitação
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick 2b3c4d5 Correção novamente
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick 3c4d5e6 Adição de testes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Reescreva isto da seguinte forma.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick 1a2b3c4 Implementação do recurso X
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash 2b3c4d5 Correção novamente
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash 3c4d5e6 Adição de testes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ao salvar e fechar, esses três commits serão lindamente consolidados em um só.&lt;/p>
&lt;hr>
&lt;h2 id="10-estudo-de-caso-7-não-sei-quando-o-bug-foi-introduzido-git-bisect">10. Estudo de caso 7: Não sei quando o bug foi introduzido! &lt;code>git bisect&lt;/code>
&lt;/h2>&lt;p>&lt;strong>[Situação]&lt;/strong>
Há um bug na branch &lt;code>main&lt;/code> atual, mas estava normal durante a versão lançada um mês atrás. Quero identificar em qual commit o bug foi introduzido, mas há mais de 100 commits e é impossível fazer isso manualmente!&lt;/p>
&lt;h3 id="solução-identificação-de-bugs-usando-busca-binária">Solução: Identificação de bugs usando busca binária
&lt;/h3>&lt;p>O Git possui uma ferramenta embutida para encontrar o commit no qual um bug foi introduzido usando a busca binária matemática (Binary Search). A complexidade computacional é $\mathcal{O}(\log N)$, portanto, mesmo que você tenha 1000 commits, você pode identificá-lo em cerca de 10 testes.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Inicie a busca&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect start
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># O commit atual tem o bug (bad)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect bad
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1 mês atrás (por exemplo, o hash a1b2c3d) estava normal (good)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect good a1b2c3d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># O Git automaticamente verificará o commit intermediário, então execute os testes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Se o teste for bem-sucedido:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect good
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Se o teste falhar:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect bad
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Repetindo isso, o Git informará com precisão &amp;ldquo;Este é o primeiro commit Bad&amp;rdquo;. Ao terminar, reverta ao estado original com &lt;code>$ git bisect reset&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="11-a-rede-de-segurança-definitiva-git-reflog">11. A rede de segurança definitiva: &lt;code>git reflog&lt;/code>
&lt;/h2>&lt;p>O trunfo final contra qualquer &amp;ldquo;deslize&amp;rdquo; no Git é o &lt;code>git reflog&lt;/code>. O Git registra todo o histórico de operações locais (histórico de movimentos do HEAD) por um determinado período de tempo. Mesmo que você exclua uma branch ou faça um reset incorreto, você pode recuperar a situação encontrando o hash antigo com &lt;code>git reflog&lt;/code> e executando &lt;code>git reset --hard&lt;/code> para ele.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ git reflog
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">9f8a7b6 &lt;span class="o">(&lt;/span>HEAD -&amp;gt; main&lt;span class="o">)&lt;/span> HEAD@&lt;span class="o">{&lt;/span>0&lt;span class="o">}&lt;/span>: commit: Add new feature
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1a2b3c4 HEAD@&lt;span class="o">{&lt;/span>1&lt;span class="o">}&lt;/span>: reset: moving to HEAD~1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="12-conclusão">12. Conclusão
&lt;/h2>&lt;p>Explicamos detalhadamente os erros comuns de iniciantes no Git, os mecanismos do Git por trás deles e suas soluções. Fazer commit na branch errada, desfazer commits já enviados (pushed), utilizar o Stash, sobreviver ao Detached HEAD e resolver conflitos. O mais importante em tudo isso é imaginar &amp;ldquo;que objetos e ponteiros o Git está manipulando nos bastidores&amp;rdquo;.&lt;/p>
&lt;p>As diferenças dos arquivos são calculadas por algoritmos Diff rigorosos expressos em fórmulas matemáticas, e a consistência histórica é garantida por funções hash criptográficas. Se você entender essa bela filosofia de design, descobrirá que o Git não é de forma alguma uma &amp;ldquo;caixa preta indescritível&amp;rdquo;, mas sim o escudo mais forte para proteger seu código-fonte.&lt;/p>
&lt;p>Na próxima vez que você pensar &amp;ldquo;Fiz besteira!&amp;rdquo;, não se apresse em fechar o terminal; respire fundo e digite &lt;code>git status&lt;/code>. O Git sempre fornecerá dicas de recuperação.&lt;/p></description></item></channel></rss>