L'École · ˜˜ FX · AX ˜˜ Polytechnique.org · Associations polytechniciennes · Élèves · Wats4U
[ Polytechnique.org ]
28.439 étudiants et anciens de l'X sur le web
[LES X SUR LE WEB]

Portail de la documentation - Recherche - Plan | Pages des équipes | Développeurs
Howto git | Conventions | SQL | Templates

Depuis le 24 août 2007, le développement de plat/al est passé sur git. Ce document explique comment utiliser git avec plat/al.

  1. Avant toute chose
  2. Installation d'une version de plat/al
  3. Fonctionnement de base
  4. Utilisation avancée, développements massifs
  5. Développement du core
  6. Développer sur la branche de production
  7. Interfaces web et git-daemon

Avant toute chose

Avant de commencer à utiliser git, il faut le configurer. Pour ceci, tu peux récupérer le .gitconfig de quelqu'un d'autre (celui de Fruneau par exemple, dans ~x2003bruneau/.gitconfig). N'oublie surtout pas de changer ton nom/email dans le fichier de configuration.

Une configuration minimaliste peut-être faite en entrant les commandes suivantes :

% git config --global user.name "Florent Bruneau" # En mettant ton nom bien sûr :)
% git config --global user.email "" # Idem..

Dans ton .gitconfig, il peut être intéressant d'ajouter des alias qui permettrons de simplifier la vie de tous les jours. Ceci se faire via la section [alias] du fichier. Je conseille principalement la définition des deux alias suivants, principalement pour les personnes qui font peu de développement, ou qui ont du mal à s'adapter depuis des systèmes comme SVN :

[alias]
up=!git fetch && git rebase `git symbolic-ref HEAD | sed -e 's~refs/heads/~origin/~'` && git submodule update
send=!git up && git push

Avec ceci, tu auras deux commandes git supplémentaires :

  • git up qui récupère les changements sur le repository et les fusionne dans le copie locale.
  • git send qui s'assure que le repository est à jour et envoie les commits locaux au repository central.

''Note : Pour éviter les remarques du type rtfm, mieux vaut signaler dès maintenant que git est fournit avec une documentation importante. Celle-ci est accessible via :

# Lister les commandes
% git help # liste les commandes courantes
% git help -a # liste toutes les commandes

# Avoir de l'aide sur les commandes
% man git-$command
% git help $command
% git $command --help
% http://git.polytechnique.org/doc/git-$command.html

Installer sa version du site

Installation de plat/al

Pour commencer à développer sur plat/al il faut récupérer une version du repository de plat/al. Pour ceci, on réalise une copie du repository public qui est stocké dans /home/git de de murphy. Depuis murphy, cela correspond à la commande :

% mkdir ~/dev
% cd ~/dev
% git clone /home/git/platal.git platal

Il est également possible de réaliser une copie depuis une autre machine grâce à l'accès via le protocole git :

% git clone git://git.polytechnique.org/platal.git

Note : Contrairement à SVN, ceci ne fait pas un checkout , mais une véritable copie du repository : ~/dev/platal devient un autre repository pour plat/al. Ceci permet de travailler localement sur plat/al, gérer des branches localement... sans affecter le repository central, puis, lorsque le développement local est fini de transmettre les changements locaux sur le repository public.

Une fois une version du site récupérée, il faut la configurer :

% cd platal
% git submodule init
% git submodule update
% make
% cp ~x2003bruneau/dev/platal/configs/platal.conf configs/

Il ne faut pas oublier d'adapter le fichier de configuration (mettre à jour son nom, adresse mail...)

Installation de banana

Si tu as besoin de travailler sur banana, il faudra effectuer quelques opérations supplémentaires. Tout d'abord, récupérer la version SVN de banana :

% cd ~/dev/
% git clone /home/git/banana.git
% cd banana
% make
% make devel

Il faut ensuite configurer plat/al pour qu'il utilise cette installation de Banana. Le choix de la version utilisée par plat/al est faite par lors du make de plat/al. En l'absence d'un checkout local de Banana celui-ci utilise l'installation qui se trouve dans /home/web/dev. Après le checkout de Banana, il faudra donc mettre à jour le lien :

% cd ~/dev/platal
% make banana

Tester sa version de développement

Pour tester sa version de développement de plat/al il suffit de se rendre sur http://dev.m4x.org/~login/

Développer

Le développement sur son repository local (celui que nous avons cloné à la section d'avant) présente bon nombre de différences par rapport à SVN. En particuliers, lorsqu'on réalise un commit, celui-ci est stocké sur le repository local tant que ne demande pas explicitement de le partager avec le repository public.

Mettre à jour son repository

Pour les personnes qui ont ajouté les alias up et send expliqués au début de ce document, il suffit d'exécuter la commande suivante et de passer à la sous-section suivante de la documentation.

% git up

Pour ceux qui veulent mieux comprendre, ou qui font des développement un peu poussés, voici un plus de détails.

La mise à jour (équivalent de svn up) revient à importer les patchs appliqués sur la branche principale du repository public sur le repository local. Pour ceci, on utilise la commande fetch

% git fetch

Il faut bien comprendre que fetch ne fait que récupérer la liste des commits depuis le repository central, mais n'affecte pas la copie locale. Ainsi, on se retrouve dans l'état :

    B--B-B-- working copy
   /
--o--A--A--  origin/master

Dans la plupart des cas, la mise à jour de la copie locale se traduira par :

% git rebase origin/master
% git submodule update

Des explications complémentaires se trouvent dans la partie sur le commit et le push.

Valider ses modifications

Lorsqu'on développe, on veut valider ses changements. Pour ceci, on utilise la commande commit qui permet d'enregistrer les changement dans le repository. Dans le cas de git, les commits sont selectifs : il faut explicitement indiquer les fichiers à commiter. Pour ceci on utilise la commande add.

% git add fichier

Contrairement à SVN, la commande add ne s'applique pas uniquement aux fichiers absent du repository. Elle permet d'ajouter la version courante du fichier. Une fois les fichiers à commiter ajouter, il ne reste plus qu'à valider tout ceci :

% git commit

Si tous les fichiers modifiés doivent être commités, il est plus simple

% git commit -a

Cette version effectue un add sur tous les fichiers contrôlés par git et lance le commit.

Note : Comme précisé plus haut, le commit n'envoie pas le changement sur le repository public. Il s'agit simplement d'une validation locale. Ainsi, il est possible développer une fonctionnalité localement, avec plusieurs commit locaux, permettant d'effectuer des reverts locaux, et une fois la fonctionnalité terminée, d'effectuer d'une traite son envoi sur le repository public.

Envoi d'un changement sur le repository public

Pour les personnes qui ont ajouté les alias up et send indiqué au début de ce document et qui font que de petits développements (sans jouer avec les branches par exemple), cette section se résume à :

% git send

La lecture de la suite est conseillée pour tous car même si elle est masquée pour ceux qui utilisent up et send elle aborde quelques notions nécessaire pour comprendre le comportement de git.

Lorsqu'un commit local doit être exporté vers le repository public, il faut réaliser un push. Seulement, il est possible qu'on se retrouve avec une arborescence de la forme suivante :

    B--B-B-- local branch
   /
--o--A--A--  origin/master

Attention à ce cas particuliers qui peut poser quelques problèmes :

Si le changement à exporter est un ensemble de changement mineurs, il est conseillé de forcer une réécriture de l'historique permettant d'afficher les changements comme linéaires et non comme étant des changements fait en parallèle de la branche principale. Ainsi, si A et B commitent en parallèle sur leur repository locaux et que A puis B valident leurs changement, l'historique va ressembler à ceci :

    B--B-B
   /      \
--o--A--A--2--  origin/master

[2] Commit de "merge" de la branche de B dans le master

Si les changements réalisés par A et B sont mineurs, on préfère avoir un historique linéaire (l'apparition d'une nouvelle branche n'étant intéressante que pour le développement d'une fonctionnalité importante). Pour permettre cela, il suffit de dire à git qu'en fait on aimerait que nos patchs soient appliqués après ceux de la branche principale. Pour ceci on effectue un "rebase" :

Au départ :
    B--B-B-- local branch
   /
--o--A--A--  origin/master

% git fetch
% git rebase origin/master  # On indique que l'origine de la branche locale
                            # est le dernier commit de la branche master du
                            # repository public

          B--B-B-- local branch
         /
--o--A--A--  origin/master

Note : Ne pas faire de rebase dans le cas de changements important, comme le développement d'une fonctionnalité ayant pris beaucoup de temps.

Pour envoyer les changements au repository public, il suffit alors d'effectuer un push

% git push

--o--A--A--B--B-B-- origin/master

Et voilà.

Développements avancés

Comme nous venons de le voir, la commande push permet d'envoyer les changements effectués sur la branche courante vers le repository public. De fait, il vaut donc mieux séparer les développements de différentes fonctionnalités en différentes branches. Comme chacun a son propre repository, ceci est facile à faire : il suffit de créer une branche locale basée sur une source (à définir) faire le développement de la fonctionnalité sur cette branche, changer de branche lorsqu'on change de fonctionnalité sur laquelle on travaille, et ansi de suite.

Lister/Créer les branches

Chaque repository peut contenir des branches. Celles-ci peuvent être listées grâce à la commande... branch.

% git branch # liste les branches locales
% git branch -r # liste les branches du repository père

La branche courante est notée avec une étoile.

Pour créer une nouvelle branche, il suffit de d'indiquer une source et un nom. La source donne l'état initial de la branche (il s'agit donc de la branche depuis laquelle on réalise un fork).

% git checkout --track -b $nom $source

Par exemple, pour créer une nouvelle branche pour une fonctionnalité kwel, on ferait soit :

% git checkout -b kwel master # nouvelle branche basée sur la branche master locale
% git checkout -b kwel origin/master # nouvelle branche basée sur la branche master du repository public

Changer de branche

Pour changer de branche, il suffit de la checkouter. Ainsi, si je veux passer de la branche kwel à la branche master, il me suffit de faire :

% git checkout master

Et ainsi, la copie locale associée au repository local est changée.

Fusionner des branches

Une fois qu'une branche est arrivée à maturité, on peut vouloir la fusionner avec la branche principale. Ceci se fait extrêmement simplement grâce à la commande merge :

% git checkout master
% git merge kwel

Ainsi, tous les changements effectués sur kwel sont importés dans la branche master. Il est également possible de le faire à l'aide de la commande push. Par exemple, pour importer les changements de la branche kwel directement sur le repository public, on fera :

% git push origin kwel:master

Supprimer des branches

Pour supprimer une branche, il suffit d'exécuter la commandes :

% git branch -D $nom

Voilà, ceci devrait suffir pour travailler proprement sur plat/al. Pour le reste, la documentation de git devrait apporter pas mal d'informations aidant à mieux comprendre le fonctionnement du programme.

Résoudre les conflits

Il arrive que lors d'un merge ou d'un rebase on se retrouve dans un état de conflit : des changements à fusionner ne sont pas compatibles entre eux. Git tente alors plusieurs algorithmes pour corriger le conflit, et si il n'y arrive pas, il interrompt l'opération en cours (merge ou rebase) et attend que l'utilisateur corrige manuellement le problème.

Dans ce cas, il indique qu'il y a un conflit dans sa sortie :

CONFLICT (content): Merge conflict in #######

Dans ce cas, un git stat aide à avoir un aperçu des dégats. Les conflits apparaissent avec la mention "unmerged". Il faut traiter cas par cas les fichiers conflictuels. Il peut y avoir plusieurs sortes de conflits :

  • des modifications ont été apportées à un fichier qui a été supprimé dans une autre branche, dans ce cas, il faut extraire le changement apportés à ce fichier et les appliquer au bon endroit.
  • plusieurs changements se juxtapose. Dans ce cas la zone à problème est délimitée par des ">>>>>>>>>>" et "<<<<<<<<<<<<" dans le fichier en question. Dans 90% des cas il suffit de choisir quelle version conserver, mais parfois il faudra fusionner les différentes versions.

Une fois les conflits résolus, il faut appliquer git add sur le fichier (sauf dans le cas de fichier à supprimer, ou il faut effectuer un git rm dessus), puis, en fonction de l'opération en cours, indiquer à git la fin du conflit. Dans le cas d'un rebase, ce sera git rebase --continue, dans le cas d'un merge, ce sera git commit.

Développement du core

Pour "tous les jours"

A partir des version postérieures à plat/al 0.9.17, le code se trouve séparé en 2 parties :

  • la corelib : il s'agit du répertoire core. Cette bibliothèque contient le moteur de plat/al ainsi qu'un certain nombre d'outils anonymes (i.e. non spécifique à X.org ou à une autre asso).
  • le code des sites X.net et X.org

Pour le développeur "de base", il est important de savoir qu'il y a une séparation core/non-core, mais cela aura peu d'impact sur le développement courant. Ce qu'il convient de noter, c'est que l'update d'une copie locale contient une action supplémentaire : git submodule update qui met à jour le core.

Pour développer sur le core

Pour les personnes développant sur le core, il est important de se souvenir de ces quelques points :

  • le core est un repository plat/al à part entière, indépendant du repository principal (donc dev/platal est un repository et dev/platal/core est un autre repository, tous les deux copient le repository central)
  • le repository principal (dev/platal) référencie un commit du core et non une branche : donc si j'ai un repository up-to-date et qu'un autre développeur modifie le core, mon repository reste up-to-date ; il faudra modifier l'association core -> révision pour que les changements effectuées sur le core affectent le repository principal.

Le core est un repository à part entière, vous pouvez donc y travailler exactement comme sur le repository principal : créer par exemple une branche core qui traque la branche core principale :

% cd core
% git checkout -b core origin/core

Lorsque vous voulez développer sur le core, il est important de vous assurez que vous êtes sur la dernière révision du core... qui n'est pas forcément la révision actuellement checkouté.

% cd core
% git checkout core

Il est également important de se souvenir que les actions sur le repository principal peuvent affecter le core. Donc, prenez garde à toujours commiter vos changements sur le core avant de faire quoi que ce soir sur votre checkout. Par exemple :

% cd core
% git commit -a -s
% cd ..
% git up

Pour pusher vos changement, c'est exactement comme sur le repository principal :

% cd core
% git checkout core
% git push

Lorsque le checkout du core n'est pas sur le commit auquel la révision courante du repository principal fait référence, le core apparaît dans le diff sur le forme d'une différence d'id de commit. Ce changement peut être commité comme n'importe quel fichier :

% cd ~/dev/platal
% git stat
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#	modified:   core
% git diff
diff --git a/core b/core
index ddeb5f8..8e978a0 160000
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit ddeb5f8915f2aed8877689b0db19a63791c4e57d
+Subproject commit 8e978a06eadda7cbb320a3a5acf88e898754aa71
% git commit -s core

Le commit change alors l'association et ainsi, toute personne passant sa copie de plat/al sur ce commit aura le core à la nouvelle révision.

Maintenir la branche de production.

Il peut arriver que la branche de production nécessite des bugfixes ou le développement de nouvelles fonctionnalités "urgentes". Dans ce cas, ceci ne doit jamais être fait directement en prod, mais sur un checkout de la branche de production en développement.

Supposons que je veuille effectuer un bugfix sur la branche 0.9.16.

Récupérer la branche de prod

Il faut avant tout avoir une branche reflétant la branche de prod sur son repository personnel. git branch permet de savoir si cette branche existe :

% git branch
* master
  platal-0.9.15

La sortie de git branch m'indique que je n'ai pas de branche reflétant la branche platal-0.9.16 dans mon repository (l'étoile indique que je suis actuellement sur la branche master). Je vais donc la créer :

Format de la commande :
% git checkout -b nomlocal origin/nomglobal

Donc, dans mon cas particulier
% git checkout -b platal-0.9.16 origin/platal-0.9.16

La sortie de git branch alors devient

% git branch
  master
  platal-0.9.15
* platal-0.9.16

Une fois la branche créée, il me suffit d'appeler git checkout nomlocal pour passer d'une branche à l'autre, de même que si je suis sur une branche git fetch && git rebase origin/nomglobal ou git up permet de la mettre à jour pour avoir les changements du repository global.

Développer

Le développement sur la branche 0.9.16 fonctionne alors exactement comme sur la branche principale, j'édite et je commit avec git commit (et si besoin git add). De même on peut utiliser git push ou git send pour envoyer les changements (git send étant une nouvelle fois fortement conseillé car il effectue l'update et évite les fork/merge permanent de branches).

Backporter

Le système de branches de git permet simplement d'importer les fixes d'une branche stable sur une branche de dev. Ceci utilise la commande git merge. Cela impose également le processus de réalisation des bugfixes :

  • effectuer le fix sur la branche stable
  • merger la branche stable dans la branche de dev

Le fait de merger constamment la branche stable dans la branche de dev permet de s'assurer que tous les fixes de la branche stable sont dans la branche de dev... et permet donc de garantir la cohérence du développement.

Pour effectuer un backport, il faut procéder comme suit :

  • tout d'abord, on update la copie locale.
% git checkout platal-0.9.16
% git up
  • ensuite, on effectue le merge.
% git checkout master
% git up
% git merge platal-0.9.16
% git push

Attention, ici il faut bien réaliser un git push et non un git send car git aura du mal à effectuer un rebase autour d'un merge.

Updater la prod

Il faut ensuite demander à un root d'updater la prod. Ceci s'effectue comme suit :

% cd /home/web/prod/platal
% su web
% git pull

Et en cas de besoin, effectuer les mises à jours des tables SQL, supprimer le cache smarty, remettre les droits sur le platal.cron, ...

Interfaces web et git-daemon

Gitweb

Un gitweb est installé sur murphy. Il permet d'observer le contenu des repository git. La page par défaut est celle du repository public, mais il est également possible de l'utiliser pour accéder aux repositories des différents développeurs (à condition que ceux-ci aient été proprement configurés).

Pour rendre son repository accessible il faut suivre les quelques étapes de configuration qui suivent :

% cd ~
% mkdir public_git
% cd public_git
% ln -s /usr/lib/cgi-bin/gitweb.cgi
% ln -s /usr/share/gitweb/gitweb.css    # Ces lignes permettent d'avoir une jolie interface
% ln -s /usr/share/gitweb/git-logo.png  # pour son gitweb

Ensuite, pour chaque projet sur git, il faut ajouter un lien symbolique vers le répertoire git de ce projet. Ainsi, pour plat/al, ceci donne :

% ln -s ../dev/platal/.git platal.git
% vi platal.git/description # Juste pour donner un titre sympa au projet sur l'interface web :)

Dès lors, le repository est accessible sur http://git.polytechnique.org/~login/

Git-daemon

git-daemon fournit l'accès via le protocole git:// qui permet de cloner un repository distant efficacement (bien plus efficacement que le protocole http://).

L'accès aux repositories publics se fait via git://git.polytechnique.org. Tout comme l'interface web, il est également configuré pour donné accès aux repositories listés dans ~/public_git/ à l'URL git://git.polytechnique.org/~login/

Utilisation de gitk ou qgit

Un moyen simple de suivre l'évolution d'un repository est d'utiliser gitk ou qgit qui offre une interface graphique rapide et efficace (plus que l'interface web) pour suivre visuellement les branches, commits, diffs... Pour utiliser ces programmes, il faut avoir un clone local (sur sa machine perso) du repository à observer. Puis dans ce clone, il suffit de lancer gitk (ou qgit).

Plat/al 1.1.23 - Copyright © 1999-2018 Polytechnique.org  -  Lien avec l'AX  -  À propos de ce site et ses équipes
Services et éthique | Charte