Close

Resetting, checking out & reverting


The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.

Por serem muito parecidos, é muito fácil misturar qual comando deve ser usado em qualquer cenário de desenvolvimento. Neste artigo, a gente vai comparar as configurações mais comuns de git reset, git checkout e git revert. Espero que você saia com a confiança necessária para navegar em seu repositório usando qualquer um desses comandos.

As três árvores do Git

It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.

Um checkout é uma operação que move o ponteiro de referência HEAD para um commit especificado. Para demonstrar melhor esse comportamento, considere o exemplo a seguir:

Mova o ponteiro de referência HEAD para um commit especificado
bancos de dados
Material relacionado

Como mover um Repositório do Git completo

Logotipo do Bitbucket
VER SOLUÇÃO

Aprenda a usar o Git com o Bitbucket Cloud

Este exemplo demonstra uma sequência de commits no branch main. A referência HEAD e a referência do branch main apontam no momento para o commit d. Agora vamos executar o git checkout b

Sequence of commits on the main branch

Esta é uma atualização para a árvore do "histórico de commits". O comando git checkout pode ser usado em um escopo de nível de commit ou de arquivo. Um checkout no nível do arquivo vai alterar o conteúdo do arquivo para o commit específico.

Uma reversão é uma operação que recebe um commit especificado e cria um novo commit que inverte o commit especificado. O git revert só pode ser executado em um escopo de nível de commit e não tem funcionalidade no nível do arquivo.

Uma redefinição é uma operação que recebe um commit especificado e redefine as "três árvores" para corresponder ao estado do repositório nesse commit especificado. Uma redefinição pode ser invocada em três modos diferentes, que correspondem às três árvores.

O checkout e a redefinição costumam ser usados para realizar ações de desfazer locais ou privadas. Eles modificam o histórico de um repositório que pode causar conflitos ao enviar para repositórios compartilhados remotos. A reversão é considerada uma operação segura para a ação de desfazer pública, pois cria um novo histórico que pode ser compartilhado remotamente e não substitui o histórico do qual os membros da equipe remota podem depender.

Git reset vs revert vs checkout reference


A tabela abaixo resume os casos de uso mais comuns para todos esses comandos. Mantenha essa referência à mão, pois sem dúvida você vai precisar usar pelo menos algumas delas durante sua carreira no Git.

Comando

Escopo

Casos de uso comuns

git reset

Escopo

Nível de commit

Casos de uso comuns

Discard commits in a private branch or throw away uncommitted changes

git reset

Escopo

Nível do arquivo

Casos de uso comuns

Desfazer o staging de um arquivo

git checkout

Escopo

Nível de commit

Casos de uso comuns

Alternar entre os branches ou inspecionar instantâneos antigos

git checkout

Escopo

Nível do arquivo

Casos de uso comuns

Descartar alterações no diretório de trabalho

git revert

Escopo

Nível de commit

Casos de uso comuns

Desfazer commits em um branch público

git revert

Escopo

Nível do arquivo

Casos de uso comuns

(N/A)

Commit level operations


Os parâmetros que você passa para git reset e git checkout determinam o escopo. Quando você não inclui um caminho de arquivo como parâmetro, eles operam em commits inteiros. É o que a gente vai explorar nesta seção. Observe que o git revert não tem equivalente no nível do arquivo.

Reset a specific commit

No nível do commit, a redefinição é uma maneira de mover a ponta de um branch para um commit diferente, o que pode ser usado para remover commits do branch atual. Por exemplo, o comando a seguir move o branch de hotfix para trás por dois commits.

git checkout hotfix git reset HEAD~2

Os dois commits que estavam no final do hotfix agora são commits órfãos, pendentes. Ou seja: eles vão ser excluídos na próxima vez que o Git realizar uma coleta de lixo. Em outras palavras, você está dizendo que quer jogar fora esses commits. Essa situação pode ser vista da seguinte forma:

Redefinir o branch de hotfix para HEAD-2

Esse uso do git reset é uma maneira simples de desfazer alterações que não foram compartilhadas com mais ninguém. É o seu comando quando você começa a trabalhar em uma função e se pega pensando: “Caramba, o que estou fazendo? Eu deveria começar de novo.”

Além de mover o branch atual, você também pode usar o git reset para alterar o instantâneo de staging e/ou o diretório de trabalho passando uma das seguintes marcações:

  • --soft — O instantâneo de staging e o diretório de trabalho não são alterados de forma alguma.
  • --mixed — O instantâneo de staging é atualizado para corresponder ao commit especificado, mas o diretório de trabalho não é afetado. Essa é a opção padrão.
  • --hard — O instantâneo de staging e o diretório de trabalho são atualizados para corresponder ao commit especificado.

It’s easier to think of these modes as defining the scope of a git reset operation. For further detailed information visit the git reset page.

Fazer checkout de commits antigos

O comando git checkout é usado para atualizar o estado do repositório para um ponto específico no histórico do projeto. Quando transmitido com um nome de branch, ele permite alternar entre branches.

git checkout hotfix

Internamente, tudo o que o comando acima faz é mover o HEAD para um branch diferente e atualizar o diretório de trabalho para corresponder a essa mudança. Como essa operação tem o potencial de substituir as alterações locais, o Git força você a fazer o commit ou o stash de quaisquer alterações no diretório de trabalho que vão ser perdidas durante a operação de checkout. Ao contrário do git reset, o git checkout não move nenhum branch.

Moving HEAD from main to hotfix

Você também pode fazer o check out de commits arbitrários passando a referência do commit em vez de um branch. É exatamente a mesma coisa que o check out de um branch: a referência HEAD é movida para o commit especificado. Por exemplo, o comando a seguir vai verificar o avô do commit atual:

git checkout HEAD~2
Mover `HEAD` para um commit arbitrário

Ele é útil para fazer a inspeção rápida uma versão antiga do seu projeto. No entanto, como não há referência de branch para o HEAD atual, você fica em um estado de HEAD desanexado. Essa situação pode ser perigosa se você começar a adicionar novos commits porque não vai ter como voltar para eles depois que você mudar para outro branch. Por esse motivo, você deve sempre criar um novo branch antes de adicionar commits a um HEAD desanexado.

Undo public commits with revert

Reverter desfaz um commit criando um novo commit. Essa é uma maneira segura de desfazer alterações, pois não há chance de reescrever o histórico de commits. Por exemplo, o comando a seguir vai identificar as alterações contidas no penúltimo commit, criar um novo commit desfazendo essas alterações e anexar o novo commit no projeto existente.

git checkout hotfix git revert HEAD~2

Essa situação pode ser vista da seguinte forma:

Reverter o penúltimo commit

Compare esse comportamento com o do git reset, que altera o histórico de commits existente. Por esse motivo, o git revert deve ser usado para desfazer alterações em um branch público, e o git reset deve ser reservado para desfazer alterações em um branch privado.

Você também pode pensar no git revert como uma ferramenta para desfazer alterações com commit, enquanto o git reset HEAD é para desfazer alterações sem commit.

Como o git checkout, o git revert tem o potencial de sobrescrever arquivos no diretório de trabalho, então ele vai solicitar que você faça o commit ou o stash das alterações que seriam perdidas durante a operação de reversão.

File-level operations


Os comandos git reset e git checkout também aceitam um caminho de arquivo opcional como parâmetro. Assim, o comportamento deles tem uma alteração drástica. Em vez de operar em instantâneos inteiros, eles são forçados a limitar suas operações a um único arquivo.

Git reset a specific file

Quando invocado com um caminho de arquivo, o git reset atualiza o instantâneo de staging para corresponder à versão do commit especificado. Por exemplo, esse comando vai buscar a versão do foo.py no penúltimo commit e o preparar para o próximo commit:

git reset HEAD~2 foo.py

Assim como na versão de nível de commit do git reset, essa opção costuma ser mais usada com HEAD em vez de um commit arbitrário. Executar git reset HEAD foo.py vai desfazer o staging de foo.py. As alterações que ele contém ainda vão estar presentes no diretório de trabalho.

Mover um arquivo do histórico de commits para o instantâneo de staging

As marcações --soft, --mixed e --hard não têm nenhum efeito na versão em nível de arquivo do git reset, pois o instantâneo de staging sempre é atualizado, e o diretório de trabalho nunca é atualizado.

Git checkout file

Fazer checkout de um arquivo é semelhante a usar o git reset com um caminho de arquivo, exceto pelo fato de que ele atualiza o diretório de trabalho em vez do ambiente de staging. Ao contrário da versão em nível de commit desse comando, essa ação não move a referência HEAD, o que significa que você não vai mudar de branch.

Mover um arquivo do histórico de commits para o diretório de trabalho

Por exemplo, o comando a seguir faz com que o foo.py no diretório de trabalho corresponda ao do penúltimo commit:

git checkout HEAD~2 foo.py

Assim como a invocação no nível do commit do git checkout, essa opção pode ser usada para inspecionar versões antigas de um projeto, mas o escopo é limitado ao arquivo especificado.

Se você fizer o staging e o commit do arquivo com checkout, o efeito vai ser o de “reverter” para a versão antiga desse arquivo. Observe que assim você remove todas as alterações subsequentes no arquivo, enquanto o comando git revert desfaz apenas as alterações introduzidas pelo commit especificado.

Como o git reset, ele costuma ser usado com HEAD como referência de commit. Por exemplo, git checkout HEAD foo.py tem o efeito de descartar alterações que não passaram por staging para foo.py. Esse é um comportamento semelhante ao de git reset HEAD --hard, mas opera apenas no arquivo especificado.

Resumo


You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.


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.

Pessoas colaborando usando uma parede cheia de ferramentas

Blog do Bitbucket

Ilustração do DevOps

Caminho de aprendizagem de DevOps

Demonstrações de funções no Demo Den com parceiros da Atlassian

Como o Bitbucket Cloud funciona com o Atlassian Open DevOps

Inscreva-se para receber a newsletter de DevOps

Thank you for signing up