Neste artigo, você aprenderá sobre diferentes maneiras de brincar com commits no Git.
Como desenvolvedor, você passaria por essas situações várias vezes 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 Git como reset, revert, rebase, você 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.
últimas postagens
Git Redefinir
Git reset é um comando complexo e é usado para desfazer as alterações.
Você pode pensar no 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 git reset, três mecanismos internos de gerenciamento do git entram em cena: HEAD, área de preparação (índice) e o diretório de trabalho.
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.
Staging Area (Index) é onde o git rastreia e salva todas as alterações nos arquivos. As alterações salvas são refletidas no diretório .git. Você usa git add “filename” para adicionar o arquivo à área de preparação. E como antes, ao executar git status, você verá quais arquivos estão presentes na área de teste.
A ramificação atual no Git é chamada de HEAD. Ele aponta para o último commit, que aconteceu na ramificação de checkout atual. É tratado como um ponteiro para qualquer referência. Depois de fazer o checkout em outra ramificação, o HEAD também se move para a nova ramificação.
Deixe-me explicar como o git reset funciona nos modos rígido, suave e misto. O modo difícil é usado para ir para o commit apontado, o diretório de trabalho é preenchido com arquivos desse commit e a área de preparação é 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 preparação antes da redefinição. No modo misto (padrão), o ponteiro e a área de preparação são redefinidos.
Git Redefinir 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 commits e apontará para o commit especificado.
Neste exemplo, vou adicionar três novos arquivos, confirmá-los e executar uma reinicialização total.
Como você pode ver no comando abaixo, agora 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, criarei 3 arquivos e adicionarei 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 confirmar, deixe-me mostrar a você, atualmente tenho um registro de 3 confirmações 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 arquivo1.txt manualmente e fizer um git status, ele mostrará a mensagem de que as alterações não estão preparadas para confirmação.
$ 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, executarei o comando hard reset.
$ 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 que o arquivo excluído voltou ao repositório. O rollback aconteceu porque depois de deletar o arquivo, eu não fiz o commit, então depois de um hard reset, 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 ficará.
$ 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 do hard reset é apontar para o commit especificado 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 está assim:
Aqui, executarei o comando com HEAD^, o que significa que quero 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 da cabeça mudou para 0db602e de d69950b.
$ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test
Se você verificar o log, o commit de d69950b desapareceu 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 ls-files, 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 o hard reset.
$ git ls-files demo dummyfile newfile
Git Soft Reset
Da mesma forma, agora mostrarei um exemplo de reinicialização suave. Considere, eu adicionei os 3 arquivos novamente como mencionado acima e os confirmei. O git log aparecerá como 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
Os 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, executarei o comando abaixo. Você precisa passar mais de 6 caracteres iniciais do SHA, não é necessário o SHA completo.
$ git reset --soft 0db602e085a4
Agora, quando executo o git log, posso ver que o HEAD foi redefinido para o commit que especifiquei.
$ 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 adicionei 3 arquivos ainda estão no meu diretório de trabalho. Eles não foram excluídos. É por isso que você deve usar um soft reset em vez de um hard reset. Não há risco de perder os arquivos no modo suave.
$ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfile
Git Reverter
No Git, o comando revert é 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 determinado commit. 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 últimos commits, digamos – “59c86c9 new commit”. Eu executaria o comando abaixo.
$ git revert 59c86c9
Isso abrirá um arquivo, você encontrará os detalhes do commit para o qual está tentando reverter e poderá dar um nome ao seu novo commit aqui, 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 do reset, o revert realizou mais um novo commit. Se você verificar o log novamente, encontrará um novo commit devido à 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 log terá todo o histórico de commits. Se você deseja remover os commits do histórico, reverter não é uma boa escolha, mas se você deseja manter as alterações de commit no histórico, reverter é o comando adequado em vez de redefinir.
Git RebaseName
No Git, rebase é a maneira de mover ou combinar commits de um branch sobre outro branch. Como desenvolvedor, eu não criaria meus recursos na ramificação master em um cenário do mundo real. Eu trabalharia em minha própria ramificação (uma ‘ramificação de recursos’) e, quando tiver alguns commits em minha ramificação de recursos com o recurso adicionado, gostaria de movê-la para a ramificação principal.
Às vezes, o rebase pode ser um pouco confuso de entender porque é muito semelhante a uma mesclagem. O objetivo de mesclar e rebasear 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 que se parece com isso:
Suponha que você esteja trabalhando em equipe com outros desenvolvedores. Nesse caso, você pode imaginar que isso pode ficar realmente complexo, onde você tem vários outros desenvolvedores trabalhando em diferentes ramificações de recursos e eles mesclam várias alterações. Torna-se confuso rastrear.
Então, é aqui que o rebase vai ajudar. Desta vez, em vez de fazer um git merge, farei um rebase, onde quero pegar meus dois commits de feature branch e movê-los para o branch master. Um rebase pegará todos os meus commits do branch feature e os moverá para cima dos commits do branch master. Portanto, nos bastidores, o git está duplicando os commits do branch de recurso no branch master.
Essa abordagem fornecerá um gráfico de linha reta limpo com todos os commits em uma linha.
Isso facilita o rastreamento de quais commits foram para onde. Você pode imaginar que se você estiver em uma equipe com muitos desenvolvedores, todos os commits ainda estarão seguidos. Portanto, é realmente fácil de seguir, mesmo que você tenha 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. Tem 4 confirmações.
$ 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 uma nova ramificação chamada feature, e esta ramificação será criada a partir do 2º commit, ou seja, 59c86c9
(master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'
Se você checar o log no branch feature, ele tem 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 para a ramificação do recurso.
(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 ramo de recursos e confirmá-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 do 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 à ramificação master. Para isso, usarei o comando rebase. A partir do branch feature, farei o rebase contra o branch master. O que isso fará é ancorar novamente minha ramificação 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 recurso e os repetirá 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 features 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 foi tudo sobre redefinir, reverter e rebase comandos no Git.
Conclusão
Isso foi tudo sobre redefinir, reverter e rebase comandos 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.