« VCS/GitDaemon » : différence entre les versions
(Page créée avec « = Préambule = == Rappel des faits, synopsis de l’épisode == Vous avez donc vu (malgré quelques soucis de mise en page) dans le numéro 101 que Git n’est pas si diffici... ») |
|||
| Ligne 114 : | Ligne 114 : | ||
pwd | pwd | ||
/home/ange/projets/projet_alpha | /home/ange/projets/projet_alpha | ||
git push ssh://git.jardin.ca/var/depots/git.jardin.ca/projets/projet_alpha.git master | git push ssh://git.jardin.ca/var/depots/git.jardin.ca/projets/projet_alpha.git master | ||
== Résumé de l’acte == | == Résumé de l’acte == | ||
Cet acte se finit donc avec de quoi faire un serveur relativement robuste pour publier vos projets et ceux de vos amis. Rappelons rapidement les commandes importantes. | Cet acte se finit donc avec de quoi faire un serveur relativement robuste pour publier vos projets et ceux de vos amis. Rappelons rapidement les commandes importantes. | ||
Dernière version du 14 novembre 2012 à 16:16
Préambule
Rappel des faits, synopsis de l’épisode
Vous avez donc vu (malgré quelques soucis de mise en page) dans le numéro 101 que Git n’est pas si difficile que ça à prendre en mains et à utiliser. Dans le précédent épisode, Max avait donc découvert (pêle-mêle) :
- les commandes liées aux commits : git add, git status, git diff, git commit, git revert ;
- les commandes liées aux branches : git branch branch, git checkout branch, git merge branch ;
- les commandes liées à la création d’un dépôt public en utilisant un serveur HTTP : git clone -bare depot depot.git, git push ;
- les commandes pour suivre un dépôt distant : git clone depot, git branch -a, git remote depot url, git fetch, git pull.
Dans celui-ci, nous verrons :
- la création d’un dépôt public avec git-daemon ;
- comment trouver un mauvais commit avec git bisect ;
- la résolution de conflits ;
- des exemples réels d’utilisation.
Il s’agit là de sujets un peu plus poussés que les précédents et d’approfondissements demandés par des lutins. À nouveau, rien de bien sorcier. Je n’ai fait que lire, tester et utiliser ce qui se trouve dans les man pages et la documentation de Git (http://www.kernel.org/pub/software/scm/git/docs/user-manual.html).
Acte 1 : git-daemon
Un dépôt sur un serveur HTTP est relativement simple à mettre en place et probablement plus pratique. Cependant, le protocole git est conçu de manière à être plus efficace en termes de performances et de fiabilité. De plus, il permet de faire un serveur de dépôts plus souple qu’avec un serveur HTTP, pratique dans le cas d’un serveur dédié à ça (enfin, à mon humble avis).
Préparation des ingrédients
Pour mettre en place ce serveur, il vous faut :
- 2 œufs ;
- 100 grammes de farine ;
- Git installé sur le serveur ;
- sshd fonctionnel sur le serveur ;
- Git installé sur le client (si, si, je vous assure).
Comme pour le dépôt sur HTTPd, il vous faut préparer le sachet prêt à l’emploi :
cd && cd projets git clone --bare projet_alpha projet_alpha.git touch projet_alpha.git/git-daemon-export-ok
Remarquez la création (via touch) du fichier git-daemon-export-ok, fichier qui, par sa présence, indique à git-daemon qu’il peut effectivement rendre accessible ce dépôt. Ce répertoire obtenu, il vous faut le copier sur votre serveur dans le répertoire qui va accueillir tous les dépôts, servir de root pour votre git-daemon.
scp -r projet_alpha.git pinpin@jardin.ca:/var/depots/
Serveur basique
Des fois, on a envie de tester rapidement un truc, faire quelque chose en 5 minutes sur un coin de table (chacun son truc) et, pour ça, il faut pouvoir mettre rapidement en place certaines choses. Dans ces cas-là donc, on ne veut pas s’embarrasser d’un régiment d’options, juste ce qu’il faut pour que ça marche.
git-daemon --base-path=/var/depots --listen=192.168.1.20
Du coup, sur le client :
cd && cd projets git clone git://server/projet_alpha Initialized empty Git repository in /home/blah/projets/projet_alpha/.git remote: Generating pack... remote: Done counting 76 objects. remote: Deltifying 76 objects... remote: 6/76) done76) done Indexing 76 objects... remote: Total 76 (delta 23), reused 70 (delta 20) 100% (76/76) done Resolving 23 deltas... 100% (23/23) done
C’est tout. Par défaut, git-daemon utilise le port 9148, et écoute sur localhost. Notez que si vous avez un support IPv6 actif, il peut refuser la connexion sur 127.0.0.1, mais l’accepter sur ::1 (allez savoir…). Notez aussi l’utilisation de git:// et non http:// lors du clonage depuis le client. L’option --base-path permet de simplifier le chemin passé dans l’URL de clonage : les clients n’ont pas à taper le chemin entier depuis la racine de votre serveur, mais simplement le chemin vers le dépôt dans votre root git-daemon. L’option --listen permet de définir une IP sur laquelle le serveur va écouter. Vous avez donc de quoi mettre un dépôt public en deux minutes.
Quelques options
Changement de port
L’option --port=?? permet d’indiquer un port différent : cette option n’est pas compatible avec l’option --inetd.
Logs
L’option --verbose rendra le serveur plus verbeux dans ses logs qu’ils soient sur stderr ou, avec l’utilisation de l’option --syslog, dans syslog.
En background
L’option --detach indique à git-daemon de passer en background une fois lancé : cela implique l’option --syslog.
Sans stress
Si vous voulez aller plus vite et zapper l’étape de création du fichier git-daemon-export-ok dans vos dépôts, il vous suffit d’utiliser l’option --export-all pour ne plus y penser. Git-daemon exportera tout ce qui ressemble à un dépôt.
Utilisateur et groupe
Si vous voulez que git-daemon fonctionne sous un utilisateur et un groupe particulier, il suffit d’utiliser les options --user=user et --group=group.
Hôtes virtuels
Si vous aimez les hôtes virtuels pour les serveurs http, vous apprécierez peut être que git-daemon sache aussi faire ça. L’option --interpolated-path=pathtemplate permet cela via une syntaxe, comment dire… simple ? Oui sûrement. Disons donc que nous avons deux hôtes virtuels à servir : git.jardin.ca et git.librium.org. On crée donc un répertoire /var/depots, dans celui-ci un répertoire par hôte et dans ceux-ci un répertoire projets (histoire de) :
cd /var/depots sudo mkdir git.jardin.ca Password: It can only be attributed to human error. Password: sudo mkdir git.librium.org sudo mkdir git.jardin.ca/projets sudo mkdir git.librium.org/projets
Reste le plus dur, la commande avec les options au poil. Reprenons la base précédente : git-daemon --base-path=/var/depots --listen=vo.tr.e.ip mais sans --base-path désormais inutile. On va y rajouter une dose d’armagnWW de magie avec l’option --interpolated-path. Celle-ci utilise une syntaxe charmante avec des % partout :
- %H pour le hostname ;
- %CH pour canonical hostname ;
- %IP pour l’IP (on aurait donc pu utiliser des IP en lieu et place des noms d’hôtes dans l’étape précédente) ;
- %P pour le port ;
- %D pour le chemin vers les dépôts.
Comme disait un de mes profs d’élec’, " un schéma vaut mieux que des longs discours " :
git-daemon --listen=vo.tr.e.ip --verbose --interpolated-path=/var/depots/%H%D /var/depots/git.jardin.ca/projets /var/depots/git.librium.org/projets
N’oubliez pas de spécifier le path absolu avant %H et %D, sinon vous risquez de patauger un peu avant de faire marcher la chose. Vos clients n’ont alors qu’à cloner comme ils le font d’habitude. Par exemple, pour les projets projet_A, et froggy, situés respectivement sur git.jardin.ca et git.librium.org :
- depuis le serveur ls /var/depots/git.jardin.ca/projets/ projet_alpha.git ls /var/depots/git.librium.org/projets/ froggy # depuis le client : cd && cd projets git clone git://git.jardin.ca/projets/projet_alpha.git Initialized empty Git repository in /home/ange/projets/projet_alpha/.git/ remote: Generating pack... ... git clone git://git.librium.org/projets/froggy.git Initialized empty Git repository in /home/ange/projets/froggy/.git/ remote: Generating pack... ...
depuis le serveur
ls /var/depots/git.jardin.ca/projets/ projet_alpha.git ls /var/depots/git.librium.org/projets/ froggy
depuis le client :
cd && cd projets git clone git://git.jardin.ca/projets/projet_alpha.git Initialized empty Git repository in /home/ange/projets/projet_alpha/.git/ remote: Generating pack... ... git clone git://git.librium.org/projets/froggy.git Initialized empty Git repository in /home/ange/projets/froggy/.git/ remote: Generating pack... ...
Inetdisation ?
Oui, les agités du fond de la salle qui veulent savoir si on peut utiliser git-daemon avec inetd peuvent se rassurer, c’est possible. On peut utiliser quasiment toutes les options précédemment vues : il suffit de mettre la commande suivante dans /etc/inetd, le tout sur une seule ligne : git stream tcp nowait nobody /usr/bin/git-daemon git-daemon --listen=vo.tr.e.ip --verbose --interpolated-path=/var/depots/%H%D /var/depots/git.jardin.ca/projets /var/depots/git.librium.org/projets --export-all --inetd
git stream tcp nowait nobody /usr/bin/git-daemon git-daemon --listen=vo.tr.e.ip --verbose --interpolated-path=/var/depots/%H%D \ /var/depots/git.jardin.ca/projets /var/depots/git.librium.org/projets --export-all \ --inetd
Oui enfin, cloner, cloner
Oui, cloner ne fait pas tout et il faut effectivement pouvoir pousser vers le serveur pour que ce soit efficace. Mais git-daemon ne gère pas l’écriture, seulement la lecture : il vous faut donc utiliser un autre accès au serveur pour ça (ssh par exemple comme vu dans le numéro 101) :
pwd /home/ange/projets/projet_alpha git push ssh://git.jardin.ca/var/depots/git.jardin.ca/projets/projet_alpha.git master
Résumé de l’acte
Cet acte se finit donc avec de quoi faire un serveur relativement robuste pour publier vos projets et ceux de vos amis. Rappelons rapidement les commandes importantes.
- un serveur de base : git-daemon --base-path=/var/depots --listen=vo.tr.e.ip ;
- un serveur avec support d’hôtes virtuels : git-daemon --listen=vo.tr.e.ip --verbose --interpolated-path=/var/depots/%H%D /var/depots/git.jardin.ca/projets /var/depots/git.librium.org/projets.
Acte 2 : conflits
Sujet qui m’a été demandé et qui, il est vrai, fut bien succinctement traité dans le précédent article. En effet, un des " soucis " que l’on peut avoir, lorsqu’on utilise des branches et des branches pour tester des choses (vous savez, une veille de partiels, quand vous vous dites que vous recoderiez bien la moitié d’une bibl…), c’est que lorsqu’on réintègre ça dans la branche master, ça risque de coincer. Alors évidemment, on n’appelle surtout pas un détachement de la Légion pour supprimer les conflits qui sont apparus, on va y aller doucement avec nos deux seuls alliés : Git et votre éditeur favori. Commençons donc par pondre une tartine de code pas très jolie : on va faire ça en Perl parce que c’est un langage que j’aime bien et qu’il est relativement répandu. Le script en lui-même n’a que peu d’importance, mais, pour vous aider à suivre si vous ne lisez par le Perl couramment, il s’agit d’un script qui lit le /etc/passwd et affiche son contenu. Tout d’abord, voici la version dans la branche master :
#!/usr/bin/perl -w
use strict;
# ouverture du handle du fichier (lecture)
open MYPASSWD, "/etc/passwd"
or die "impossible d’ouvrir le fichier";
# parcourt du fichier
while (<MYPASSWD>) {
# decoupe brutale
my @champs = split /:/, $_;
print "login : $champs[0]\n";
print "\tshell : $champs[6]\n";
print "\thome dir : $champs[5]\n";
}
# fermeture du handle du fichier
close MYPASSWD
or die "impossible de fermer le fichier";
Et voici la version de la branche monoline (on se souvient que la commande git checkout branche permet de passer d’une branche à une autre) :
#!/usr/bin/perl -w
use strict;
sub affichage {
my @champs = @_;
chomp($champs[6]);
print "\tshell : $champs[6]\n\thome dir : $champs[5]\n";
}
# ouverture du handle du fichier (lecture)
open MYPASSWD, "/etc/passwd"
or die "impossible d’ouvrir le fichier";
# parcourt du fichier
while (<MYPASSWD>) {
# decoupe brutale
my @champs = split /:/, $_;
print "login : $champs[0]\n";
affichage(@champs);
}
# fermeture du handle du fichier
close MYPASSWD
or die "impossible de fermer le fichier";
Lorsqu’on effectue le merge de la branche monoline dans la branche master, voici ce qui se passe :
git branch * master monoline git merge monoline Auto-merged script.pl CONFLICT (content): Merge conflict in script.pl Automatic merge failed; fix conflicts and then commit the result. git branch * master monoline git merge monoline Auto-merged script.pl CONFLICT (content): Merge conflict in script.pl Automatic merge failed; fix conflicts and then commit the result.
On a donc tout cassé. Regardons plus attentivement :
cat script.pl
#!/usr/bin/perl -w
use strict;
sub affichage {
my @champs = @_;
chomp($champs[6]);
print “\tshell : $champs[6]\n\thome dir : $champs[5]\n”;
}
# ouverture du handle du fichier (lecture)
open MYPASSWD, “/etc/passwd”
or die “impossible d’ouvrir le fichier”;
# parcourt du fichier
while (<MYPASSWD>) {
# decoupe brutale
my @champs = split /:/, $_;
print “login : $champs[0]\n”;
<<<<<<< HEAD:script.pl
print "\tshell : $champs[6]\n";
print “\thome dir : $champs[5]\n”;
=======
affichage(@champs);
>>>>>>> monoline:script.pl
}
# fermeture du handle du fichier
close MYPASSWD
or die “impossible de fermer le fichier”;
On voit ici que git a mergé ce qu’il pouvait (la fonction affichage), mais qu’il a ensuite buté sur le conflit auquel on s’attendait. Nous retrouvons donc les lignes qui posent problème, avec la version de chaque branche séparée de l’autre. La première correspond à la version de la branche master (HEAD) dans laquelle nous avons essayé de merger la deuxième version de la branche monoline. Il faut alors résoudre à la main :
while (<MYPASSWD>) {
# decoupe brutale
my @champs = split /:/, $_;
print "login : $champs[0]\n";
affichage(@champs);
}
Il ne reste plus qu’à commiter :
git add script.pl && git commit -m "resolution du conflit" Created commit 0cdf6b6: resolution du conflit
Résumé de l’acte
D’une manière générale, git sait gérer et merger tout seul pas mal de choses. Cependant, il vous faut parfois (quand c’est vraiment conflictuel) ouvrir la trappe et aller régler les comptes à la main. Pas besoin de se demander s’il faut passer un flag à git avant de commiter les fichiers résolus, un commit suffit.
Acte 3 : la mort du colonel
L’autre outil super utile est la commande bisect. Elle permet de trouver quel commit a tout pété dans votre projet. En clair : quel patch (et donc qui) a mis le souk (ou qui a tué le colonel Moutarde) ?. Quoi que vous fassiez, votre code ne passe plus, et vous ne trouvez pas non plus qui a rajouté le chandelier sur la table. Pas de souci : commencez par regarder les logs (0, un peu raccourcis), puis il vous suffit d’isoler la scène du crime (1), de vous rappeler quand le chandelier n’était pas sur la table (2), et enfin de constater la mort du colonel (3).
pwd /home/ange/projets/moutarde # 0 git log commit a4d332054f61160c59d9aa1274dcc445763e76b7 Merge: d4a946c... d657e3c... resolution conflit sub affichage commit d657e3c1571c6bfa5291d50013f34824b4678838 factorisation commit d4a946cd38d837aea9e3e0806a68dcf89f7def37 nouvelle amelioration de l’affichage commit 0cdf6b66aa0f15f681d8b328dd1720012e4c730c Merge: de3d621... d346a5b... resolution du conflit commit de3d621836300e8eb07ce5b2a54f4df2ab1738b8 ajout de l’affichage du champ shell commit d346a5b9a029210a1d0e5c20ee0e05e3a4ba5d5f ajout de l’affichage du champ home dir commit dfc34381c7021b0871c54dc579c6357c3cd3f39f commit initial # 1 git bisect start # 2 git bisect good dfc34381c7021b0871c54dc579c6357c3cd3f39f # 3 git bisect bad master Bisecting: 2 revisions left to test after this [0cdf6b66aa0f15f681d8b328dd1720012e4c730c] resolution du conflit
pwd
/home/ange/projets/moutarde
# 0
git log
commit a4d332054f61160c59d9aa1274dcc445763e76b7
Merge: d4a946c... d657e3c...
resolution conflit sub affichage
commit d657e3c1571c6bfa5291d50013f34824b4678838
factorisation
commit d4a946cd38d837aea9e3e0806a68dcf89f7def37
nouvelle amelioration de l’affichage
commit 0cdf6b66aa0f15f681d8b328dd1720012e4c730c
Merge: de3d621... d346a5b...
resolution du conflit
commit de3d621836300e8eb07ce5b2a54f4df2ab1738b8
ajout de l’affichage du champ shell
commit d346a5b9a029210a1d0e5c20ee0e05e3a4ba5d5f
ajout de l’affichage du champ home dir
commit dfc34381c7021b0871c54dc579c6357c3cd3f39f
commit initial
# 1
git bisect start
# 2
git bisect good dfc34381c7021b0871c54dc579c6357c3cd3f39f
# 3
git bisect bad master
Bisecting: 2 revisions left to test after this
[0cdf6b66aa0f15f681d8b328dd1720012e4c730c] resolution du conflit
La commande git bisect good peut prendre un tag ou un hash de commit comme argument. Si vous faites un git branch, vous verrez que git a créé une branche bisect pour réaliser ces tests. J’ai pris ici l’identifiant du premier commit que j’ai réalisé sur mon projet (au moins, je suis sûr que c’était bon). Cet identifiant est en fait un hash sha1 (donc unique). Lorsqu’on donne master comme référence mauvaise, git revient à un commit précédent, accessible depuis master, mais pas depuis mon premier commit. Il attend alors de savoir s’il est remonté suffisamment dans le passé pour retrouver un état ok de votre code ou pas. Comme ce n’est pas le cas, on va l’en informer grâce à la commande bisect bad :
git bisect bad Bisecting: 1 revisions left to test after this [d346a5b9a029210a1d0e5c20ee0e05e3a4ba5d5f] ajout de l’affichage du champ home dir
Il remonte alors de nouveau dans le passé. Disons que celui ci est bon :
git bisect good Bisecting: 0 revisions left to test after this [de3d621836300e8eb07ce5b2a54f4df2ab1738b8] ajout de l’affichage du champ shell
Au fur et à mesure des good et bad, vous devriez arriver au coupable. Ici, git a proposé le commit resolution du conflit, puis, comme il était mauvais, il est allé deux commits plus loin. Comme nous avons désigné ce commit là comme bon, le coupable ne pouvait qu’être celui qui est entre eux deux. Une fois ceci fait, vous pouvez retourner à votre environnement de travail initial via la commande :
git bisect reset Switched to branch "master" git bisect reset Switched to branch "master"
Résumé de l’acte
Git bisect est donc un outil des plus utiles quand vous voulez traquer certains problèmes le long de vos commits. Il est fort appréciable notamment quand vous utilisez un script pour faire le test (si le script retourne 0, git considère que le code est bon ; s’il retourne entre 1 et 127, il considère qu’il n’est pas bon).
- démarrage d’une session bisect : git bisect start ;
- désignation du commit en bonne santé : git bisect good <rev> ;
- désignation du commit en mauvaise santé connu : git bisect bad <red> ;
- innocenter un commit : git bisect good ;
- accabler un commit : git bisect bad ;
- revenir dans un état normal : git bisect reset.
Rideau
Voilà, un deuxième volet de fini, il reste encore bien des choses à apprendre : les tags, des cas d’utilisation réelle, etc. Cette fois-ci, vous êtes prêt à tout ou presque, la documentation vous en dira évidemment plus si vous avez encore faim. À nouveau, je tiens à remercier lutins et barbus, surtout Don Lefinnois pour sa patience et son accueil, ainsi que son équipe (silencieuse)