Git Reset vs Reverter vs Rebase

Publicados: 2021-05-20

Neste artigo, você aprenderá sobre as diferentes maneiras de brincar com commits no Git.

Como um desenvolvedor, você teria passado por várias situações em que gostaria de reverter para um de seus commits anteriores, mas não tinha certeza de como fazer isso. E mesmo que você conheça os comandos do Git como reset, reverter, rebase, não está ciente das diferenças entre eles. Então, vamos começar e entender o que são git reset, revert e rebase.

Git Reset

Git reset é um comando complexo e é usado para desfazer as alterações.

Você pode pensar em git reset como um recurso de reversão. Com git reset, você pode pular entre vários commits. Existem três modos de executar um comando git reset: –soft, –mixed e –hard. Por padrão, o comando git reset usa o modo misto. Em um fluxo de trabalho de redefinição do git, três mecanismos de gerenciamento interno do git entram em cena: HEAD , área de teste (índice) e o diretório de trabalho .

git reset - geekflare

O diretório de trabalho é o local onde você está trabalhando atualmente, é o local onde seus arquivos estão presentes. Usando um comando git status, você pode ver quais arquivos / pastas estão presentes no diretório de trabalho.

A área de teste (índice) é onde o git rastreia e salva todas as mudanças nos arquivos. As alterações salvas são refletidas no diretório .git. Use git add “filename” para adicionar o arquivo à área de teste. E como antes, ao executar git status, você verá quais arquivos estão presentes na área de teste.

O branch atual no Git é conhecido como HEAD. Ele aponta para o último commit, que aconteceu no branch de checkout atual. É tratado como um ponteiro para qualquer referência. Depois de fazer check-out em outro branch, o HEAD também se move para o novo branch.

Deixe-me explicar como o git reset funciona nos modos hard, soft e mixed. O modo difícil é usado para ir para o commit apontado, o diretório de trabalho é povoado com arquivos desse commit e a área de teste é redefinida. Na reinicialização suave, apenas o ponteiro é alterado para o commit especificado. Os arquivos de todos os commits permanecem no diretório de trabalho e na área de teste antes da redefinição. No modo misto (padrão), o ponteiro e a área de teste são redefinidos.

Git Reset Hard

O objetivo do git hard reset é mover o HEAD para o commit especificado. Ele removerá todos os commits ocorridos após o commit especificado. Este comando mudará o histórico de confirmação e apontará para a confirmação especificada.

Neste exemplo, vou adicionar três novos arquivos, confirmá-los e, em seguida, executar uma reinicialização a frio.

Como você pode ver no comando abaixo, no momento, não há nada para confirmar.

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Agora, vou criar 3 arquivos e adicionar algum conteúdo a eles.

 $ vi file1.txt $ vi file2.txt $ vi file3.txt

Adicione esses arquivos ao repositório existente.

 $ git add file*

Quando você executar novamente o comando status, ele refletirá os novos arquivos que acabei de criar.

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: file1.txt new file: file2.txt new file: file3.txt

Antes de fazer commit, deixe-me mostrar a você, atualmente tenho um log de 3 commits no Git.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Agora, vou me comprometer com o repositório.

 $ git commit -m 'added 3 files' [master d69950b] added 3 files 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

Se eu fizer ls-files, você verá que os novos arquivos foram adicionados.

 $ git ls-files demo dummyfile newfile file1.txt file2.txt file3.txt

Quando executo o comando log no git, tenho 4 commits e o HEAD aponta para o commit mais recente.

 $ git log --oneline d69950b (HEAD -> master) added 3 files 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Se eu excluir o file1.txt manualmente e fizer um git status, ele mostrará a mensagem de que as alterações não foram preparadas para commit.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a")

Agora, irei executar o comando de reinicialização a frio.

 $ git reset --hard HEAD is now at d69950b added 3 files

Se eu verificar novamente o status, descobrirei que não há nada para confirmar e o arquivo que excluí voltou para o repositório. A reversão aconteceu porque depois de excluir o arquivo, eu não confirmei, então, após uma reinicialização a frio, ele voltou ao estado anterior.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Se eu verificar o log do git, é assim que fica.

 $ git log commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 19:53:31 2020 +0530 added 3 files commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

O objetivo da reinicialização a frio é apontar para a confirmação especificada e atualizar o diretório de trabalho e a área de preparação. Deixe-me mostrar mais um exemplo. Atualmente, a visualização dos meus commits fica assim abaixo:

ficar duro

Aqui, irei executar o comando com HEAD ^, o que significa que desejo redefinir para o commit anterior (um commit de volta).

 $ git reset --hard HEAD^ HEAD is now at 0db602e one more commit

Você pode ver que o ponteiro principal agora mudou para 0db602e de d69950b.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git hard 1

Se você verificar o log, o commit de d69950b foi embora e o cabeçalho agora aponta para 0db602e SHA.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 Test

Se você executar os arquivos ls, poderá ver que file1.txt, file2.txt e files3.txt não estão mais no repositório porque esse commit e seu arquivo foram removidos após a reinicialização a frio.

 $ git ls-files demo dummyfile newfile

Git Soft Reset

Da mesma forma, agora vou mostrar um exemplo de uma reinicialização suave. Considere, eu adicionei os 3 arquivos novamente conforme mencionado acima e os enviei. O log do git aparecerá conforme mostrado abaixo. Você pode ver que 'soft reset' é meu último commit, e HEAD também está apontando para isso.

 $ git log --oneline aa40085 (HEAD -> master) soft reset 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Detalhes do commit no log podem ser vistos usando o comando abaixo.

 $ git log commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 21:01:36 2020 +0530 soft reset commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Agora, usando o soft reset, quero mudar para um dos commits mais antigos com SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

Para fazer isso, irei executar o comando abaixo. Você precisa passar mais de 6 caracteres iniciais de SHA, o SHA completo não é necessário.

 $ git reset --soft 0db602e085a4

Agora, quando executo o log do git, posso ver que o HEAD foi redefinido para o commit especificado.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Mas a diferença aqui é que os arquivos do commit (aa400858aab3927e79116941c715749780a59fc9) onde eu adicionei 3 arquivos ainda estão no meu diretório de trabalho. Eles não foram excluídos. É por isso que você deve usar uma reinicialização suave em vez de uma reinicialização total. Não há risco de perder os arquivos no modo soft.

 $ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfile

Git Reverter

No Git, o comando reverter é usado para realizar uma operação de reversão, ou seja, para reverter algumas alterações. É semelhante ao comando reset, mas a única diferença aqui é que você executa um novo commit para voltar a um commit particular. Resumindo, é justo dizer que o comando git revert é um commit.

O comando Git revert não exclui nenhum dado durante a execução da operação de reversão.

Digamos que estou adicionando 3 arquivos e executando uma operação git commit para o exemplo de reversão.

 $ git commit -m 'add 3 files again' [master 812335d] add 3 files again 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

O log mostrará o novo commit.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Agora eu gostaria de reverter para um dos meus commits anteriores, digamos - “59c86c9 novo commit”. Gostaria de executar o comando abaixo.

 $ git revert 59c86c9

Isso abrirá um arquivo, você encontrará os detalhes do commit para o qual está tentando reverter, e você pode dar um nome ao seu novo commit aqui, e então salvar e fechar o arquivo.

 Revert "new commit" This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: dummyfile

Depois de salvar e fechar o arquivo, esta é a saída que você obterá.

 $ git revert 59c86c9 [master af72b7a] Revert "new commit" 1 file changed, 1 insertion(+), 1 deletion(-)

Agora, para fazer as alterações necessárias, ao contrário de reset, reverter executou mais um novo commit. Se você verificar o log novamente, encontrará um novo commit por causa da operação de reversão.

 $ git log --oneline af72b7a (HEAD -> master) Revert "new commit" 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git revert

O log do Git terá todo o histórico de commits. Se você deseja remover os commits do histórico, então reverter não é uma boa escolha, mas se você deseja manter as alterações dos commits no histórico, então reverter é o comando adequado ao invés de redefinir.

Git Rebase

No Git, rebase é a maneira de mover ou combinar commits de um branch sobre outro branch. Como desenvolvedor, eu não criaria meus recursos no branch master em um cenário do mundo real. Eu trabalharia em meu próprio branch (um 'branch de recurso'), e quando tiver alguns commits em meu branch de recurso com o recurso adicionado, gostaria de movê-lo para o branch master.

Rebase às vezes pode ser um pouco confuso de entender porque é muito semelhante a uma fusão. O objetivo de mesclar e rebasing ambos é pegar os commits do meu branch de recursos e colocá-los em um branch master ou qualquer outro branch. Considere, eu tenho um gráfico parecido com este:

git rebase

Suponha que você esteja trabalhando em equipe com outros desenvolvedores. Nesse caso, você pode imaginar que isso poderia ficar realmente complexo quando você tem um monte de outros desenvolvedores trabalhando em diferentes ramos de recursos, e eles têm mesclado várias alterações. É confuso rastrear.

Portanto, é aqui que o rebase vai ajudar. Desta vez, em vez de fazer um git merge, vou fazer um rebase, onde quero pegar meus dois commits de branch de recurso e movê-los para o branch master. Um rebase pegará todos os meus commits do branch de recursos e os moverá para cima dos commits do branch master. Então, nos bastidores, o git está duplicando os commits de branch de recurso no branch master.

git rebase 1

Esta abordagem lhe dará um gráfico de linha reta limpo com todos os commits em uma linha.

git revert 2

Isso torna mais fácil rastrear quais commits foram para onde. Você pode imaginar se você está em uma equipe com muitos desenvolvedores, todos os commits ainda estão em uma fileira. Portanto, é realmente fácil acompanhar, mesmo se você tiver muitas pessoas trabalhando no mesmo projeto ao mesmo tempo.

Deixe-me mostrar isso de forma prática.

É assim que meu branch master se parece atualmente. Possui 4 commits.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Vou executar o comando abaixo para criar e mudar para um novo branch chamado feature, e este branch será criado a partir do segundo commit, ou seja, 59c86c9

 (master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'

Se você verificar o log no branch de recursos, ele terá apenas 2 commits vindos do master (mainline).

 (feature) $ git log --oneline 59c86c9 (HEAD -> feature) new commit e2f44fc (origin/master, origin/HEAD) test

Vou criar o recurso 1 e enviá-lo ao branch de recursos.

 (feature) $ vi feature1.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 1' [feature c639e1b] feature 1 1 file changed, 1 insertion(+) create mode 100644 feature1.txt

Vou criar mais um recurso, ou seja, o recurso 2, no branch de recursos e submetê-lo.

 (feature) $ vi feature2.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 2' [feature 0f4db49] feature 2 1 file changed, 1 insertion(+) create mode 100644 feature2.txt

Agora, se você verificar o log do branch de recurso, ele tem dois novos commits, que executei acima.

 (feature) $ git log --oneline 0f4db49 (HEAD -> feature) feature 2 c639e1b feature 1 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Agora, quero adicionar esses dois novos recursos ao branch master. Para isso, usarei o comando rebase. A partir do branch de recursos, vou rebase contra o branch master. O que isso fará é ancorar novamente meu branch de recursos em relação às alterações mais recentes.

 (feature) $ git rebase master Successfully rebased and updated refs/heads/feature.

Agora vou prosseguir e verificar o branch master.

 (feature) $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)

E, finalmente, rebase o branch master contra o meu branch de recurso. Isso pegará esses dois novos commits no meu branch de recursos e os reproduzirá no topo do meu branch master.

 (master) $ git rebase feature Successfully rebased and updated refs/heads/master.

Agora, se eu verificar o log no branch master, posso ver que os dois commits do meu branch de recursos foram adicionados ao meu branch master com sucesso.

 (master) $ git log --oneline 766c996 (HEAD -> master, feature) feature 2 c036a11 feature 1 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Isso era tudo sobre comandos de reset, reversão e rebase no Git.

Conclusão

Isso era tudo sobre comandos de reset, reversão e rebase no Git. Espero que este guia passo a passo tenha sido útil. Agora, você sabe como brincar com seus commits de acordo com a necessidade usando os comandos mencionados no artigo.