-
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.6 Git Internals (Por Dentro do Git) - Protocolos de Transferência
Protocolos de Transferência
O Git pode transferir dados entre dois repositórios de duas maneiras principais: pelo protocolo “dumb” e pelo protocolo “smart”. Esta seção cobrirá rapidamente como esses dois protocolos principais operam.
O Protocolo Dumb
Se você estiver configurando um repositório para ser servido somente para leitura via HTTP, provavelmente será usado o protocolo dumb.
Esse protocolo é chamado de “dumb” porque não exige nenhum código específico do Git no lado do servidor durante o processo de transporte; o processo de fetch é uma série de requisições HTTP GET, nas quais o cliente pode presumir a organização do repositório Git no servidor.
|
Note
|
Hoje em dia o protocolo burro é muito raramente usado. É difícil o tornar seguro ou torná-lo privado, de forma em que a maioria dos hosts Git (ambos em servidores baseados em nuvem e os locais/físicos/on-premises) se recusarão a usá-lo. Em geral, recomenda-se usar o protocolo smart, que descreveremos um pouco mais adiante. |
Vamos acompanhar o processo de http-fetch para a biblioteca do simplegit:
$ git clone http://server/simplegit-progit.git
A primeira coisa que esse comando faz é baixar o arquivo info/refs.
Esse arquivo é escrito pelo comando update-server-info, e é por isso que você precisa habilitar isso como um hook post-receive para que o transporte por intermédio HTTP funcione adequadamente:
=> GET info/refs
ca82a6dff817ec66f44342007202690a93763949 refs/heads/master
Agora você tem uma lista das referências remotas e seus SHA-1s. Depois, você procura pelo que é a referência da HEAD, para que você saiba do que deve fazer o checkout quando você terminar:
=> GET HEAD
ref: refs/heads/master
Você precisará fazer o checkout do branch master quando você tiver concluído o processo.
Neste ponto, você está pronto para iniciar o processo da caminhada.
Como seu ponto de partida é o objeto commit ca82a6 que você viu no arquivo info/refs, comece buscando-o:
=> GET objects/ca/82a6dff817ec66f44342007202690a93763949
(179 bytes of binary data)
Você recebe um objeto de volta – ele está em formato loose no servidor e foi obtido por uma requisição HTTP GET estática. Você pode usar a descompressão dele via zlib, remover o cabeçalho e dar uma olhada ao conteúdo do commit:
$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
Change version number
Em seguida, você tem mais dois objetos para recuperar – cfda3b, a árvore de conteúdo para a qual aponta o commit que acabamos de obter, e 085bb3, o commit pai:
=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
(179 bytes of data)
Isso te devolve ao seu próximo objeto de commit. Pegue o objeto da tree (árvore):
=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
(404 - Not Found)
Opa – parece que esse objeto árvore não está em formato loose no servidor, portanto você recebe uma resposta 404. Há alguns motivos para isso – o objeto pode estar em um repositório alternativo ou em um packfile desse repositório. O Git verifica por qualquer alternativo que primeiro for listado:
=> GET objects/info/http-alternates
(empty file)
Se isso retornar uma lista de URLs alternativas, o Git procurará ali arquivos loose e packfiles – esse é um bom mecanismo para que projetos derivados uns dos outros compartilhem objetos no disco.
Contudo, como nenhum alternativo é listado neste caso, seu objeto deve estar num arquivo de packfile.
Para ver quais packfiles estão disponíveis nesse servidor, você precisa obter o arquivo objects/info/packs, que contém uma lista deles (também gerada por update-server-info):
=> GET objects/info/packs
P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
Há apenas um arquivo de packfile no servidor, então seu objeto está obviamente nele, mas você checará o arquivo de índice para ter certeza disso. Isso também é útil quando há vários packfiles no servidor, pois permite descobrir qual deles contém o objeto necessário:
=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
(4k of binary data)
Agora que você tem o índice do packfile, pode verificar se o objeto está nele – o índice lista os SHA-1 dos objetos contidos no packfile e os deslocamentos até esses objetos. O seu objeto se localiza lá, sendo assim então vá em frente e obtenha o arquivo de packfile inteiramente:
=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
(13k of binary data)
Você detém de um objeto à sua árvore, então, assim, continue a seguir seu trajeto caminhando aos seus referidos commits.
Eles todos também estão dentro do packfile em que você acabou de baixar, então você não precisa fazer mais requisições para o seu servidor.
O Git faz o checkout de uma cópia de trabalho do branch master que foi apontado pela referência da HEAD que você baixou logo mais ao seu início.
O Protocolo Smart
O protocolo dumb é simples, mas um pouco ineficiente, e não permite gravar dados do cliente no servidor. O protocolo smart é o método mais comum de transferência de dados, mas exige na extremidade remota um processo que compreenda o Git – ele pode ler os dados locais, descobrir o que o cliente possui e necessita e gerar um packfile personalizado. Há dois conjuntos de processos para transferir dados: um par para enviar dados e outro para baixá-los.
Enviando Dados
Para enviar dados para um processo remoto, o Git usa os processos send-pack e receive-pack.
O processo send-pack é executado no cliente e se conecta a um processo receive-pack no lado remoto.
SSH
Por exemplo, digamos que você execute git push origin master em seu projeto, e a origin é definida como uma URL que usa o protocolo de SSH.
O Git aciona o processo send-pack, que inicia uma conexão via SSH com seu servidor.
Ele tenta executar um comando no servidor remoto por meio de uma chamada num processo provindo pelo respectivo SSH de modo em que se pareça com algo mais como desta exata assimilação disposta que venha logo a seguir logo abaixo, em seguida:
$ ssh -x git@server "git-receive-pack 'simplegit-progit.git'"
00a5ca82a6dff817ec66f4437202690a93763949 refs/heads/master□report-status \
delete-refs side-band-64k quiet ofs-delta \
agent=git/2:2.1.1+github-607-gfba4028 delete-refs
0000
O comando git-receive-pack responde imediatamente com uma linha para cada referência que possui naquele momento – nesse caso, apenas a branch master e seu SHA-1.
A primeira linha também contém uma lista das capacidades do servidor (aqui, report-status, delete-refs, e algumas outras mais à sua exatidão, incluindo nelas até mesmo o identificador do cliente).
Os dados são transmitidos em blocos. Cada bloco começa com um valor hexadecimal de 4 caracteres que especifica seu comprimento (incluindo os 4 bytes do próprio tamanho). Os blocos geralmente contêm uma única linha de dados e um avanço de linha ao final. Seu primeiro bloco começa com 00a5, que é 165 em hexadecimal, indicando que o bloco tem 165 bytes. O próximo trecho é 0000, o que significa que o servidor concluiu a listagem de suas próprias referências.
Agora que ele conhece o estado do servidor, seu processo de send-pack determina quais são os commits que ele tem e por fim quais são eles os quais o servidor não detém consigo em partes correspondentes nos referidos termos presentes nas suas referenciadas partes da parte provinda dele próprio, que se restam ali, com as faltas destes.
Para cada referência que o push atualizará, o processo send-pack transmite essa informação ao processo receive-pack.
Por exemplo, se você estiver atualizando o branch master e adicionando um branch experiment, a resposta send-pack pode ficar parecida com isso:
0076ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 \
refs/heads/master report-status
006c0000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d \
refs/heads/experiment
0000
O Git envia uma linha para cada referência que você está atualizando, com o comprimento da linha, o SHA-1 antigo, o novo SHA-1 e a referência que está sendo atualizada.
A primeira linha também contém as capacidades do cliente.
O valor SHA-1 formados de todos os termos contendo apenas os números constituídos em '0’s significa que não havia nada ali antes – porque você está adicionando a referência de experiment.
Se você estivesse excluindo uma referência, veria o oposto: apenas '0’s do lado direito.
Em seguida, o cliente envia um packfile com todos os objetos que o servidor ainda não possui. Por fim, o servidor responde com uma indicação de sucesso (ou falha):
000eunpack ok
HTTP(S)
Esse processo é praticamente o mesmo via HTTP, embora a negociação inicial seja um pouco diferente. A conexão é iniciada com esta requisição:
=> GET http://server/simplegit-progit.git/info/refs?service=git-receive-pack
001f# service=git-receive-pack
00ab6c5f0e45abd7832bf23074a333f739977c9e8188 refs/heads/master□report-status \
delete-refs side-band-64k quiet ofs-delta \
agent=git/2:2.1.1~vmg-bitmaps-bugaloo-608-g116744e
0000
Esse é o fim da primeira troca de informações entre cliente e servidor.
O cliente então faz outra requisição, dessa vez um POST, com os dados fornecidos pelo send-pack.
=> POST http://server/simplegit-progit.git/git-receive-pack
A requisição POST inclui a saída do send-pack e o packfile como sua carga útil.
O servidor então indica sucesso ou falha com a sua correspondente resposta HTTP que a responde.
Lembre-se de que o protocolo HTTP ainda pode encapsular esses dados em uma codificação de transferência em blocos.
Baixando (Transferindo/Downloading) Dados
Quando você baixa dados, os processos fetch-pack e upload-pack entram em ação.
O cliente inicia um processo fetch-pack, que se conecta a um processo upload-pack no lado remoto para negociar quais dados serão transferidos.
SSH
Se você está fazendo o fetch via SSH, o fetch-pack roda algo assim:
$ ssh -x git@server "git-upload-pack 'simplegit-progit.git'"
Depois que o fetch-pack se conecta, o upload-pack devolve algo semelhante a isto:
00dfca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
side-band side-band-64k ofs-delta shallow no-progress include-tag \
multi_ack_detailed symref=HEAD:refs/heads/master \
agent=git/2:2.1.1+github-607-gfba4028
003fe2409a098dc3e53539a9028a94b6224db9d6a6b6 refs/heads/master
0000
Isso é muito semelhante à resposta do receive-pack, mas as capacidades são diferentes.
Além disso, ele informa para onde HEAD aponta (symref=HEAD:refs/heads/master), permitindo ao cliente saber o que deve colocar em checkout caso se trate de um clone.
Nesse ponto, o processo fetch-pack examina os objetos que possui e responde com os objetos de que precisa, enviando “want” seguido pelo SHA-1 desejado.
Ele envia todos os objetos que já possui com “have”, seguido pelo SHA-1.
Ao final da lista, escreve “done” para fazer o processo upload-pack começar a enviar o packfile com os dados necessários:
003cwant ca82a6dff817ec66f44342007202690a93763949 ofs-delta
0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0009done
0000
HTTP(S)
A negociação inicial de uma operação de fetch requer duas requisições HTTP.
A primeira é uma requisição GET para o mesmo endpoint usado no protocolo burro:
=> GET $GIT_URL/info/refs?service=git-upload-pack
001e# service=git-upload-pack
00e7ca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
side-band side-band-64k ofs-delta shallow no-progress include-tag \
multi_ack_detailed no-done symref=HEAD:refs/heads/master \
agent=git/2:2.1.1+github-607-gfba4028
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
0000
Isso é muito semelhante a invocar git-upload-pack por uma conexão SSH, mas a segunda troca é realizada como uma requisição separada:
=> POST $GIT_URL/git-upload-pack HTTP/1.0
0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7
0032have 441b40d833fdfa93eb2908e52742248faf0ee993
0000
Novamente, este é o exato e mesmo formato que o disposto e baseador correspondido logo acima, e anteriormente. A resposta a essa requisição indica sucesso ou falha e inclui o packfile.
Resumo dos Protocolos
Esta seção contém uma visão geral muito básica dos protocolos de transferência.
O protocolo inclui muitos outros recursos, como as capacidades multi_ack ou side-band, mas abordá-las está fora do escopo deste livro.
Tentamos dar uma ideia do fluxo geral entre cliente e servidor; se precisar de mais detalhes, provavelmente será melhor consultar o código-fonte do Git.