-
1. Primeiros Passos
- 1.1 Sobre Controle de Versão
- 1.2 Uma Breve História do Git
- 1.3 O que é Git?
- 1.4 A Linha de Comando
- 1.5 Instalando o Git
- 1.6 Configuração inicial do Git
- 1.7 Obtendo Ajuda
- 1.8 Resumo
-
2. Fundamentos do Git
-
3. Ramificação (Branching) no Git
-
4. Git no Servidor
- 4.1 Os Protocolos
- 4.2 Colocando o Git em um Servidor
- 4.3 Gerando a sua Chave Pública SSH
- 4.4 Configurando o Servidor
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Opções de Hospedagem de Terceiros
- 4.10 Resumo
-
5. Git Distribuído
-
6. GitHub
-
7. Ferramentas do Git
- 7.1 Seleção de Revisão
- 7.2 Área de Stage Interativa
- 7.3 Fazendo Stash e Limpando
- 7.4 Assinando Seu Trabalho
- 7.5 Pesquisando (Searching)
- 7.6 Reescrevendo o Histórico
- 7.7 Reset Desmistificado
- 7.8 Merging Avançado
- 7.9 Rerere
- 7.10 Depurando com Git
- 7.11 Submódulos
- 7.12 Empacotando (Bundling)
- 7.13 Substituir (Replace)
- 7.14 Armazenamento de Credenciais
- 7.15 Resumo
-
8. Customizando o Git
- 8.1 Configuração do Git
- 8.2 Atributos do Git
- 8.3 Hooks do Git
- 8.4 Uma Política de Exemplo Imposta pelo Git
- 8.5 Resumo
-
9. Git e Outros Sistemas
- 9.1 Git como Cliente
- 9.2 Migrando para o Git
- 9.3 Resumo
-
10. Git Internals (Por Dentro do Git)
- 10.1 Encanamento e Porcelana (Plumbing and Porcelain)
- 10.2 Objetos do Git
- 10.3 Referências do Git
- 10.4 Arquivos de pacote (Packfiles)
- 10.5 Refspec
- 10.6 Protocolos de Transferência
- 10.7 Manutenção e Recuperação de Dados
- 10.8 Variáveis de Ambiente
- 10.9 Resumo
-
A1. Appendix A: O Git em Outros Ambientes
- A1.1 Interfaces Gráficas
- A1.2 Git no Visual Studio
- A1.3 Git no Visual Studio Code
- A1.4 Git no IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git no Sublime Text
- A1.6 Git no Bash
- A1.7 Git no Zsh
- A1.8 Git no PowerShell
- A1.9 Resumo
-
A2. Appendix B: Incorporando o Git nos seus Aplicativos
- A2.1 Linha de Comando do Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Appendix C: Comandos do Git
- A3.1 Configuração e Ajustes
- A3.2 Obtendo e Criando Projetos
- A3.3 Snapshots Básicos
- A3.4 Branches e Merges
- A3.5 Compartilhando e Atualizando Projetos
- A3.6 Inspeção e Comparação
- A3.7 Depuração
- A3.8 Patches
- A3.9 E-mail
- A3.10 Sistemas Externos
- A3.11 Administração
- A3.12 Comandos de Encanamento
10.4 Git Internals (Por Dentro do Git) - Arquivos de pacote (Packfiles)
Arquivos de pacote (Packfiles)
Se você seguiu todas as instruções de exemplo da seção anterior, agora você deve ter um repositório Git de teste com 11 objetos — quatro blobs, três trees (árvores), três commits e uma tag:
$ find .git/objects -type f
.git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
.git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
.git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
.git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
.git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
.git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
O Git comprime o conteúdo desses arquivos com zlib e, como você não está armazenando muita coisa, todos esses arquivos juntos ocupam apenas 925 bytes.
Agora você vai adicionar mais conteúdo de tamanho razoável ao repositório para demonstrar uma funcionalidade interessante do Git.
Para demonstrar, nós adicionaremos o arquivo repo.rb da biblioteca do Grit — que é um arquivo de código-fonte de aproximadamente 22K:
$ curl https://raw.githubusercontent.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb
$ git checkout master
$ git add repo.rb
$ git commit -m 'Create repo.rb'
[master 484a592] Create repo.rb
3 files changed, 709 insertions(+), 2 deletions(-)
delete mode 100644 bak/test.txt
create mode 100644 repo.rb
rewrite test.txt (100%)
Se você olhar para a árvore resultante, você poderá ver o valor SHA-1 que foi calculado para o seu novo objeto blob repo.rb:
$ git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
Você pode então usar o git cat-file para ver quão grande é esse objeto:
$ git cat-file -s 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5
22044
Neste momento, faça uma pequena modificação nesse arquivo e veja o que acontece:
$ echo '# testing' >> repo.rb
$ git commit -am 'Modify repo.rb a bit'
[master 2431da6] Modify repo.rb a bit
1 file changed, 1 insertion(+)
Ao conferir a árvore criada por esse último commit, você verá algo interessante:
$ git cat-file -p master^{tree}
100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
100644 blob b042a60ef7dff760008df33cee372b945b6e884e repo.rb
100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
O blob agora é um blob diferente, o que significa que, embora você tenha adicionado apenas uma única linha ao final de um arquivo de 400 linhas, o Git armazenou esse novo conteúdo como um objeto completamente novo:
$ git cat-file -s b042a60ef7dff760008df33cee372b945b6e884e
22054
Você tem dois objetos de 22K quase idênticos em seu disco (cada um comprimido para aproximadamente 7K). Não seria legal se o Git pudesse armazenar um deles na íntegra, mas então para o segundo objeto o Git armazenasse apenas o delta entre ele e o primeiro?
Acontece que ele pode.
O formato inicial em que o Git salva objetos no disco é chamado de formato de objeto “loose” (solto).
No entanto, ocasionalmente, o Git empacota (packs) vários desses objetos num único arquivo binário chamado de “packfile” (arquivo de pacote) a fim de economizar espaço e ser mais eficiente.
O Git faz isso se você tiver muitos objetos loose soltos, se você rodar o comando git gc manualmente, ou se você os submeter (push) ao servidor remoto.
Para ver o que acontece, você pode pedir ao Git para empacotar os objetos chamando o comando git gc:
$ git gc
Counting objects: 18, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (18/18), done.
Total 18 (delta 3), reused 0 (delta 0)
Se você olhar em seu diretório objects, você notará que a maioria de seus objetos sumiu e um novo par de arquivos apareceu:
$ find .git/objects -type f
.git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/info/packs
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.idx
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.pack
Os objetos que permanecem são os blobs que não são apontados por nenhum commit — neste caso, o exemplo “what is up, doc?” e os blobs de exemplo “test content” que você criou anteriormente. Como você nunca os adicionou a nenhum commit, eles são considerados dangling (soltos/perdidos) e não são empacotados no seu novo packfile.
Os outros arquivos são o seu novo arquivo packfile e um índice.
O packfile é um único arquivo que abrange o conteúdo de todos os objetos que foram removidos do seu sistema de arquivos.
O índice é um arquivo que contém os offsets (deslocamentos) para que você possa buscar e encontrar de forma veloz para algum objeto mais específico.
O que é legal é que, embora os objetos no disco antes de você executar o comando gc tivessem juntos em média 15K de tamanho, o novo arquivo de pacote (packfile) tem apenas 7K.
Você cortou pela metade a utilização do seu disco em virtude pelo empacotamento de seus objetos.
Como o Git faz isso?
Quando o Git empacota objetos, ele procura por arquivos que tenham nomes e tamanhos semelhantes e armazena apenas os deltas (as diferenças) de uma versão do arquivo para a próxima.
Você pode olhar no arquivo packfile e ver o que o Git fez para poupar mais espaço.
O comando plumbing git verify-pack permite que você veja tudo o que foi empacotado:
$ git verify-pack -v .git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.idx
2431da676938450a4d72e260db3bf7b0f587bbc1 commit 223 155 12
69bcdaff5328278ab1c0812ce0e07fa7d26a96d7 commit 214 152 167
80d02664cb23ed55b226516648c7ad5d0a3deb90 commit 214 145 319
43168a18b7613d1281e5560855a83eb8fde3d687 commit 213 146 464
092917823486a802e94d727c820a9024e14a1fc2 commit 214 146 610
702470739ce72005e2edff522fde85d52a65df9b commit 165 118 756
d368d0ac0678cbe6cce505be58126d3526706e54 tag 130 122 874
fe879577cb8cffcdf25441725141e310dd7d239b tree 136 136 996
d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree 36 46 1132
deef2e1b793907545e50a2ea2ddb5ba6c58c4506 tree 136 136 1178
d982c7cb2c2a972ee391a85da481fc1f9127a01d tree 6 17 1314 1 \
deef2e1b793907545e50a2ea2ddb5ba6c58c4506
3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree 8 19 1331 1 \
deef2e1b793907545e50a2ea2ddb5ba6c58c4506
0155eb4229851634a0f03eb265b69f5a2d56f341 tree 71 76 1350
83baae61804e65cc73a7201a7252750c76066a30 blob 10 19 1426
fa49b077972391ad58037050f2a75f74e3671e92 blob 9 18 1445
b042a60ef7dff760008df33cee372b945b6e884e blob 22054 5799 1463
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 9 20 7262 1 \
b042a60ef7dff760008df33cee372b945b6e884e
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob 10 19 7282
non delta: 15 objects
chain length = 1: 3 objects
.git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.pack: ok
Aqui, o blob 033b4, que se você bem se lembrar era a primeira versão do seu arquivo repo.rb, está fazendo a referência ao blob b042a, que se tratava da segunda versão do arquivo.
A terceira coluna na saída é o tamanho do objeto no pack (pacote), de modo que você possa ver que b042a consome 22K do arquivo, mas que 033b4 leva apenas 9 bytes.
O que também é interessante é que a segunda versão do arquivo é a única que é armazenada de forma intacta, enquanto a versão original é armazenada como delta — isso ocorre porque é mais provável que você precise de um acesso mais rápido à versão mais recente do arquivo.
A parte muito interessante em tudo isso é que ela pode ser repacotada a qualquer momento.
Ocasionalmente o Git reempacota o seu banco de dados automaticamente, sempre visando tentar economizar mais espaço, mas você pode também o reempacotar a qualquer momento que quiser ao se rodar com a manualidade através do git gc pelas suas próprias mãos.