-
1. Démarrage rapide
-
2. Les bases de Git
-
3. Les branches avec Git
-
4. Git sur le serveur
- 4.1 Protocoles
- 4.2 Installation de Git sur un serveur
- 4.3 Génération des clés publiques SSH
- 4.4 Mise en place du serveur
- 4.5 Démon (Daemon) Git
- 4.6 HTTP intelligent
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Git hébergé
- 4.10 Résumé
-
5. Git distribué
-
6. GitHub
-
7. Utilitaires Git
- 7.1 Sélection des versions
- 7.2 Indexation interactive
- 7.3 Remisage et nettoyage
- 7.4 Signer votre travail
- 7.5 Recherche
- 7.6 Réécrire l’historique
- 7.7 Reset démystifié
- 7.8 Fusion avancée
- 7.9 Rerere
- 7.10 Déboguer avec Git
- 7.11 Sous-modules
- 7.12 Empaquetage (bundling)
- 7.13 Replace
- 7.14 Stockage des identifiants
- 7.15 Résumé
-
8. Personnalisation de Git
- 8.1 Configuration de Git
- 8.2 Attributs Git
- 8.3 Crochets Git
- 8.4 Exemple de politique gérée par Git
- 8.5 Résumé
-
9. Git et les autres systèmes
- 9.1 Git comme client
- 9.2 Migration vers Git
- 9.3 Résumé
-
10. Les tripes de Git
- 10.1 Plomberie et porcelaine
- 10.2 Les objets de Git
- 10.3 Références Git
- 10.4 Fichiers groupés
- 10.5 La refspec
- 10.6 Les protocoles de transfert
- 10.7 Maintenance et récupération de données
- 10.8 Les variables d’environnement
- 10.9 Résumé
-
A1. Annexe A: Git dans d’autres environnements
- A1.1 Interfaces graphiques
- A1.2 Git dans Visual Studio
- A1.3 Git dans Visual Studio Code
- A1.4 Git dans IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git dans Sublime Text
- A1.6 Git dans Bash
- A1.7 Git dans Zsh
- A1.8 Git dans PowerShell
- A1.9 Résumé
-
A2. Annexe B: Embarquer Git dans vos applications
- A2.1 Git en ligne de commande
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Commandes Git
- A3.1 Installation et configuration
- A3.2 Obtention et création des projets
- A3.3 Capture d’instantané basique
- A3.4 Création de branches et fusion
- A3.5 Partage et mise à jour de projets
- A3.6 Inspection et comparaison
- A3.7 Débogage
- A3.8 Patchs
- A3.9 Courriel
- A3.10 Systèmes externes
- A3.11 Administration
- A3.12 Commandes de plomberie
10.6 Les tripes de Git - Les protocoles de transfert
Les protocoles de transfert
Git peut transférer des données entre deux dépôts de deux façons principales : le protocole « stupide » et le protocole « intelligent ». Cette section fait un tour d’horizon du fonctionnement de ces deux protocoles.
Le protocole stupide
Si vous mettez en place un dépôt à accéder en lecture seule sur HTTP, c’est vraisemblablement le protocole stupide qui sera utilisé. Ce protocole est dit « stupide », car il ne nécessite aucun code spécifique à Git côté serveur durant le transfert ; le processus de récupération est une série de requêtes GET, où le client devine la structure du dépôt Git présent sur le serveur.
Note
|
Le protocole stupide est rarement utilisé ces derniers temps. Il est difficile de le rendre sécurisé ou privé, et donc la plupart des hébergeurs Git (sur le cloud ou sur serveur dédié) refusent de l’utiliser. On conseille généralement d’utiliser le protocole intelligent, qui est décrit plus loin. |
Suivons le processus http-fetch
pour la bibliothèque simplegit :
$ git clone https://server/simplegit-progit.git
La première chose que fait cette commande est de récupérer le fichier info/refs
.
Ce fichier est écrit par la commande update-server-info
et c’est pour cela qu’il faut activer le crochet post-receive
, sinon le transfert HTTP ne fonctionnera pas correctement :
> GET info/refs
ca82a6dff817ec66f44342007202690a93763949 refs/heads/master
On possède maintenant une liste des références distantes et empreintes SHA-1. Ensuite, on regarde vers quoi pointe HEAD, pour savoir sur quelle branche se placer quand on aura fini :
> GET HEAD
ref: refs/heads/master
On aura besoin de se placer sur la branche master
, quand le processus sera terminé.
On est maintenant prêt à démarrer le processus de parcours.
Puisque votre point de départ est l’objet commit ca82a6
que vous avez vu dans le fichier info/refs
, vous commencez par le récupérer :
> GET objects/ca/82a6dff817ec66f44342007202690a93763949
(179 bytes of binary data)
Vous obtenez un objet, cet objet est dans le format brut sur le serveur et vous l’avez récupéré à travers une requête HTTP GET statique. Vous pouvez le décompresser avec zlib, ignorer l’en-tête et regarder le contenu du 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
changed the version number
Puis, vous avez deux autres objets supplémentaires à récupérer : cfda3b
qui est l’arbre du contenu sur lequel pointe le commit que nous venons de récupérer et 085bb3
qui est le commit parent :
> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
(179 bytes of data)
Cela vous donne le prochain objet commit. Récupérez l’objet arbre :
> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
(404 - Not Found)
Oups, on dirait que l’objet arbre n’est pas au format brut sur le serveur, vous obtenez donc une réponse 404. On peut en déduire certaines raisons : l’objet peut être dans un dépôt suppléant ou il peut être dans un fichier groupé de ce dépôt. Git vérifie la liste des dépôts suppléants d’abord :
> GET objects/info/http-alternates
(empty file)
Si la réponse contenait une liste d’URL suppléantes, Git aurait cherché les fichiers bruts et les fichiers groupés à ces emplacements, c’est un mécanisme sympathique pour les projets qui ont dérivé d’un autre pour partager les objets sur le disque.
Cependant, puisqu’il n’y a pas de suppléants listés dans ce cas, votre objet doit se trouver dans un fichier groupé.
Pour voir quels fichiers groupés sont disponibles sur le serveur, vous avez besoin de récupérer le fichier objects/info/packs
, qui en contient la liste (générée également par update-server-info
) :
> GET objects/info/packs
P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
Il n’existe qu’un seul fichier groupé sur le serveur, votre objet se trouve évidemment dedans, mais vous allez tout de même vérifier l’index pour être sûr. C’est également utile lorsque vous avez plusieurs fichiers groupés sur le serveur, vous pouvez donc voir quel fichier groupé contient l’objet dont vous avez besoin :
> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
(4k of binary data)
Maintenant que vous avez l’index du fichier groupé, vous pouvez vérifier si votre objet est bien dedans car l’index liste les empreintes SHA-1 des objets contenus dans ce fichier groupé et des emplacements de ces objets. Votre objet est là, allez donc récupérer le fichier groupé complet :
> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
(13k of binary data)
Vous avez votre objet arbre, vous continuez donc le chemin des commits.
Ils sont également tous contenus dans votre fichier groupé que vous venez de télécharger, vous n’avez donc pas d’autres requêtes à faire au serveur.
Git récupère une copie de travail de votre branche master
qui été référencée par HEAD que vous avez téléchargé au début.
Le protocole intelligent
Le protocole stupide est simple mais un peu inefficace, et il ne permet pas l’écriture de données du client au serveur. Le protocole intelligent est une méthode plus habituelle pour transférer des données, mais elle nécessite l’exécution sur le serveur d’un processus qui connaît Git : il peut lire les données locales et déterminer ce que le client a ou ce dont il a besoin pour générer un fichier groupé personnalisé pour lui. Il y a deux ensembles d’exécutables pour transférer les données : une paire pour téléverser des données et une paire pour en télécharger.
Téléverser des données
Pour téléverser des données vers un exécutable distant, Git utilise les exécutables send-pack
et receive-pack
.
L’exécutable send-pack
tourne sur le client et se connecte à l’exécutable receive-pack
du côté serveur.
======= SSH
Par exemple, disons que vous exécutez git push origin master
dans votre projet et origin
est défini comme une URL qui utilise le protocole SSH.
Git appelle l’exécutable send-pack
, qui initialise une connexion à travers SSH vers votre serveur.
Il essaye d’exécuter une commande sur le serveur distant via un appel SSH qui ressemble à :
$ 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
La commande git-receive-pack
répond immédiatement avec une ligne pour chaque référence qu’elle connaît actuellement, dans ce cas, uniquement la branche master
et son empreinte SHA-1.
La première ligne contient également une liste des compétences du serveur (ici : report-status
, delete-refs
et quelques autres, dont l’identifiant du client).
Chaque ligne commence avec une valeur hexadécimale sur 4 caractères, spécifiant le reste de la longueur de la ligne.
La première ligne, ici, commence avec 00a5
, soit 165 en hexadécimal, ce qui signifie qu’il y a 165 octets restants sur cette ligne.
La ligne d’après est 0000
, signifiant que le serveur a fini de lister ses références.
Maintenant qu’il connait l’état du serveur, votre exécutable send-pack
détermine quels commits il a de plus que le serveur.
L’exécutable send-pack
envoie alors à l’exécutable receive-pack
les informations concernant chaque référence que cette commande push
va mettre à jour.
Par exemple, si vous mettez à jour la branche master
et ajoutez la branche experiment
, la réponse de send-pack
ressemblera à quelque chose comme :
0076ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 \
refs/heads/master report-status
006c0000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d \
refs/heads/experiment
0000
Git envoie une ligne pour chaque référence que l’on met à jour avec l’ancien SHA-1, le nouveau SHA-1 et la référence en train d’être mise à jour.
La première ligne contient également les compétences du client.
La valeur SHA-1 remplie de '0' signifie qu’il n’y avait rien à cet endroit avant, car vous êtes en train d’ajouter la référence experiment
.
Si vous étiez en train de supprimer une référence, vous verriez l’opposé : que des '0' du côté droit.
Puis, le client téléverse un fichier groupé de tous les objets que le serveur n’a pas encore. Finalement, le serveur répond avec une indication de succès (ou d’échec) :
000eunpack ok
HTTP(S)
Le processus est quasiment le même avec HTTP, à une différence près lors de l’établissement de la liaison (handshaking). La connection est amorcée avec cette requête :
> GET https://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
Ceci est la fin du premier échange client-serveur.
Le client fait alors une nouvelle requête, qui est cette fois un POST
, avec les données fournies par git-upload-pack
.
> POST https://server/simplegit-progit.git/git-receive/pack
La requête POST
contient la sortie de send-pack
et le fichier groupé.
Enfin, le serveur indique le succès ou l’échec dans sa réponse HTTP.
Gardez en tête que le protocole HTTP peut ensuite envelopper ces données dans un encodage de transfert par paquets.
Téléchargement des données
Lorsque vous téléchargez des données, les exécutables fetch-pack
et upload-pack
entrent en jeu.
Le client démarre un processus fetch-pack
qui se connecte à un processus upload-pack
du côté serveur pour négocier les données qui seront téléchargées.
SSH
Si vous téléchargez par SSH, fetch-pack
fait quelque chose comme ceci :
$ ssh -x git@server "git-upload-pack 'simplegit-progit.git'"
Une fois fetch-pack
connecté, upload-pack
lui répond quelque chose du style :
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
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
0000
Ceci est très proche de la réponse de receive-pack
mais les compétences sont différentes.
En plus, il envoie ce qui est pointé par HEAD (symref=HEAD:refs/heads/master
), afin que le client sache ce qu’il doit récupérer dans le cas d’un clone.
À ce moment, fetch-pack
regarde les objets qu’il a et répond avec la liste des objets dont il a besoin en envoyant « want » (vouloir) suivi du SHA-1 qu’il veut.
Il envoie tous les objets qu’il a déjà avec « have » suivi du SHA-1.
À la fin de la liste, il écrit « done » (fait) pour inciter l’exécutable upload-pack
à commencer à envoyer le fichier groupé des données demandées :
003cwant ca82a6dff817ec66f44342007202690a93763949 ofs-delta
0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0009done
0000
HTTP(S)
L’établissement de la liaison pour une opération de téléchargement nécessite deux requêtes HTTP.
La première est un GET
vers le même point que dans le protocole stupide :
> 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
Ceci ressemble beaucoup à un appel à git-upload-pack
par une connection SSH, mais le deuxième échange est fait dans une requête séparée :
> POST $GIT_URL/git-upload-pack HTTP/1.0
0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7
0032have 441b40d833fdfa93eb2908e52742248faf0ee993
0000
Une fois de plus, ce format est le même que plus haut. La réponse à cette requête indique le succès ou l’échec, et contient le fichier groupé.
Résumé sur les protocoles
Cette section contient un survol basique des protocoles de transfert.
Les protocoles contiennent de nombreuses autres fonctionalités,
comme les compétences multi_ack
ou side-band
,
mais leur étude est hors du sujet de ce livre.
Nous avons essayé de vous donner une idée générale des échanges entre client et serveur.
Si vous souhaitez en connaître davantage, vous devrez probablement jeter un œil sur le code source de Git.