As três árvores do Git
24 Jan 2020Quando trabalhamos com os comandos reset
e checkout
do Git, podemos utilizar um modelo mental em que o Git gerencia três árvores: HEAD
, Index
e Working Directory
. Neste texto pretendo mostrar como estas árvores afetam nosso dia-a-dia com a ferramenta e como manipulá-las.
HEAD
A HEAD
é um apontador para o branch atual, que por sua vez é um apontador para o último commit naquele branch.
Para exemplificar, imagine que você acabou de clonar um repositório e este tem os seguintes branches: master
e branch1
. Assim que você o clona, você está no branch master
, portanto a sua HEAD
aponta para o branch master
.
C < master < HEAD
|
B D < branch1
| _/
|/
A
E no momento que executamos o comando git checkout branch1
, estamos mudando o apontamento da HEAD
para o branch branch1
.
C < master
|
B D < branch1 < HEAD
| _/
|/
A
Index
O Index
é seu próximo commit, ou seja, os arquivos adicionados na área de stagging
com o comando git add
e antes do comando git commit
. O comando git status
exibe os arquivos que irão para o próximo commit.
Working Directory
Também referenciado como working tree
, o working directory
representa os arquivo em seu diretório, na qual você os edita para adicioná-los ao seu index
. Então ao mudar de branch com o comando git checkout
, o Git irá mudar o apontamento da HEAD
e irá modificar os arquivos em seu diretório.
Fluxo de trabalho
O fluxo de trabalho consiste em modificar um arquivo, que modifica seu working directory
, adicioná-lo ao seu index
(git add
) e realizar o commit (git commit
), que irá mudar o apontamento do seu branch atual, ou seja, o branch em que a HEAD
está apontando.
Por fim, ao mudar de branch (mudar o apontamento da HEAD
) com o comando git checkout
, o Git irá atualizar seu working directory
com os arquivos do branch.
Working Directory Index HEAD
| | |
| <---------- git checkout ---------- |
| | |
| --- git add --> | |
| | |
| | -- git commit --> |
Detalhando o processo
A partir do momento em que iniciamos um repositório no Git com git init
, o branch master
é criado automaticamente e não temos nenhum commit, assim a HEAD
aponta para o branch master
, que não aponta para um commit específico.
? < master
^
head
Então você começa seu trabalho e cria um novo arquivo index.html
. Com isso você modificou seu working directory
.
Working Directory Index HEAD
|
index.html
Ao executar o comando git add index.html
, estamos colocando o arquivo index.html
em nosso index
.
Working Directory Index HEAD
|
index.html
Se adicionarmos outro arquivo chamado footer.html
, nosso working directory
é modificado novamente.
Working Directory Index HEAD
| |
footer.html index.html
Em seguida, para adicionar este arquivo em nosso próximo commit, devemos adicioná-lo em nosso index
com o comando git add footer.html
.
Working Directory Index HEAD
|
index.html
footer.html
Agora é hora de realizarmos nosso commit com o comando git commit -m "Mensagem"
.
Working Directory Index HEAD
|
96b7f8c
|
index.html
footer.html
reset
Durante o detalhamento do processo já vimos como modificar as três árvores, porém existem outros comandos que as modificam. O primeiro comando que veremos é o reset
, que tem três modos.
reset --mixed
Imagine que você tem alguns commits e sua HEAD
está apontando para o último commit.
5d50d76 < master < HEAD
|
|
f831ed8
$ git log --children --decorate
commit 51d7b8b43f6a7742f6a015dec50076d934f1e79f (HEAD -> master)
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date: Sat Nov 2 17:54:34 2019 -0300
Arquivo 3
commit 5d50d7664780f91c91d480e1a6b185fdc71c7733 51d7b8b43f6a7742f6a015dec50076d934f1e79f
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date: Sat Nov 2 17:54:10 2019 -0300
Arquivo 2
commit f831ed83ecc8e25cd4103fecdcb61ce2649cad93 5d50d7664780f91c91d480e1a6b185fdc71c7733
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date: Sat Nov 2 17:53:55 2019 -0300
Arquivo 1
Usando o comando git reset --mixed 5d50d76
, você mudará o apontamento do branch em que a HEAD
aponta.
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
arquivo3.txt
nothing added to commit but untracked files present (use "git add" to track)
O comando
git reset
sem argumentos é equivalente a executar o comandogit reset --mixed
51d7b8b
|
|
5d50d76 < master < HEAD
|
|
f831ed8
Um ponto interessante sobre modo --mixed
é que além de modificar a HEAD
, também modifica o Index
, então o comando desfaz seu commit (conceitualmente) e desfaz o Index
, ou seja, te deixa e um estado onde você acabou de fazer sua alteração no working directory
.
reset --soft
Se executar o comando git reset --soft 5d50d76
, o Git irá modificar a HEAD
mas não o Index
, ou seja, te deixa em um estado onde você modificou seu working directory
e adicionou os arquivos no Index
.
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: arquivo3.txt
reset --hard
Os dois modos anteriores modificam algumas coisas, mas não são perigosos por você ainda ter seu working directory
preservado. O modo --hard
irá alterar as três árvores do Git, então mudará sua HEAD
, Index
e working directory
.
$ git reset --hard 5d50d76
HEAD is now at 5d50d76 Arquivo 2
$ git status
On branch master
nothing to commit, working tree clean
Executando git reset --hard 5d50d76
te deixará em um estado onde você acabou de realizar o commit que você especificou, perdendo todas as alterações após o commit.
$ git log --children --decorate
commit 5d50d7664780f91c91d480e1a6b185fdc71c7733 (HEAD -> master)
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date: Sat Nov 2 17:54:10 2019 -0300
Arquivo 2
commit f831ed83ecc8e25cd4103fecdcb61ce2649cad93 5d50d7664780f91c91d480e1a6b185fdc71c7733
Author: João Vitor Retamero <joaovretamero@gmail.com>
Date: Sat Nov 2 17:53:55 2019 -0300
Arquivo 1
checkout
O comando checkout
é muito similar ao reset --hard
, ou seja, modifica as três árvores. A diferença é que o reset
irá mover o branch que a HEAD
aponta, já o checkout
irá mover apenas a HEAD
.
Então veja a situação abaixo:
51d7b8b < master < HEAD
|
|
5d50d76 9ef3499 < develop
| |
| ______/
|/
f831ed8
Usando o comando git checkout develop
, irá mudar o apontamento da HEAD
assim como as três árvores para que estejam sincronizadas com a nova situação.
51d7b8b < master
|
|
5d50d76 9ef3499 < develop < HEAD
| |
| ______/
|/
f831ed8
Conclusão
Neste texto vimos um conceito importante do Git e que usamos muito no dia-a-dia: as três árvores. Vimos também como as três árvores interagem entre si. Também vimos como modificá-las e as diferenças entre os comandos.
Espero que da próxima vez que usar o Git, você possa entender melhor o que está acontecendo com seu repositório.
Até mais.