-
1. Começando
- 1.1 Sobre Controle de Versão
- 1.2 Uma Breve História do Git
- 1.3 O Básico do Git
- 1.4 A Linha de Comando
- 1.5 Instalando o Git
- 1.6 Configuração Inicial do Git
- 1.7 Pedindo Ajuda
- 1.8 Sumário
-
2. Fundamentos de Git
-
3. Branches no Git
-
4. Git on the Server
- 4.1 The Protocols
- 4.2 Getting Git on a Server
- 4.3 Generating Your SSH Public Key
- 4.4 Setting Up the Server
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Third Party Hosted Options
- 4.10 Summary
-
5. Distributed Git
-
6. GitHub
- 6.1 Configurando uma conta
- 6.2 Contribuindo em um projeto
- 6.3 Maintaining a Project
- 6.4 Managing an organization
- 6.5 Scripting GitHub
- 6.6 Summary
-
7. Git Tools
- 7.1 Revision Selection
- 7.2 Interactive Staging
- 7.3 Stashing and Cleaning
- 7.4 Signing Your Work
- 7.5 Searching
- 7.6 Rewriting History
- 7.7 Reset Demystified
- 7.8 Advanced Merging
- 7.9 Rerere
- 7.10 Debugging with Git
- 7.11 Submodules
- 7.12 Bundling
- 7.13 Replace
- 7.14 Credential Storage
- 7.15 Summary
-
8. Customizing Git
- 8.1 Git Configuration
- 8.2 Git Attributes
- 8.3 Git Hooks
- 8.4 An Example Git-Enforced Policy
- 8.5 Summary
-
9. Git and Other Systems
- 9.1 Git as a Client
- 9.2 Migrating to Git
- 9.3 Summary
-
10. Funcionamento Interno do Git
- 10.1 Encanamento e Porcelana
- 10.2 Objetos do Git
- 10.3 Referências do Git
- 10.4 Packfiles
- 10.5 The Refspec
- 10.6 Transfer Protocols
- 10.7 Maintenance and Data Recovery
- 10.8 Variáveis de ambiente
- 10.9 Sumário
-
A1. Appendix A: Git em Outros Ambientes
- A1.1 Graphical Interfaces
- A1.2 Git in Visual Studio
- A1.3 Git in Eclipse
- A1.4 Git in Bash
- A1.5 Git in Zsh
- A1.6 Git in Powershell
- A1.7 Resumo
-
A2. Appendix B: Embedding Git in your Applications
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Git Commands
- A3.1 Setup and Config
- A3.2 Getting and Creating Projects
- A3.3 Basic Snapshotting
- A3.4 Branching and Merging
- A3.5 Sharing and Updating Projects
- A3.6 Inspection and Comparison
- A3.7 Debugging
- A3.8 Patching
- A3.9 Email
- A3.10 External Systems
- A3.11 Administration
- A3.12 Plumbing Commands
10.3 Funcionamento Interno do Git - Referências do Git
Referências do Git
Você pode executar algo como git log 1a410e
para ver todo o seu histórico, mas você ainda precisa lembrar que 1a410e
é o último commit para poder caminhar nesse histórico para encontrar todos esses objetos.
Você precisa de um arquivo em que você possa armazenar o valor do SHA-1 com um simples nome para que você possa usar essa referência em vez do valor de um SHA-1 puro.
No Git, chamamos isso de “referências” (references) ou “refs”; você pode encontrar os arquivos que contém os valores SHA-1 no diretório .git/refs
.
No projeto atual, este diretório não contém nenhum arquivo, mas contém uma simples estrutura:
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
Para criar uma nova referência que irá te ajudar a lembrar onde está seu último commit, você pode tecnicamente fazer algo tão simples quanto isto:
$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master
Agora, você pode usar a referência head que você acabou de criar em vez do valor SHA-1 nos seus comandos Git:
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Nós não encorajamos você a editar diretamente arquivos de referência.
O Git provê um comando mais seguro para fazer isso se você quiser atualizar uma referência, chamado update-ref
:
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
Isto é o que uma branch é basicamente: uma simples referência para a cabeça de uma linha de trabalho. Para criar uma branch no segundo commit, você pode fazer isto:
$ git update-ref refs/heads/test cac0ca
Sua branch irá conter apenas o trabalho a partir desse commit:
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
Agora, seu banco de dados do Git conceitualmente aparenta ser algo assim:
Quando você executa comandos como git branch (nome da branch)
, o Git basicamente executa esse comando update-ref
para adicionar o SHA-1 do último commit da branch que você está em qualquer nova referência que você quer criar.
A HEAD
A questão agora é, quando você executa git branch (nome da branch)
, como o Git sabe o SHA-1 do último commit?
A resposta é o arquivo HEAD.
O arquivo HEAD é uma referência simbólica para a branch que você está no momento. Queremos dizer por referência simbólica que, ao contrário de uma referência normal, em geral ela não contém um valor de um SHA-1, mas um ponteiro para outra referência. Se você olhar para o arquivo, normalmente você verá algo como isto:
$ cat .git/HEAD
ref: refs/heads/master
Se você executar git checkout test
, o Git atualizará o arquivo de forma que ele ficará assim:
$ cat .git/HEAD
ref: refs/heads/test
Quando você executa git commit
, ele cria um objeto commit, especificando como pai desse objeto commit o valor do SHA-1 que a referência contida em HEAD aponta.
Você pode alterar manualmente esse arquivo mas, novamente, um comando mais seguro existe para fazer isso: symbolic-ref
.
Você pode ler esse arquivo de sua HEAD através deste comando:
$ git symbolic-ref HEAD
refs/heads/master
Você também pode definir o valor de HEAD:
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
Você não pode definir o valor de uma referência simbólica fora do estilo refs:
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
Tags
Nós acabamos de falar sobre os três principais tipos de objetos, mas existe também um quarto. O objeto tag é bem parecido com um objeto commit, ele contém um tagger, a data, a mensagem, e uma referência. A principal diferença é que um objeto tag geralmente aponta para um commit em vez de uma tree. Ele é bem parecido com uma referência do tipo branch, mas ele nunca se move - ele sempre aponta para o mesmo commit mas dá a ele um nome mais amigável.
Como discutimos em [ch02-git-basics], exitem dois tipos de tags: anotada e leve. Você pode criar uma tag leve executando algo assim:
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Isso é tudo que uma tag leve é - uma referência que nunca se move.
Entretanto, uma tag anotada é mais complexa.
Se você criar uma tag anotada, o Git cria um objeto tag e então escreve uma referência que aponta para ele em vez de apontar diretamente para o commit.
Você pode ver isso criando uma tag anotada (-a
especifica que é uma tag anotada):
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'
Aqui está o valor SHA-1 do objeto que foi criado:
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Agora, execute o comando cat-file
no valor SHA-1:
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
test tag
Note que o item object
aponta ao SHA-1 do commit que você criou a tag.
Note também que ele não precisa apontar para um commit; você pode adicionar qualquer objeto do Git.
No código-fonte do Git, por exemplo, o mantenedor adicionou sua chave GPG pública como um objeto blob e então criou uma tag para ele.
Você pode ver a chave pública executando isto em um clone do repositório do Git:
$ git cat-file blob junio-gpg-pub
O repositório do kernel Linux também tem um objeto tag que não aponta para um commit: a primeira tag criada aponta para a tree inicial da importação do código-fonte.
Remotes
O terceiro tipo de referência que você verá é o remote (remoto).
Se você adicionar um remote e fizer um push para ele, o Git armazenará o valor que você fez o push para ele para cada branch no diretório refs/remotes
.
Por exemplo, você pode adicionar um remote chamado origin
e fazer o push da sua master
para ele:
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
Então, você pode ver onde a branch master
no remote origin
estava na última vez que você se comunicou com o servidor, olhando o arquivo refs/remotes/origin/master
:
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Remotes se diferenciam de branches (referências em refs/heads
) principalmente pelo fato de normalmente serem somente-leitura.
Você pode executar git checkout
para um remote, mas o Git não irá apotar a HEAD para um, então você nunca irá atualizá-la com um commando commit
.
O Git gerencia elas como marcadores para a último estado conhecido de onde essas branches estavam nos servidores.