O Guia Avançado do Git: Git Stash, Redefinir, Rebase e muito mais
Publicados: 2022-03-11Todo desenvolvedor deve ter uma boa compreensão do controle de versão, e o Git se tornou o padrão de fato para controle de versão no desenvolvimento de software.
Muitas vezes, porém, os desenvolvedores aprendem apenas alguns comandos simples e ignoram o poder do histórico do Git e outras coisas que o Git pode fazer para torná-lo muito mais eficiente. Por exemplo, gerenciar lançamentos é muito fácil com o Git usando git tag
.
Fiz um curso avançado de Git online (com Github) e dei aulas de Git para iniciantes em conjunto com o Github. Quando percebi que não havia muitos artigos técnicos sobre meus recursos favoritos do Git, aproveitei a chance de compartilhá-lo com meus colegas desenvolvedores. Neste post, você aprenderá como aproveitar as seguintes funções avançadas do Git:
-
git stash
, que faz um salvamento local temporário do seu código -
git reset
, que permite que você organize seu código antes de fazer um commit -
git bisect
, uma função que permite caçar commits ruins -
git squash
, que permite combinar seus commits -
git rebase
, que permite aplicar alterações de uma ramificação para outra
Git Stash
O Git stash permite que você salve seu código sem fazer um commit. Como isso é útil? Imagine o seguinte cenário:
Você já fez três commits limpos e organizados, mas também tem algum código não confirmado que é bastante confuso; você não vai querer comitá-lo sem antes remover seu código de depuração. Então, por algum motivo, de repente você precisa atender a outra tarefa e precisa trocar de ramal. Isso geralmente pode acontecer se você estiver em seu branch main
e se esquecer de criar um novo branch para seu recurso. No momento, seu código está assim:
$ git status On branch my-feature Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: css/common.scss no changes added to commit (use "git add" and/or "git commit -a")
$ git diff diff --git a/css/common.scss b/css/common.scss index 2090cc4..90fd457 100644 --- a/css/common.scss +++ b/css/common.scss @@ -13,6 +13,6 @@ body { font-family: "Proxima Nova", Arial, sans-serif; font-size: 13px; - color: #333; + color: red; background-color: #f00; }
Quando você executa git stash
, o código não confirmado desaparece sem ser confirmado. Stashing é como salvar um commit local temporário em seu branch. Não é possível enviar um stash para um repositório remoto, portanto, um stash é apenas para seu uso pessoal.
$ git stash Saved working directory and index state WIP on my-feature: 49ee696 Change text color
Seu branch agora aparece como estava quando você fez seu último commit. Agora, você pode alterar as ramificações com segurança sem perder seu código ou ter um commit confuso. Quando você voltar para sua ramificação e executar git stash list
, você verá uma lista de stashes que se parece com isso:
$ git stash list stash@{0}: WIP on my-feature: 49ee696 Change text color
Você pode reaplicar facilmente o conteúdo armazenado executando git stash apply
. Você também pode aplicar um stash específico (se tiver stash mais de uma vez) executando git stash apply stash@{1}
(o '1' denota o segundo antes do último stash). Aqui está um exemplo de stash de mais de um commit e aplicação de um stash diferente:
$ git diff diff --git a/css/common.scss b/css/common.scss index 2090cc4..90fd457 100644 --- a/css/common.scss +++ b/css/common.scss @@ -13,6 +13,6 @@ body { font-family: "Proxima Nova", Arial, sans-serif; font-size: 13px; - color: #333; + color: red; background-color: #f00; } $ git stash Saved working directory and index state WIP on my-feature: 49ee696 Change text color $ git diff diff --git a/css/common.scss b/css/common.scss index 2090cc4..b63c664 100644 --- a/css/common.scss +++ b/css/common.scss @@ -13,6 +13,6 @@ body { font-family: "Proxima Nova", Arial, sans-serif; font-size: 13px; - color: #333; + color: red; background-color: #f00; } $ git stash Saved working directory and index state WIP on my-feature: 49ee696 Change text color
$ git stash list stash@{0}: WIP on my-feature: 49ee696 Change text color stash@{1}: WIP on my-feature: 49ee696 Change text color stash@{2}: WIP on my-feature: 49ee696 Change text color $ git stash apply stash@{2} On branch my-feature Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: css/common.scss no changes added to commit (use "git add" and/or "git commit -a")
git stash apply stash@{2}
aplicou o código stash mais antigo, quando alteramos a cor do texto para vermelho.
$ git diff diff --git a/css/common.scss b/css/common.scss index 2090cc4..90fd457 100644 --- a/css/common.scss +++ b/css/common.scss @@ -13,6 +13,6 @@ body { font-family: "Proxima Nova", Arial, sans-serif; font-size: 13px; - color: #333; + color: red; background-color: #f00; }
Se você decidir não confirmar seu trabalho depois de restaurar o stash, poderá executar git checkout .
, que redefine todo o código não confirmado.
Como outro exemplo de como usar o Git stash: digamos que você tenha alguns arquivos novos, um dos quais tem um bug. Deixe todos, exceto o arquivo de bug suspeito, sem preparação (o código deve ser preparado para ser armazenado), então você pode armazenar esse arquivo e solucionar o problema. Se o arquivo stash não foi o problema, você pode restaurar o stash.
$ git status On branch my-feature Untracked files: (use "git add <file>..." to include in what will be committed) css/colors.scss nothing added to commit but untracked files present (use "git add" to track)
$ git add css/colors.scss $ git stash Saved working directory and index state WIP on my-feature: 0d8deef delete colors $ git status On branch my-feature nothing to commit, working tree clean $ git stash apply stash@{0} On branch my-feature Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: css/colors.scss
Você também pode transferir seus commits stash para uma nova ramificação de recurso ou ramificação de depuração usando git stash branch
:
$ git status On branch my-feature Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: css/common.scss no changes added to commit (use "git add" and/or "git commit -a") $ git stash Saved working directory and index state WIP on my-feature: 66f3f3b Add colors file $ git stash branch debugging-branch M css/common.scss Switched to a new branch 'debugging-branch' Unstaged changes after reset: M css/common.scss On branch debugging-branch Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: css/common.scss Dropped refs/stash@{0} (d140624f60d8deef7bceb0d11fc80ed4fd47e0a1)
Observe que quando você aplica um stash, o stash não é excluído. Você pode remover stashes individualmente usando git drop
, ou remover todos os stashes usando git stash clear
:
$ git stash list stash@{0}: WIP on my-feature: 66f3f3b Add colors file stash@{1}: WIP on my-feature: 0d8deef delete colors stash@{2}: WIP on my-feature: 49ee696 Change text color $ git stash drop stash@{2} Dropped stash@{2} (8ed6d2ce101aa2e28c8ccdc94cb12df8e5c468d6) $ git stash list stash@{0}: WIP on my-feature: 66f3f3b Add colors file stash@{1}: WIP on my-feature: 0d8deef delete colors $ git stash clear $ git stash list $
Redefinir Git
Se você se encontrar na situação em que acidentalmente cometeu algum código confuso, você pode fazer uma reinicialização “soft”. Isso significa que o código aparece como se ainda não tivesse sido confirmado. Então você pode organizar seu código em seu IDE antes de fazer um commit mais limpo. Para fazer isso, você pode executar git reset --soft HEAD~1
. Isso irá redefinir o commit mais recente. Você pode redefinir mais de um commit alterando o número após ~
por exemplo git reset --soft HEAD~2
.
$ git reset --soft HEAD~1 $ git status On branch debugging-branch Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: css/common.scss Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: css/common.scss
$ git diff diff --git a/css/common.scss b/css/common.scss index 2090cc4..90fd457 100644 --- a/css/common.scss +++ b/css/common.scss @@ -13,6 +13,6 @@ body { font-family: "Proxima Nova", Arial, sans-serif; font-size: 13px; - color: $grey; + color: red; background-color: #f00; }
A redefinição do Git é um pouco mais confusa, especialmente ao ensinar novos usuários do Git. Um soft reset deve ser reservado para um erro genuíno, enquanto um stash pode ser usado para trocar o código de entrada e saída.
Você também pode executar um hard reset ( git reset --hard HEAD~1
). Esse tipo de reset basicamente apaga seu último commit. Você deve ter muito cuidado ao realizar reinicializações forçadas, especialmente se você enviar seu branch, pois não há como restaurar seu commit.
Git Bisect
Minha ferramenta Git favorita é git bisect
. Eu só precisei um punhado de vezes, mas quando precisei, foi inestimável! Eu o usei principalmente em grandes bases de código onde havia um problema para o qual ninguém encontrou a causa raiz, mesmo após uma depuração vigorosa.
git bisect
essencialmente executa uma pesquisa binária entre dois commits fornecidos e, em seguida, apresenta os detalhes de um commit específico. Você primeiro precisa dar ao Git um bom commit, onde você sabe que sua funcionalidade estava funcionando, e um commit ruim. Observe que, contanto que você tenha um commit bom e um ruim, os commits podem ter anos de diferença (embora quanto mais você retroceder no tempo, mais difícil se torna!).
A coisa mais divertida sobre o git bisect
é que você normalmente não sabe quem escreveu o commit do bug quando você começa. A emoção de descobrir onde o bug foi introduzido mais de uma vez fez com que alguns colegas de trabalho se amontoassem em volta do meu computador!
Para começar, dê uma olhada no branch buggy e encontre os bons commits. Você precisará passar pelo seu histórico de commits e encontrar o hash do commit, então verificar esse commit específico e testar seu branch. Depois de encontrar um local bom e ruim para trabalhar, você pode executar um git bisect
.
Nesse cenário, o texto é vermelho neste site que criamos (embora possa usar um designer de interface do usuário), mas não sabemos como ou quando foi feito em vermelho. Este é um exemplo muito simples, em um cenário da vida real você provavelmente teria um problema muito menos óbvio, por exemplo, um formulário não sendo enviado/funcionando.
Quando executamos um git log
, podemos ver a lista de commits para escolher.
$ git log commit a3cfe7f935c8ad2a2c371147b4e6dcd1a3479a22 (HEAD -> main) Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:52:57 2021 +0100 Update .gitignore file for .DS_Store commit 246e90977790967f54e878a8553332f48fae6edc Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:51:23 2021 +0100 Change styling of page commit d647ac489ad43b3c6eaea5aceb02b0a7d7e5cf8e Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:50:48 2021 +0100 Change text color commit 032a41136b6653fb9f7d81aef573aed0dac3dfe9 Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:42:57 2021 +0100 Change text color commit 246e90977790967f54e878a8553332f48fae6edc Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:41:23 2021 +0100 delete colors commit d647ac489ad43b3c6eaea5aceb02b0a7d7e5cf8e Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:50:48 2021 +0100 Change text color commit ce861e4c6989a118aade031020fd936bd28d535b Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:07:36 2021 +0100 ...
Se eu abrir minha página da Web no hash de confirmação mais recente, o texto ficará vermelho, então eu sei que tenho um problema.
Agora começamos o bisect e dizemos ao Git que temos um commit ruim.
$ git bisect start $ git bisect bad 8d4615b9a963ef235c2a7eef9103d3b3544f4ee1
Agora voltamos no tempo para tentar encontrar um commit onde o texto não estava vermelho. Aqui eu tento verificar meu primeiro commit…
$ git checkout ce861e4c6989a118aade031020fd936bd28d535b Note: checking out 'ce861e4c6989a118aade031020fd936bd28d535b'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at ce861e4 Add CSS styles
…e atualizando a página da web…
O texto não está mais vermelho, então este é um bom commit! Quanto mais recente o commit for, quanto mais próximo do commit ruim, melhor:
$ git checkout d647ac489ad43b3c6eaea5aceb02b0a7d7e5cf8e Previous HEAD position was ce861e4c6989a118aade031020fd936bd28d535b Add CSS styles HEAD is now at d647ac4 Change text color
O Git agora lhe dirá quantos commits ele precisa pesquisar antes de encontrar o correto. O número de commits que o Git percorrerá depende de quantos commits estão entre o commit bom e o ruim (quanto maior o tempo, mais vezes o Git precisa iterar).
Agora, você precisará testar sua ramificação novamente e ver se o problema desapareceu. Às vezes, isso pode ser um pouco complicado se você atualizar módulos regularmente, pois pode ser necessário reinstalar módulos de nó em seu repositório front-end. Se houver atualizações do banco de dados, talvez seja necessário atualizá-las.
git bisect
verifica automaticamente um commit no meio de seus commits bons e ruins. Aqui está estimando um passo para encontrar o commit incorreto.
$ git bisect good 1cdbd113cad2f452290731e202d6a22a175af7f5 Bisecting: 1 revision left to test after this (roughly 1 step) [ce861e4c6989a118aade031020fd936bd28d535b] Add CSS styles $ git status HEAD detached at ce861e4 You are currently bisecting, started from branch '8d4615b'. (use "git bisect reset" to get back to the original branch)
Atualize a página e veja se o problema desapareceu. O problema ainda está lá, então dizemos ao Git que este ainda é um commit ruim. Não há necessidade de referenciar o hash do commit desta vez, pois o Git usará o commit que você fez check-out. Precisaremos repetir esse processo até que o Git tenha percorrido todas as etapas possíveis.
$ git bisect bad Bisecting: 0 revisions left to test after this (roughly 0 steps) [cbf1b9a1be984a9f61b79ae5f23b19f66d533537] Add second paragraph to page
Atualize a página e nosso problema desapareceu novamente, então este é um bom commit:

Neste estágio o Git encontrou o primeiro commit incorreto:
$ git bisect good ce861e4c6989a118aade031020fd936bd28d535b is the first bad commit commit ce861e4c6989a118aade031020fd936bd28d535b Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:52:57 2021 +0100 Add CSS styles :000000 100644 0000000000000000000000000000000000000000 092bfb9bdf74dd8cfd22e812151281ee9aa6f01a M css
Agora podemos usar git show
para mostrar o próprio commit e identificar o problema:
$ git show ce861e4c6989a118aade031020fd936bd28d535b commit ce861e4c6989a118aade031020fd936bd28d535b Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:52:57 2021 +0100 Add CSS styles diff --git a/css/base.scss b/css/base.scss index e69de29..26abf0f 100644 --- a/css/base.scss +++ b/css/base.scss @@ -1,7 +1,7 @@ body { background-color: $white; margin: 0px; line-height: 20px; - color: $grey; + color: red; }
Quando terminar, você pode executar git bisect reset
para redefinir sua ramificação para seu estado normal de trabalho.
Quanto mais próximos os commits estiverem juntos, mais fácil o Git poderá encontrar o problema, mas eu já fiz 10 passos antes e ainda encontrei o commit incorreto facilmente. Não é garantido que funcione, mas encontrou o problema na maioria das vezes para mim. Parabéns, agora você é um arqueólogo de código!
Esmagando seus commits
Anteriormente, trabalhei em tempo integral em um projeto de código aberto para uma organização global e rapidamente aprendi o quão importante é esmagar – ou combinar – seus commits. Acho que é um excelente hábito para adquirir, mesmo que seu empregador não o exija. É especialmente atencioso para outros desenvolvedores que precisarão revisar e editar recursos que você criou posteriormente.
Por que esmagar seus commits?
- É mais fácil para os contribuidores do seu repositório lerem. Imagine se você tiver uma lista de commits assim:
- Implementar controle deslizante de carrossel
- Adicionar estilo ao carrossel
- Adicionar botões ao carrossel
- Corrigir problema estranho no IE com carrossel
- Ajustar margens no carrossel
É muito mais fácil comprimi-los em um único commit que diz “Adicionar carrossel à página inicial”.
- Ele encoraja você a manter suas mensagens de commit compreensíveis e relevantes se toda vez que você fizer um pull request, você tiver que compactar seus commits em um. Quantas vezes você viu um commit intitulado “WIP”, “correção de bug para página de login” ou “corrigir erro de digitação”? É importante ter nomes de commit relevantes, por exemplo, “Correção de bug para a página de login #444 - correção de oscilação devido à falta da função $scope”.
Uma razão pela qual você pode não querer esmagar seus commits pode ser porque você está trabalhando em um recurso muito detalhado e longo e deseja manter um histórico diário para si mesmo, caso encontre bugs mais tarde. Então seu recurso é mais fácil de depurar. No entanto, ao verificar seu recurso em seu branch principal e você estiver confiante de que está livre de bugs, ainda faz sentido squash.
Nesse cenário, fiz cinco commits, mas todos estão relacionados a um recurso. Minhas mensagens de commit também estão intimamente relacionadas ao mérito de serem separadas - todos os meus commits são sobre o estilo da página para este novo recurso:
$ git log commit a8fbb81d984a11adc3f72ce27dd0c39ad24403b7 (HEAD -> main) Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 11:16:10 2021 +0100 Import colors commit e2b3ddd5e8b2cb1e61f88350d8571df51d43bee6 Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 11:15:32 2021 +0100 Add new color commit d647ac489ad43b3c6eaea5aceb02b0a7d7e5cf8e Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 10:50:48 2021 +0100 Change text color commit c005d9ceeefd4a8d4e553e825fa40aaafdac446e Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 09:59:57 2021 +0100 Add CSS styles commit 9e046b7df59cef07820cc90f694fabc666731bd2 Author: Ursula Clarke <[email protected]> Date: Tue Jan 11 09:56:28 2021 +0100 Add second paragraph to page commit 5aff973577d67393d914834e8af4c5d07248d628 Author: Ursula Clarke <[email protected]> Date: Mon Jan 10 16:04:22 2021 +0100 Add colors CSS file and edit background color
Você também pode usar git merge --squash
, mas acho que é mais claro usar rebase
porque quando você escolhe seus commits é mais fácil ver a descrição do commit. Se você executar um git merge --squash
, primeiro terá que fazer um hard reset de seus commits ( git reset --hard HEAD~1
), e é fácil ficar confuso com exatamente com quantos commits você precisa fazer isso. Acho o git rebase
mais visual.
Comece executando git rebase -i --root
e seu editor de texto padrão na linha de comando será aberto com sua lista de commits:
pick eb1eb3c Update homepage pick 5aff973 Add colors CSS file and edit background color pick 9e046b7 Add second paragraph to page pick c005d9c Add CSS styles pick d647ac4 Change text color pick e2b3ddd Add new color pick a8fbb81 Import colors # Rebase a8fbb81 onto b862ff2 (7 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
Você pode querer apenas esmagar seus últimos commits, nesse caso você pode executar git rebase -i HEAD~3
e ser apresentado com seus últimos três commits:
pick eb1eb3c Update homepage pick 5aff973 Add colors CSS file and edit background color pick 9e046b7 Add second paragraph to page # Rebase b862ff2..9e046b7 onto b862ff2 (3 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
Agora podemos compactar todos os commits no primeiro commit, como mostrado abaixo.
pick eb1eb3c Update homepage squash 5aff973 Add colors CSS file and edit background color squash 9e046b7 Add second paragraph to page # Rebase b862ff2..9e046b7 onto b862ff2 (3 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
Quando você salvar o arquivo, o Git abrirá sua mensagem de commit para editar.
# This is a combination of 3 commits. # This is the 1st commit message: Update homepage # This is the commit message #2: Add colors CSS file and edit background color # This is the commit message #3: Add second paragraph to page # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # Date: Wed Jan 13 18:31:28 2021 +0100 # # interactive rebase in progress; onto b862ff2 # Last commands done (3 commands done): # squash 5aff973 Add colors CSS file and edit background color # squash 9e046b7 Add second paragraph to page # No commands remaining. # You are currently rebasing branch 'main' on 'b862ff2'. # # Changes to be committed: # new file: .gitignore # new file: css/base.css # new file: css/base.scss # new file: css/colors.css # new file: css/colors.css.map # new file: css/colors.scss # new file: css/common.css # new file: css/common.scss # new file: index.html #
Enquanto estamos fazendo o rebase, também podemos editar a descrição do commit para que seja mais fácil de ler.
Implement new design for homepage. Add .gitignore file for Sass folder. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. #
Salve este arquivo novamente e pronto! Quando damos outra olhada no log do Git, podemos ver que há apenas um commit limpo.
[detached HEAD 574ec7e] Implement new design for homepage. Add .gitignore file for Sass folder. Date: Wed Jan 13 18:31:28 2021 +0100 10 files changed, 215 insertions(+) create mode 100644 .gitignore create mode 100644 css/base.css create mode 100644 css/base.scss create mode 100644 css/colors.css create mode 100644 css/colors.css.map create mode 100644 css/colors.scss create mode 100644 css/common.css create mode 100644 css/common.scss create mode 100644 index.html create mode 100644 verylargefile.txt Successfully rebased and updated refs/heads/main. $ git log commit 574ec7e5d7d7a96427e049cad9806cdef724aedd (HEAD -> main) Author: Ursula Clarke <[email protected]> Date: Wed Jan 13 18:31:28 2021 +0100 Implement new design for homepage. Add .gitignore file for Sass folder.
Git Rebase
Os desenvolvedores geralmente hesitam em usar o git rebase
porque sabem que um rebase pode ser usado para excluir permanentemente arquivos de sua base de código.
Como vimos acima, o git rebase
pode ser usado para manter seu código e arrumá-lo, bem como excluí-lo - mas e se você realmente quiser remover permanentemente um arquivo do histórico?
Certa vez, testemunhei um cenário em que um membro de nossa equipe de desenvolvimento acidentalmente submeteu um arquivo muito grande à base de código. Era parte de uma ramificação muito maior, então o arquivo grande passou despercebido na revisão de código e foi registrado por engano na ramificação principal. Isso se tornou um problema sempre que alguém queria clonar novamente o repositório - levava muito tempo para fazer o download! E, claro, o arquivo em questão era desnecessário. Não teria sido um problema se o arquivo fosse o último commit para o branch principal - nesse caso você poderia simplesmente executar um hard reset ( git reset --hard HEAD~1
) e forçar o push do branch.
Da mesma forma, se o arquivo fosse a única alteração em um determinado commit, você poderia remover o commit inteiro executando git reset --hard <commit-id>
. Em nosso cenário, porém, o arquivo grande foi confirmado junto com outro código que queríamos manter no histórico, como o penúltimo commit.
Depois de encontrar o commit problemático, verifique-o usando o git checkout
e o hash do commit:
$ git checkout ce861e4c6989a118aade031020fd936bd28d535b Note: checking out 'ce861e4c6989a118aade031020fd936bd28d535b'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at ce861e4 Add CSS styles
Remova o arquivo ou edite seu código e deixe o código (ou arquivos) que deseja manter intacto.
$ rm verylargefile.txt $ git status HEAD detached at ce861e4 Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: verylargefile.txt no changes added to commit (use "git add" and/or "git commit -a")
Certifique-se de executar git add -A
para que seu arquivo excluído seja preparado e o Git saiba como removê-lo. Agora execute git commit --amend -v
e o Git solicitará que você edite sua mensagem de commit.
Depois disso, execute git rebase --onto HEAD <commit-id> main
. É aqui que você pode encontrar alguns conflitos de mesclagem, o que significa que há um conflito entre seu novo commit e o código antigo. O Git solicitará que você resolva o conflito:
$ git add -A $ git status HEAD detached at ce861e4 Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: verylargefile.txt $ git commit --amend -v [detached HEAD 7c9516a] Add CSS styles Date: Thu Jan 14 14:43:54 2021 +0100 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 css/common.css.map delete mode 100644 verylargefile.txt $ git status HEAD detached from ce861e4 nothing to commit, working tree clean $ git rebase --onto HEAD ce861e4 First, rewinding head to replay your work on top of it... Fast-forwarded HEAD to HEAD.
Se você abrir o arquivo em seu editor de texto, verá que o Git marcou duas versões do arquivo de índice. Você simplesmente precisa remover um ou editar um para manter as alterações desejadas.
<p> Toptal was created by engineers. We are entrepreneurs, all passionate about working with top tech talent and exciting companies from all over the world. </p> <<<<<<< HEAD <p> Toptal connects the top 3% of freelance talent all over the world. </p> </main> </body> </html> ======= </main> </body> </html> >>>>>>> Add index file
O código entre <<<<<<< HEAD
e a linha de sinais de igual é uma versão, e o código entre os sinais de igual e >>>>>>> Add index file
é a versão do commit “Adicionar arquivo de índice” . Então você pode ver que uma versão tem o parágrafo adicional de “Toptal conecta os 3% melhores talentos freelance em todo o mundo”, enquanto a outra não.
Salve seu arquivo editado e execute git add filename
seguido por git rebase --continue
. Se não houver alterações, você também pode executar git rebase --skip
. Pode demorar um pouco para passar pelo rebase se houver muitos commits entre seu commit de “arquivo grande” e o commit mais recente no main.
Seja paciente e, se você estiver em uma equipe grande, procure uma segunda opinião! É especialmente importante consultar a(s) pessoa(s) que escreveu(m) o(s) commit(s) que você está mesclando, se possível.
Lembre-se de que as alterações de mesclagem são relevantes para o commit específico no histórico, e não para as alterações mais atualizadas. Ou seja, se você estiver editando um commit de quando o texto em seu site era Arial, e agora é Verdana, você ainda deve manter esse commit com o histórico de Arial como fonte.
Observe também que se o Git vir um espaço ou um caractere de fim de linha, isso pode causar um conflito de mesclagem, portanto, tenha cuidado!
Mais do que apenas comprometer e puxar
Git é mais poderoso do que muitos desenvolvedores pensam. Se você estiver apresentando um novato, certifique-se de dar algumas dicas sobre esses recursos inestimáveis. Isso torna o fluxo de trabalho mais eficiente.
Quer saber mais sobre o Git? Dê uma olhada na página Git Tips and Practices da Toptal.