Undoing changes

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 um aplicativo de processamento de palavras. Vai ser vantajoso não mapear operações do Git para nenhum modelo mental tradicional de 'desfazer'. Além disso, 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. As confirmações 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 disso, vários cronogramas podem ser gerenciados através do uso de ramificações. Ao 'desfazer' no Git, você, geralmente, está voltando no tempo ou para outro cronograma em que os erros não aconteceram.

Este tutorial fornece todas as habilidades necessárias para trabalhar com revisões anteriores de um projeto de software. Primeiro, ele mostra como explorar confirmações antigas e, em seguida, explica a diferença entre a reversão de confirmações públicas 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 tenha que se preocupar com a quebra irreparável de sua base de código. Depois de construir o histórico de confirmações de um projeto, você pode revisar e revisitar qualquer confirmação no histórico. Uma das melhores utilidades para revisar o histórico de um repositório do Git é o comando git log. No exemplo abaixo, usamos git log para obter uma lista das confirmações mais recentes para uma biblioteca de gráficos de software 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

Cada confirmação tem um hash de identificação exclusivo SHA-1. Esses IDs são usados para percorrer o cronograma confirmado e revisitar confirmações. Por padrão, git log vai mostrar apenas as confirmações para a ramificação selecionada atualmente. É totalmente possível que a confirmação que você está procurando esteja em outra ramificação. Você pode ver todas as confirmações em todas as ramificações executando git log --branches=*. O comando git branch é usado para ver e visitar outras ramificações. Ao chamar 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 <branch_name>.

Quando encontrar uma referência de confirmação ao ponto no histórico que quer visitar, você pode utilizar o comando git checkout para visitar essa confirmação. Git checkout é uma maneira fácil de “carregar” qualquer uma dessas capturas instantâneas salvas na máquina de desenvolvimento. Durante o curso normal de desenvolvimento, HEAD geralmente aponta para mestre ou para alguma outra ramificação local, mas quando você verifica uma confirmação anterior, HEAD não aponta mais para uma ramificação—ele aponta diretamente para uma confirmação. Isso é chamado de estado “HEAD desanexado” e pode ser visualizado da seguinte maneira:

Git Tutorial: Checking out a previous commit

Verificar um arquivo antigo não move o indicador HEAD. Ele permanece na mesma ramificação e na mesma confirmação, evitando um estado 'head desanexado'. Você pode, então, confirmar a versão antiga do arquivo em uma nova captura instantânea como faria com qualquer outra alteração. Então, com efeito, este uso de git checkout em um arquivo serve como uma forma de voltar para uma versão antiga de um arquivo individual. Para obter 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 fazendo coisas malucas
872fa7e Tente algo maluco
a1e8fb5 Faça algumas alterações importantes em hello.txt
435b61d Crie hello.txt
9773e52 Importação inicial

Você pode usar git checkout para ver a confirmação “Fazer algumas alterações de importação em hello.txt” como segue:

git checkout a1e8fb5

Isso faz com que seu diretório ativo corresponda ao estado exato da confirmação 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ê faça aqui será salvo no seu repositório. Para continuar o desenvolvimento, é necessário voltar para o estado “atual” do projeto:

git checkout master

Isso supõe que você esteja desenvolvendo na ramificação mestre padrão. Depois que estiver de volta na ramificação mestre, você pode usar git revert ou git reset para desfazer qualquer alteração indesejada.

Como desfazer uma captura instantânea confirmada

Há, tecnicamente, várias estratégias diferentes para 'desfazer' uma confirmação. Os exemplos a seguir supõem que nós temos um histórico de confirmação parecido com o seguinte:

git log --oneline
872fa7e Tente algo maluco
a1e8fb5 Faça algumas alterações importantes em hello.txt
435b61d Crie hello.txt
9773e52 Importação inicial

Vamos focar em desfazer a confirmação 872fa7e Tente algo maluco. Talvez as coisas fiquem um pouco malucas demais.

Como desfazer uma confirmação com git checkout

Usando o comando git checkout, podemos verificar a confirmação anterior, a1e8fb5, colocando o repositório em um estado antes de a confirmação maluca ter acontecido. Verificar uma confirmação específica vai pôr o repositório em um estado "HEAD desanexado". Isso significa que você não está mais trabalhando em nenhuma ramificação. Em um estado desanexado, qualquer confirmação nova que você faça ficará órfã quando você voltar as ramificações para uma ramificação estabelecida. As confirmações órfãs estão ativas para exclusão pelo coletor de lixo do Git. O coletor de lixo é executado em um intervalo configurado e destrói permanentemente as confirmações órfãs. Para evitar que as confirmações órfãs sejam pegas como lixo, precisamos garantir que estamos em uma ramificação.

A partir do estado HEAD desanexado, podemos executar git checkout -b new_branch_without_crazy_commit. Isso vai criar uma nova ramificação denominada new_branch_without_crazy_commit e mudar para esse estado. O repositório, agora, está em um novo cronograma do histórico no qual a confirmação 872fa7e não existe mais. Neste ponto, podemos continuar trabalhando nessa nova ramificação, na qual a confirmação 872fa7e não existe mais e considerá-la como 'desfeita'. Infelizmente, se você precisar da ramificação anterior, talvez ela tenha sido sua ramificação mestre, esta estratégia 'desfazer' não é apropriada. Vamos dar uma olhada em algumas outras estratégias 'desfazer'. Para obter mais informações e exemplos, reveja nossa discussão detalhada do git checkout .

Como desfazer uma confirmação pública com git revert

Vamos supor que estamos de volta ao exemplo de histórico de confirmação original. O histórico que inclui a confirmação 872fa7e. Desta vez, vamos tentar reverter 'desfazer'. Se executarmos git revert HEAD, o Git vai criar uma nova confirmação com o inverso da última confirmação. Isso adiciona uma nova confirmação ao histórico de ramificação atual e faz com que ele seja parecido com o seguinte:

git log --oneline
e2f9a78 Reverter "Tente algo maluco"
872fa7e Tente algo maluco
a1e8fb5 Faça algumas alterações importantes em hello.txt
435b61d Crie hello.txt
9773e52 Importação inicial

Neste ponto, nós tecnicamente outra vez 'desfizemos' a confirmação 872fa7e. Embora 872fa7e ainda exista no histórico, a nova confirmação e2f9a78 é o inverso das alterações em 872fa7e. Diferente de nossa estratégia de verificação anterior, podemos continuar usando a mesma ramificação. Esta solução é um desfeito satisfatório. Este é o método 'desfazer' ideal para trabalhar com repositórios compartilhados públicos. Se você tiver exigências de manter um histórico Git curado e mínimo, talvez esta estratégia não seja satisfatória.

Como desfazer uma confirmação com git reset

Para esta estratégia 'desafazer', vamos continuar com o exemplo de trabalho. git reset é um comando extenso com vários usos e funções. Se chamarmos git reset --hard a1e8fb5, o histórico de confirmação é redefinido para essa confirmação especificada. Examinando o histórico de confirmação com git log, ele será parecido com:

git log --oneline
a1e8fb5 Faça algumas alterações importantes em hello.txt
435b61d Crie hello.txt
9773e52 Importação inicial

A saída de log mostra que as confirmações e2f9a78 e 872fa7e não existem mais no histórico de confirmação. Neste ponto, podemos continuar trabalhando e criando novas confirmações como se as confirmações 'malucas' 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 tivermos um repositório remoto compartilhado que tenha a confirmação 872fa7e enviada para ele e tentarmos executar git push em uma ramificação em que redefinimos o histórico, o Git vai pegar isso e lançar um erro. O Git vai supor que a ramificação que está sendo enviada não está atualizada por causa de suas confirmações ausentes. Nesses cenários, git revert deve ser o método 'desfazer' preferido.

Como desfazer a última confirmação

Na seção anterior, discutimos diferentes estratégias para desfazer confirmações. Estas estratégias são todas aplicáveis à confirmação mais recente também. Em alguns casos, porém, podemos não precisar remover ou redefinir a última confirmação. Talvez isso tenha sido feito de forma prematura. Neste caso, você pode corrigir a confirmação mais recente. Depois que tiver feito mais alterações no diretório de trabalho e tiver montado eles para confirmação usando git add, você pode executar git commit --amend. Isso vai fazer o Git abrir o editor de sistema configurado e deixar você modificar a última mensagem de confirmação. As novas alterações serão adicionadas à confirmação corrigida.

Como desfazer alterações não confirmadas

Antes que as alterações sejam confirmadas 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 obter informações mais detalhadas sobre como esses dois mecanismos funcionam, visite a página git reset, que fala deles detalhadamente.

O diretório de trabalho

O diretório de trabalho geralmente está em sincronia com o sistema de arquivos local. Para desfazer as alterações no diretório de trabalho, você pode editar arquivos como faria normalmente usando 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. Além disso, git reset pode ser chamado com as opções --mixed ou --hard e vai 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. Git reset é usado principalmente 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 geralmente deve ser considerado como um método desfazer 'local'. Uma redefinição deve ser usada ao desfazer alterações para uma ramificação privada. Isso isola com segurança a remoção de confirmações 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 remotamente 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á confirmações ausentes.

O método preferido para desfazer o histórico compartilhado é git revert. Uma reversão é mais segura do que uma redefinição porque ela não vai remover nenhuma confirmação de um histórico compartilhado. Uma reversão vai reter as confirmações que você quer desfazer e criar uma nova confirmação que inverta a confirmação indesejada. Este método é mais seguro para a colaboração remota compartilhada porque um desenvolvedor remoto pode, então, puxar a ramificação e receber a nova confirmação de reversão que desfaz a confirmação indesejada.

Resumo

Nós cobrimos muitas estratégias de alto nível para desfazer coisas no Git. É importante lembrar que existe mais de uma forma de 'desfazer' em um projeto do Git. A maior parte da discussão nesta página tocou em tópicos mais profundos que são mais completamente explicados em páginas específicas para os comandos relevantes do Git. As ferramentas de 'desfazer' mais comumente usadas são git checkout, git revert e git reset. Alguns pontos-chave a lembrar são:

  • Depois que as alterações são confirmadas, elas geralmente são permanentes
  • Use git checkout para se movimentar e rever o histórico de confirmação
  • git revert é a melhor ferramenta para desfazer alterações públicas compartilhadas
  • git reset é mais bem usado para desfazer alterações privadas locais

Além dos principais comandos de desfazer, demos uma olhada em outros utilitários do Git: git log para encontrar confirmações perdidas git clean para desfazer alterações não confirmadas 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.