Como desfazer commits e alterações
Nesta seção, vamos discutir as estratégias e comandos "desfazer" do Git disponíveis. Em primeiro lugar, é importante observar que o Git não tem um sistema tradicional de "desfazer", como aqueles encontrados em aplicativos de processamento de palavras. Vai ser vantajoso não mapear operações do Git para nenhum modelo mental tradicional de "desfazer". Além do mais, o Git tem sua própria nomenclatura para operações "desfazer", que é melhor aproveitar em uma discussão. Esta nomenclatura inclui termos como redefinir, reverter, verificar, limpar, etc.
Uma metáfora engraçada é pensar no Git como um utilitário de gerenciamento de cronograma. Os commits são capturas instantâneas de um ponto no tempo ou pontos de interesse ao longo do cronograma do histórico de um projeto. Além desse recurso, vários cronogramas podem ser gerenciados por meio do uso de ramificações. Ao "desfazer" no Git, você, em geral, está voltando no tempo ou para outro cronograma em que os erros não aconteceram.
Este tutorial oferece todas as habilidades necessárias para trabalhar com revisões anteriores de um projeto de software. Primeiro, ele mostra como explorar commits antigos e, em seguida, explica a diferença entre a reversão de commits públicos no histórico do projeto vs. a redefinição de alterações não publicadas em sua máquina local.
Como encontrar o que está perdido: como revisar confirmações antigas
A ideia por trás de qualquer sistema de controle de versão é armazenar cópias "seguras" de um projeto para que você nunca precise se preocupar com quebras irreparáveis do seu código base. Depois que você tiver construído um histórico de projeto de commits, você pode revisar e revisitar qualquer commit do histórico. Um dos melhores recursos para revisar o histórico de um repositório do Git é o comando git log
. No exemplo abaixo, é possível usar git log para levar uma lista dos commits mais recentes a uma biblioteca de gráficos de código aberto popular.
git log --oneline
e2f9a78fe Replaced FlyControls with OrbitControls
d35ce0178 Editor: Shortcuts panel Safari support.
9dbe8d0cf Editor: Sidebar.Controls to Sidebar.Settings.Shortcuts. Clean up.
05c5288fc Merge pull request #12612 from TyLindberg/editor-controls-panel
0d8b6e74b Merge pull request #12805 from harto/patch-1
23b20c22e Merge pull request #12801 from gam0022/improve-raymarching-example-v2
fe78029f1 Fix typo in documentation
7ce43c448 Merge pull request #12794 from WestLangley/dev-x
17452bb93 Merge pull request #12778 from OndrejSpanel/unitTestFixes
b5c1b5c70 Merge pull request #12799 from dhritzkiv/patch-21
1b48ff4d2 Updated builds.
88adbcdf6 WebVRManager: Clean up.
2720fbb08 Merge pull request #12803 from dmarcos/parentPoseObject
9ed629301 Check parent of poseObject instead of camera
219f3eb13 Update GLTFLoader.js
15f13bb3c Update GLTFLoader.js
6d9c22a3b Update uniforms only when onWindowResize
881b25b58 Update ProjectionMatrix on change aspect
Material relacionado
Folha de consulta do Git
VER SOLUÇÃO
Aprenda a usar o Git com o Bitbucket Cloud
Cada commit tem um hash de identificação exclusivo SHA-1. Esses IDs são usados para percorrer o cronograma que já passou por commit e revisitar commits. Por padrão, git log
vai mostrar apenas os commits para a ramificação selecionada no momento. É possível que o commit que você está procurando esteja em outra ramificação. Você pode ver todos os commits em todas as ramificações executando git log --branches=*
. O comando git branch é usado para conferir e visitar outras ramificações. Ao invocar o comando, git branch -a
vai retornar uma lista de todos os nomes conhecidos de ramificações. Um desses nomes de ramificações pode, então, ser registrado usando git log
.
Quando encontrar uma referência de commit ao ponto no histórico que quer visitar, use o comando git checkout
para visitar esse commit. Git checkout
é uma maneira fácil de “carregar” as capturas instantâneas salvas na máquina de desenvolvimento. Durante o curso normal de desenvolvimento, HEAD
em geral aponta para a ramificação main
ou para outra ramificação local, mas, quando você consulta um commit anterior, HEAD
não aponta mais para uma ramificação — ele aponta direto para um commit. Esse estado é chamado de "HEAD
desconectado" e pode ser visualizado como a seguir:
Fazer check out de um arquivo antigo não muda de lugar o indicador HEAD
. Ele permanece na mesma ramificação e no mesmo commit, evitando um estado "head desvinculado". Você pode, então, dar commit na versão antiga do arquivo em um novo instantâneo, como faria com qualquer outra mudança. Então, na verdade, o uso do git checkout
em um arquivo serve como uma forma de reverter a uma versão antiga de um arquivo individual. Para mais informações sobre esses dois modos, visite a página git checkout
Como visualizar uma revisão antiga
Este exemplo supõe que você começou a desenvolver um experimento maluco, mas você não tem certeza se quer mantê-lo ou não. Para ajudá-lo a decidir, você quer dar uma olhada no estado do projeto antes de começar o experimento. Primeiro, é necessário encontrar o ID da revisão que você quer ver.
git log --oneline
Digamos que o histórico do seu projeto seja parecido com o seguinte:
b7119f2 Continue doing crazy things
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Você pode usar git checkout
para ver o commit “Make some import changes to hello.txt” da seguinte forma:
git checkout a1e8fb5
Isso faz com que seu diretório ativo corresponda ao estado exato do commit a1e8fb5
. Você pode procurar arquivos, compilar o projeto, realizar testes e, até mesmo, editar arquivos sem se preocupar em perder o estado atual do projeto. Nada que você fizer aqui vai ser salvo no seu repositório. Para continuar o desenvolvimento, é necessário voltar para o estado “atual” do projeto:
git checkout main
Fica pressuposto que você está desenvolvendo na ramificação main
padrão. Depois que voltar à ramificação main
, você pode usar git revert ou git reset para desfazer alterações que quiser.
Como desfazer uma captura instantânea confirmada
Existem, tecnicamente, várias estratégias diferentes para "desfazer" um commit. Os exemplos a seguir pressupõem que temos um histórico de commit que se parece assim:
git log --oneline
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
A gente vai se concentrar em desfazer o commit 872fa7e Try something crazy
. Talvez as coisas tenham ficado um pouco loucas demais.
Como desfazer uma confirmação com git checkout
Utilizando o comando git checkout
, podemos dar checkout no commit anterior, a1e8fb5
, colocando o repositório em um estado antes do commit louco acontecer. Ao dar checkout em um commit específico, você colocará o repo em um estado "HEAD desvinculado". Isso quer dizer que você não está mais trabalhando em nenhuma ramificação. Em um estado desvinculado, qualquer novo commit feito ficará órfão quando você mudar ramificações de volta a uma ramificação estabelecida. Commits órfãos serão excluídos pelo coletor de lixo do Git. O coletor de lixo executa em um intervalo configurado e destrói permanentemente commits órfãos. Para evitar que commits órfãos sejam coletados como lixo, precisamos garantir que estamos em uma ramificação.
No estado HEAD desconectado, a gente pode executar git checkout -b new_branch_without_crazy_commit
. Assim, uma nova ramificação denominada new_branch_without_crazy_commit
vai ser criada e alterada para esse estado. O repositório, agora, está em um novo cronograma do histórico em que o commit 872fa7e
não existe mais. Você pode continuar trabalhando nessa nova ramificação em que o commit 872fa7e
não existe mais e considerar o commit como "desfeito". Se você precisar da ramificação anterior e ela for a main
, essa estratégia de "desfazer" não é apropriada. Confira com a gente algumas outras estratégias sobre como "desfazer". Para mais informações e exemplos, confira a discussão aprofundada sobre git checkout.
Como desfazer uma confirmação pública com git revert
Vamos supor que estejamos de volta ao nosso exemplo de histórico de commit original. O histórico que inclui o commit 872fa7e
. Desta vez, vamos tentar reverter um "desfazer". Se executarmos git revert HEAD
, o Git criará um novo commit com o inverso do último commit. Isso adiciona um novo commit ao histórico de ramificação atual e agora o faz parecer assim:
git log --oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Neste ponto, a gente tecnicamente "desfez" o commit 872fa7e
outra vez. Embora 872fa7e
ainda exista no histórico, o novo commit e2f9a78
é o inverso das mudanças em 872fa7e
. Ao contrário de nossa estratégia de checkout anterior, a gente pode continuar usando a mesma ramificação. Esta solução é uma anulação satisfatória. Este é o método ideal de 'anulação' para trabalhar com repositórios públicos compartilhados. Se você tiver requisitos para manter um histórico do Git curado e mínimo, essa estratégia pode não ser satisfatória.
Como desfazer uma confirmação com git reset
Seguindo essa estratégia para desfazer algo, a gente vai dar continuação ao exemplo de trabalho. O git reset é um comando extenso com vários usos e funções. Se executar o git reset --hard a1e8fb5
, o histórico de commit é redefinido para aquele commit específico. Ao examinar o histórico de commit com o git log
, o texto vai aparecer assim:
git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
A saída do log mostra que os commits e2f9a78
e 872fa7e
não existem mais no histórico de commits. Neste ponto, a gente pode continuar trabalhando e criando novos commits como se os commits "malucos" nunca tivessem acontecido. Este método de desfazer alterações tem o efeito mais limpo no histórico. Fazer uma redefinição é excelente para alterações locais, no entanto, ela adiciona complicações ao trabalhar com um repositório remoto compartilhado. Se a gente tiver um repositório remoto compartilhado que tenha o commit 872fa7e
enviado para ele e tentar executar git push
em uma ramificação em que o histórico foi redefinido, o Git vai lançar um erro. O Git vai supor que a ramificação que está sendo enviada não está atualizada por causa dos commits ausentes. Nesses cenários, git revert
deve ser o método 'desfazer' preferido.
Como desfazer a última confirmação
Na seção anterior, a gente falou sobre as diferentes estratégias para desfazer commits. Todas essas estratégias podem ser aplicadas ao commit mais recente também. Contudo, em alguns casos não é preciso remover ou redefinir o último commit. Talvez essa ação tenha sido prematura. Neste caso, você pode corrigir o commit mais recente. Depois de ter feito mais alterações no diretório de trabalho e ter preparado elas para o commit usando git add, você pode executar git commit --amend
. Assim o Git vai abrir o editor de sistema configurado e deixar você modificar a última mensagem de commit. As novas alterações vão ser adicionadas ao commit corrigido.
Como desfazer alterações não confirmadas
Antes que as alterações passem por commit no histórico do repositório, elas estão presentes no índice de staging e no diretório de trabalho. Talvez seja necessário desfazer alterações nessas duas áreas. O índice de staging e o diretório de trabalho são mecanismos de gerenciamento de estado do Git internos. Para saber mais informações sobre como esses dois mecanismos funcionam, visite a página git reset, que tem uma discussão aprofundada deles.
O diretório de trabalho
O diretório de trabalho em geral está em sincronia com o sistema de arquivos local. Para desfazer as alterações no diretório de trabalho, você pode editar arquivos como costuma fazer no seu editor favorito. O Git tem alguns utilitários que ajudam a gerenciar o diretório de trabalho. Há o comando git clean, que é um utilitário de conveniência para desfazer alterações no diretório de trabalho. Há também o git reset
, que pode ser invocado com as opções --mixed
ou --hard
, para aplicar uma redefinição ao diretório de trabalho.
O índice de staging
O comando git add é usado para adicionar alterações ao índice de staging. O principal uso do git reset
é para desfazer as alterações do índice de staging. Uma redefinição --mixed
vai mover qualquer alteração pendente do índice de staging de volta para o diretório de trabalho.
Como desfazer alterações públicas
Ao trabalhar em uma equipe com repositórios remotos, devem ser feitas considerações extras ao desfazer alterações. Git reset
deve ser considerado em geral como um método desfazer "local". Uma redefinição deve ser usada ao desfazer alterações para uma ramificação privada. É uma maneira segura de isolar a remoção de commits de outras ramificações que podem estar em uso por outros desenvolvedores. Surgem problemas quando uma redefinição é executada em uma ramificação compartilhada e essa ramificação é, então, enviada em contexto remoto com git push
. O Git vai bloquear o envio neste cenário alegando que a ramificação que está sendo enviada está desatualizada em relação à ramificação remota uma vez que há commits ausentes.
O melhor método para desfazer um histórico compartilhado é o git revert
. Um revert é mais seguro que um reset, pois não remove commits de um histórico compartilhado. Um revert manterá commits que você deseja desfazer e criará um novo commit que inverte o commit indesejado. Este método é mais seguro para colaboração remota compartilhada, pois um desenvolvedor remoto pode, então, fazer o pull da ramificação e receber o novo commit revert que desfaz o commit indesejado.
Resumo
A gente abordou muitas estratégias de alto nível para desfazer coisas no Git. É importante lembrar que há mais de uma maneira de "desfazer" em um projeto Git. Em geral, este artigo abordou tópicos complexos, que são explicados mais a fundo em páginas específicas dos comandos relevantes do Git. As ferramentas de "desfazer" mais usadas são git checkout, git revert e git reset. Alguns dos principais pontos a serem lembrados são:
- Uma vez que o commit tenha sido feito nas alterações, eles, geralmente, são permanentes
- Utilize
git checkout
para mudar de lugar e revisar o histórico de commit git revert
é a melhor ferramenta para desfazer alterações públicas compartilhadasgit reset
é usado melhor para desfazer alterações privadas locais
Além dos comandos de desfazer primários, foram observados outros recursos Git: git log para encontrar commits perdidos, git clean para desfazer alterações não confirmadas e git add para modificar o índice de staging.
Cada um desses comandos tem sua própria documentação detalhada. Para saber mais sobre um comando específico mencionado aqui, visite os links correspondentes.
Compartilhar este artigo
Próximo tópico
Leitura recomendada
Marque esses recursos para aprender sobre os tipos de equipes de DevOps ou para obter atualizações contínuas sobre DevOps na Atlassian.