-
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
A2.2 Annexe B: Embarquer Git dans vos applications - Libgit2
Libgit2
Une autre option Ă votre disposition consiste Ă utiliser Libgit2. Libgit2 est une mise en Ćuvre de Git sans dĂ©pendance externe, qui se focalise sur une interface de programmation agrĂ©able Ă utiliser depuis dâautres programmes. Vous pouvez la trouver sur https://libgit2.github.com.
Voyons dâabord Ă quoi ressemble lâAPI C. En voici un tour rapide :
// Ouvrir un depot
git_repository *repo;
int error = git_repository_open(&repo, "/path/to/repository");
// Dereferencer HEAD vers un commit
git_object *head_commit;
error = git_revparse_single(&head_commit, repo, "HEAD^{commit}");
git_commit *commit = (git_commit*)head_commit;
// afficher quelques proprietes du commit
printf("%s", git_commit_message(commit));
const git_signature *author = git_commit_author(commit);
printf("%s <%s>\n", author->name, author->email);
const git_oid *tree_id = git_commit_tree_id(commit);
// Nettoyer
git_commit_free(commit);
git_repository_free(repo);
Les deux premiÚres lignes ouvrent un dépÎt Git.
Le type git_repository
représente un identificateur de dépÎt avec un cache en mémoire.
Câest la mĂ©thode la plus simple, quand vous connaissez le chemin exact vers le rĂ©pertoire de travail ou le rĂ©pertoire .git
dâun dĂ©pĂŽt.
Il y a aussi git_repository_open_ext
qui inclut des options pour chercher, git_clone
et ses dĂ©clinaisons pour crĂ©er un clone local dâun dĂ©pĂŽt distant et git_repository_init
pour créer un dépÎt entiÚrement nouveau.
Le second bloc de code utilise la syntaxe « rev-parse » (voir Références de branches pour plus de détails) pour obtenir le commit sur lequel HEAD peut pointer.
Le type retourné est un pointeur sur git_object
qui représente quelque chose qui existe dans la base de données des objets de Git pour un dépÎt.
git_object
est en fait une type « parent » pour diffĂ©rentes sortes dâobjets ; lâagencement en mĂ©moire de chacun de ces types « enfants » est identique Ă celui de git_object
, donc on peut forcer la conversion vers le type désiré en toute sécurité.
Dans notre cas, git_object_type(commit)
retournerait GIT_OBJ_COMMIT
, il est donc permis de le convertir en un pointeur de git_commit
.
Le bloc suivant montre comment accĂ©der aux propriĂ©tĂ©s dâun commit.
La derniĂšre ligne utilise un type git_oid
 ; câest la reprĂ©sentation dâune empreinte SHA-1 dans Libgit2.
De cet exemple, une structure générale commence à émerger :
-
Si vous déclarez un pointeur et que vous en passez une référence dans un appel à Libgit2, cet appel renverra vraisemblablement un code de retour entier. Une valeur
0
indique un succÚs ; toute valeur négative est une erreur. -
Si Libgit2 peuple un pointeur pour vous, vous ĂȘtes responsable de sa libĂ©ration.
-
Si Libgit2 retourne un pointeur
const
aprĂšs un appel, vous nâavez pas besoin de le libĂ©rer mais il deviendra invalide quand lâobjet qui le possĂšde sera lui-mĂȘme libĂ©rĂ©. -
Ăcrire en C est un exercice plutĂŽt douloureux.
Cette derniĂšre remarque signifie quâil est fort peu probable que vous Ă©crirez du C pour utiliser Libgit2. Heureusement, il existe un certain nombre de liaisons vers dâautres langages qui rendent plus facile lâinteraction avec des dĂ©pĂŽts Git depuis votre environnement et votre langage spĂ©cifiques. Voyons lâexemple ci-dessus rĂ©Ă©crit en utilisant le portage Ruby de Libgit2, appelĂ© Rugged et qui peut ĂȘtre trouvĂ© sur https://github.com/libgit2/rugged.
repo = Rugged::Repository.new('path/to/repository')
commit = repo.head.target
puts commit.message
puts "#{commit.author[:name]} <#{commit.author[:email]}>"
tree = commit.tree
Tout de suite, le code est moins verbeux.
Déjà , Rugged utilise des exceptions ; il peut lever ConfigError
ou ObjectE
pour signaler des conditions dâerreur.
Ensuite, il nây a pas de libĂ©ration explicite des ressources, puisque Ruby utilise un ramasse-miettes.
Voyons un exemple légÚrement plus compliqué : créer un commit à partir de rien.
blob_id = repo.write("Blob contents", :blob) # (1)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(:path => 'newfile.txt', :oid => blob_id) # (2)
sig = {
:email => "bob@example.com",
:name => "Bob User",
:time => Time.now,
}
commit_id = Rugged::Commit.create(repo,
:tree => index.write_tree(repo), # (3)
:author => sig,
:committer => sig, # (4)
:message => "Add newfile.txt", # (5)
:parents => repo.empty? ? [] : [ repo.head.target ].compact, # (6)
:update_ref => 'HEAD', # (7)
)
commit = repo.lookup(commit_id) # (8)
-
CrĂ©er un nouveau blob qui contient le contenu dâun nouveau fichier.
-
Peupler lâindex avec lâarbre du commit HEAD et ajouter le nouveau fichier sous le chemin
newfile.txt
. -
Ceci crĂ©e un nouvel arbre dans la base de donnĂ©es des objets et lâutilise pour le nouveau commit.
-
Nous utilisons la mĂȘme signature pour lâauteur et le validateur.
-
Le message de validation.
-
Ă la crĂ©ation dâun commit, il faut spĂ©cifier les parents du nouveau commit. on utilise le sommet de HEAD comme parent unique.
-
Rugged (et Libgit2) peuvent en option mettre à jour la référence lors de la création du commit.
-
La valeur retournée est une empreinte SHA-1 du nouvel objet commit que vous pouvez alors utiliser pour obtenir un objet
Commit
.
Le code Ruby est joli et propre, mais comme Libgit2 rĂ©alise le gros du travail, il tourne aussi plutĂŽt rapidement. Si vous nâĂȘtes pas rubyiste, nous aborderons dâautres portages dans Autres liaisons.
Fonctionnalité avancée
Libgit2 a certaines capacitĂ©s qui ne sont pas disponibles dans Git natif. Un exemple est la possibilitĂ© de greffons : Libgit2 vous permet de fournir des services « dâarriĂšre-plan » pour diffĂ©rents types dâopĂ©rations, pour vous permettre de stocker les choses dâune maniĂšre diffĂ©rente de Git. Libgit2 autorise des services dâarriĂšre-plan pour la configuration, le stockage des rĂ©fĂ©rences et la base de donnĂ©es dâobjets, entre autres.
Voyons comment cela fonctionne. Le code ci-dessous est empruntĂ© Ă un ensemble dâexemples de services fourni par lâĂ©quipe Libgit2 (qui peut ĂȘtre trouvĂ© sur https://github.com/libgit2/libgit2-backends). Voici comment un service dâarriĂšre-plan pour une base de donnĂ©es dâobjets peut ĂȘtre crĂ©Ă©e :
git_odb *odb;
int error = git_odb_new(&odb); // (1)
git_odb_backend *my_backend;
error = git_odb_backend_mine(&my_backend, /*âŠ*/); // (2)
error = git_odb_add_backend(odb, my_backend, 1); // (3)
git_repository *repo;
error = git_repository_open(&repo, "some-path");
error = git_repository_set_odb(odb); // (4)
(Notez que les erreurs sont capturées, mais ne sont pas gérées. Nous espérons que votre code est meilleur que le nÎtre).
-
Initialise une enveloppe dâinterface dâune base de donnĂ©es dâobjets vide (ODB) qui agit comme un conteneur pour les tĂąches de fond qui feront le vrai travail.
-
Initialise une tĂąche de fond ODB.
-
Ajoute la tĂąche de fond dans lâenveloppe.
-
Ouvre le dépÎt et le paramÚtre pour utiliser notre ODB pour rechercher les objets.
Mais quâest-ce que ce git_odb_backend_mine
 ?
HĂ© bien, câest le constructeur de notre propre rĂ©alisation de lâODB et nous pouvons la faire comme nous voulons tant que la structure git_odb_backend
est correctement renseignée.
Voici à quoi elle pourrait ressembler :
typedef struct {
git_odb_backend parent;
// Some other stuff
void *custom_context;
} my_backend_struct;
int git_odb_backend_mine(git_odb_backend **backend_out, /*âŠ*/)
{
my_backend_struct *backend;
backend = calloc(1, sizeof (my_backend_struct));
backend->custom_context = âŠ;
backend->parent.read = &my_backend__read;
backend->parent.read_prefix = &my_backend__read_prefix;
backend->parent.read_header = &my_backend__read_header;
// âŠ
*backend_out = (git_odb_backend *) backend;
return GIT_SUCCESS;
}
La contrainte la plus subtile ici est que le premier membre de my_backend_structure
doit ĂȘtre une structure git_odb_backend
 ; cela assure que la disposition en mĂ©moire correspond Ă ce quâattend le code de Libgit2.
Le reste est totalement arbitraire ; cette structure peut ĂȘtre aussi grande ou petite que nĂ©cessaire.
La fonction dâinitialisation alloue de la mĂ©moire pour la structure, initialise le contexte spĂ©cifique, puis remplit les membres de la structure parent
quâelle supporte.
Référez-vous au fichier include/git2/sys/odb_backend.h
dans les sources de Libgit2 pour lâintĂ©gralitĂ© des signatures dâappels ; votre cas dâutilisation particulier vous permettra de dĂ©terminer lesquelles vous souhaitez supporter.
Autres liaisons
Libgit2 dispose de liaisons vers de nombreux langages.
Nous allons montrer ici un petit exemple en utilisant quelques-unes des liaisons les plus abouties au moment de la rédaction de ce livre ; des bibliothÚques existent pour de nombreux autres langages qui incluent C++, Go, Node.js, Erlang et la JVM à différents stades de maturité.
La collection officielle de liaisons peut ĂȘtre trouvĂ©e en parcourant les dĂ©pĂŽts sur https://github.com/libgit2.
Le code que nous allons écrire retournera le message de validation du commit finalement pointé par HEAD (git log -1
en quelque sorte).
LibGit2Sharp
Si vous Ă©crivez une application .NET ou Mono, LigGit2Sharp (https://github.com/libgit2/libgit2sharp) est tout ce que vous cherchez. Les liaisons sont Ă©crites en C# et une grande attention a Ă©tĂ© portĂ©e Ă envelopper les appels directs Ă Libgit2 avec une interface de programmation naturelle en C#. Voici Ă quoi notre programme dâexemple ressemble :
new Repository(@"C:\path\to\repo").Head.Tip.Message;
Pour les applications graphiques Windows, il existe mĂȘme un paquet NuGet qui vous permettra de dĂ©marrer vos dĂ©veloppements rapidement.
objective-git
Si votre application tourne sur une plateforme Apple, vous avez de grandes chances dâutiliser Objective-C comme langage de programmation. Objective-Git (https://github.com/libgit2/objective-git) est le nom de la liaison de Libgit2 pour cet environnement. Le programme dâexemple ressemble Ă ceci :
GTRepository *repo =
[[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"] error:NULL];
NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message];
Objective-git est totalement interopĂ©rable avec Swift, donc nâayez crainte si vous avez abandonnĂ© Objective-C.
pygit2
La liaison avec Libgit2 en Python sâappelle Pygit2 et elle peut ĂȘtre trouvĂ©e sur https://www.pygit2.org/. Notre programme dâexemple :
pygit2.Repository("/chemin/du/depot") # ouvre le depot
.head # recupere la branche en cours
.peel(pygit2.Commit) # descend au commit
.message # lit le message
Pour aller plus loin
Bien sĂ»r, un traitement complet des capacitĂ©s de Libgit2 est hors du cadre de ce livre. Si vous souhaitez plus dâinformation sur Libgit2 elle-mĂȘme, la documentation de programmation se trouve sur https://libgit2.github.com/libgit2 et un ensemble de guides sur https://libgit2.github.com/docs. Pour les autres liaisons, cherchez dans le README et dans les tests ; il y a souvent des petits didacticiels et des pointeurs sur dâautres documents.