-
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.3 Git Internals (Por Dentro do Git) - Referências do Git
Referências do Git
Se você estivesse interessado em ver o histórico do seu repositório a partir de um commit, por exemplo, 1a410e, você poderia executar algo como git log 1a410e para exibir esse histórico, mas você ainda precisaria se lembrar de que 1a410e é o commit que você quer usar como o ponto de partida para esse histórico.
Em vez disso, seria mais fácil se você tivesse um arquivo onde pudesse armazenar esse valor SHA-1 sob um nome simples, de forma que pudesse usar esse nome simples em vez do valor SHA-1 bruto.
No Git, esses nomes simples são chamados de “referências” (references) ou “refs”; você pode encontrar os arquivos que contêm esses valores SHA-1 no diretório .git/refs.
No projeto atual, esse diretório não contém arquivos, mas contém uma estrutura simples:
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
Para criar uma nova referência que ajudará você 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 em seus comandos do Git:
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Não é recomendável editar diretamente os arquivos de referência; em vez disso, o Git fornece o comando mais seguro git update-ref para fazer isso se você quiser atualizar uma referência:
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
Isso é basicamente o que um branch no Git é: um simples ponteiro ou referência para a head de uma linha de trabalho. Para criar um branch de volta no segundo commit, você pode fazer isto:
$ git update-ref refs/heads/test cac0ca
O seu branch conterá apenas o trabalho a partir desse commit para baixo:
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Agora, o seu banco de dados do Git conceitualmente se parece com algo assim:
Quando você executa comandos como git branch <branch>, o Git basicamente executa o comando update-ref para adicionar o SHA-1 do último commit do branch em que você está, para qualquer nova referência que você deseje criar.
A HEAD
A pergunta agora é: quando você executa o comando git branch <branch>, como o Git fica sabendo do SHA-1 do último commit?
A resposta é o arquivo HEAD.
Normalmente, o arquivo HEAD é uma referência simbólica ao branch em que você está no momento. Por referência simbólica, queremos dizer que, diferente de uma referência normal, ela contém um ponteiro para outra referência.
Entretanto, em alguns casos raros, o arquivo HEAD pode conter o valor SHA-1 de um objeto do Git. Isso ocorre quando você faz o checkout de uma tag, commit ou branch remoto, o que coloca seu repositório no estado "detached HEAD" (HEAD desanexada).
Se você olhar para o arquivo, normalmente você verá algo parecido com isto:
$ cat .git/HEAD
ref: refs/heads/master
Se você executar git checkout test, o Git atualizará o arquivo para que ele se pareça com isto:
$ cat .git/HEAD
ref: refs/heads/test
Quando você executa git commit, ele cria o objeto commit, especificando o pai desse objeto de commit para ser qualquer valor SHA-1 que a referência em HEAD aponte.
Você também pode editar esse arquivo manualmente, mas, mais uma vez, existe um comando mais seguro para se fazer isso: git symbolic-ref.
Você pode ler o valor do seu HEAD através deste comando:
$ git symbolic-ref HEAD
refs/heads/master
Você também pode definir o valor da HEAD usando o mesmo comando:
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
Você não pode definir uma referência simbólica de fora do estilo das referências (refs style):
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
Tags
Acabamos de discutir os três principais tipos de objetos do Git (blobs, trees e commits), mas existe um quarto. O objeto tag é muito parecido com um objeto de commit — ele contém um tagger, uma data, uma mensagem e um ponteiro. A diferença principal é que um objeto tag normalmente aponta para um commit em vez de uma tree (árvore). Ele se parece como uma referência a um branch, mas nunca se move — ele sempre aponta para o mesmo commit, mas atribuindo um nome mais amigável a ele.
Conforme discutimos no Fundamentos do Git, existem dois tipos de tags: anotadas (annotated) e leves (lightweight). Você pode criar uma tag leve executando algo como isto:
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Isto é tudo o que uma tag leve se consiste — uma referência que nunca se move.
No entanto, uma tag anotada é mais complexa.
Se você criar uma tag anotada, o Git criará um objeto tag e depois escreverá uma referência que aponta para ela em vez de diretamente para o commit.
Você pode ver isso ao se criar uma tag anotada (usando a opção -a):
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'Test tag'
Aqui está o valor SHA-1 do objeto que ele criou:
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Agora, rode o comando git cat-file -p naquele valor do 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
Observe que a entrada do objeto aponta para o valor SHA-1 do commit que você rotulou (tagged). Observe também que ele não precisa apontar a um commit; você pode rotular qualquer tipo de objeto no Git. No código-fonte do Git, por exemplo, o mantenedor adicionou a sua chave pública GPG na forma de um objeto blob e depois o rotulou em uma tag. Você pode visualizar essa chave pública rodando isso em um clone no repositório do Git:
$ git cat-file blob junio-gpg-pub
O repositório do kernel do Linux também tem um objeto tag que não aponta a um commit — a primeira tag criada que aponta à inicial da árvore de importação do código-fonte.
Remotos (Remotes)
O terceiro tipo de referência que você verá é uma referência remota (remote reference).
Se você adicionar um remote e fizer push para ele, o Git armazenará no diretório refs/remotes, para cada branch, o valor enviado pela última vez a esse remote.
Por exemplo, você pode adicionar um remote chamado origin e fazer push do seu branch 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
Em seguida, consultando o arquivo refs/remotes/origin/master, você pode ver onde estava o branch master do remote origin na última vez em que se comunicou com o servidor:
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Referências remotas diferem das branches (nas referências a refs/heads) principalmente porque elas são consideradas do tipo somente de leitura (read-only).
Você poderá fazer o git checkout com um, mas o Git nunca referenciará a HEAD a esse referido, simbolicamente; portanto, você jamais fará as atualizações nele usando um comando de commit.
O Git as gerencia como marcadores do último estado conhecido desses branches nos respectivos servidores.