Contributions

Open Source sticker

Toutes les contributions de Pragmatic Source, que ce soit sous forme d'articles, de présentations ou de code sous licence libre, sont disponibles dans cette section du site et sur notre Référentiel Open Source (Redmine).

All of our contributions (articles, slideshows, Open Source code) are available in this section and on our Open Source Repository (Redmine).

Synchronisation automatique de deux référentiels Git

  • Fan de GitHub comme système décentralisé de gestion de sources ?

  • Utilisateur satisfait de Redmine comme outil de gestion de projet ?

Vous êtes cependant tiraillé entre l'envie de mettre votre référentiel de code Git sur GitHub pour profiter de son interface ergonomique et des possibilités de travail en équipe, et celle de la mettre sur Redmine pour intégrer la gestion des version au système de gestion de tickets ?

Alors cet article est pour vous ! Il explique comment synchroniser automatiquement vos référentiels Git entre GitHub et Redmine !

Description

Cette astuce concerne le système distribué de gestion de versions Git. Elle explique comment configurer une copie en lecture seule d'un référentiel Git distant sur un serveur local en mode nu (bare) et synchroniser automatiquement le contenu (en sens unique, du référentiel distant vers la copie locale).

Exemple d'utilisation

Supposons que j'utilise GitHub pour le stockage de certains projets, mais je souhaite en même temps disposer d'une copie locale du référentiel pour que Redmine puisse afficher les révisions dans l'onglet « Activité », comme dans cet exemple.

Contrairement au référentiel Subversion qui peut être distant, Redmine ne peut indexer un référentiel Git que s'il est local, il est donc nécessaire de maintenir une copie du référentiel distant sur le serveur Redmine.

Configuration

Création du référentiel nu (bare) local

Sur le serveur Redmine / Git :

  • On clone le référentiel de GitHub en local, en mode bare. Dans notre exemple, le nom du référentiel distant est :
    git://github.com/Farzy/multilog-axfr.git.
  1. cd /srv/gitosis/repositories
  2. git clone --bare git://github.com/Farzy/multilog-axfr.git multilog-axfr.git

Affichage :

Initialized empty Git repository in /srv/gitosis/repositories/multilog-axfr.git/
remote: Counting objects: 76, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 76 (delta 31), reused 0 (delta 0)
Receiving objects: 100% (76/76), 25.33 KiB, done.
Resolving deltas: 100% (31/31), done.
  • Il faut maintenant configurer manuellement le tracking de la branche distante et synchroniser l'ensemble :
  1. cd multilog-axfr.git
  2. git remote add origin git://github.com/Farzy/multilog-axfr.git
  3. git fetch -v

Affichage :

From git://github.com/Farzy/multilog-axfr
 * [new branch]      master     -> origin/master

Synchronisation automatique des référentiels

Normalement la mise à jour d'une copie de travail git se fait avec les commandes :

  1. git fetch origin
  2. git merge origin

Mais la fusion (merge) ne fonctionne pas avec un référentiel nu. Il faut ruser, nous allons utiliser les commandes suivantes que nous allons lancer automatiquement avec l'ordonnanceur cron.

En supposant que :

  • les référentiels git locaux appartiennent à l'utilisateur gitosis,
  • la version de cron du serveur supporte des fonctionnalités avancées comme les répertoire /etc/cron.d/,

nous pouvons utiliser le fichier /etc/cron.d/synchronize-git-respositories suivant :

  1. # One-way synchronization of a local and remote bare Git repository.
  2. # Repeat this line for each repository.
  3. */30 * * * * gitosis cd /srv/gitosis/repositories/multilog-axfr.git && git fetch origin && git reset refs/remotes/origin/master > /dev/null

Le référentiel local sera automatiquement mis à jour toutes les demi-heures.

Explication

git fetch met à jour la référence refs/remotes/origin/master sans toucher à la branche HEAD.
git reset refs/remotes/origin/master force la branche HEAD à pointer sur le même arbre que la branche distante. Le tour est joué !

Attention

  • Il faut pas écrire dans le référentiel local, sous peine de perdre toutes les modifications lors de la synchronisation automatique : le référentiel local est en lecture seule, pour les besoins de Redmine par exemple.

  • Le script cron ne vérifie pas les erreurs éventuelles. la redirection « > /dev/null » est indispensable car la commande « git reset » exécutée sur un référentiel nu affiche toujours des messages d'informations, comme ci-dessous, que nous voulons ignorer :

  1. multilog-axfr.git % git reset refs/remotes/origin/master
  2. .gitignore: needs update
  3. LICENSE: needs update
  4. README.md: needs update
  5. Rakefile: needs update
  6. bin/multilog-axfr.rb: needs update
  7. multilog-axfr.conf-sample: needs update
  8. samples/root/slaves/farzy.org: needs update
  9. samples/root/slaves/linux.org: needs update
  10. samples/root/slaves/pragmatic-source.com: needs update
  11. test/slave_zones_spec.rb: needs update

Grâce à ce système vous pouvez maintenant faire cohabiter du code sur Redmine et GitHub en toute sérénité !

Commentaires

Avec une version recente de git...

Processus largement simplifié en utilisant un version récente de git (>=1.6.0). Le reset n'est plus utile si le dépôt nu est cloné avec l'option mirroir.

  1. git clone --mirror user@server:project.git

Il suffit ensuite de faire des fetch réguliers

  1. cd path/to/local/project.git && git fetch -q