Il y a quelques temps, un développeur sur le projet Jenkins a accidentellement déclenché un push force sur les dépôts GitHub qui stockent les dépôts Git pour le code de Jenkins, effaçant ainsi plusieurs mois de commits. La communauté a été très compréhensive et le problème a été rapidement résolu, mais cela met en évidence que l'ouverture de GitHub (couplé avec l'ouverture de l'organisation Jenkins CI pour permettre à quiconque de commiter dans n'importe quel référentiel) peut amplifier les problèmes quand ils se produisent.
Un push force sur Git, exécuté avec git push --force, dit au serveur de remplacer le contenu des références (branches/tags) étant poussées avec le contenu donné. Normalement, un dépôt Git permettra seulement des push en mode "fast-forward", quand la référence poussée a la référence actuelle comme ancêtre. Un push force lève cette restriction permettant au contenu de remplacer ce qui était là avant.
Les dépôts Git peuvent être configurés pour autoriser ou refuser ceci avec l'option de configuration de git receive.denyNonFastForwards. Cela empêche ces 'force' de se produire.
Il y a des cas où le 'force' est utile, par exemple, si un refactoring ou une opération de filtrage tels que git filter-branch sont exécutés, alors les commits ne seront pas les ancêtres de la branche courante et ainsi le push ne fonctionnera pas. Un autre cas d'utilisation existe quand la fonction miroir est activée, et que l'on veut synchroniser le contenu de deux répertoires. Dans ce cas vous voulez que les modifications apportées soient poussées sans la moindre erreur.
C'est ce qui s'est passé dans ce cas - Luca testait le plugin miroir de Gerrit, et avait un ensemble de référentiels pour le dépôt Jenkins récupérés localement. Le miroir Gerrit a été mis en place pour prendre le contenu de ce référentiel local comme source, et tous les autres référentiels comme miroir. Malheureusement, comme les dépôts n'avaient pas été mis à jour récemment, tous les dépôts distants ont été réinitialisés à un état antérieur.
Heureusement, tous les dépôts ont été restaurés - l'un des avantages du système de contrôle de version Git (ou des DVCS) est que vous pouvez recharger un référentiel à partir de l'un de ses clones, et il était donc assez facile de le faire. Le support de GitHub était très serviable et a fourni les reflogs côté serveur (utilisés pour identifier les changements dans les branches) afin de récupérer le contenu. Mais cela soulève deux questions particulières afin d'atténuer cela à l'avenir :
- Est-il logique que des utilisateurs committent sur plusieurs référentiels, ou les modifications devraient-elles arriver uniquement à travers un canal dédié via des pull request et des revues de code ?
- Est-il judicieux pour GitHub d'offrir l'option de configuration denyNonFastForwards ?
Le principal concurrent de GitHub, BitBucket, fournit une option pour désactiver les commits 'nonFastForwards'. BitBucket a été repris par Atlassian et était utilisé principalement avec le DVCS Mercurial. Toutefois, la croissance de BitBucket l'a vu se lancer dans les solutions d'hébergement Git, et leur solution de gestion Git, Atlassian Stash, est axée uniquement sur les dépôts Git.
Ironiquement, Luca possède une société fournissant des référentiels basés sur Gerrit appelés GerritForge et a récemment écrit un livre sur l'apprentissage de l'outil de revue de code Gerrit, récemment relu par InfoQ. Peut-être que si les dépôts Jenkins utilisaient un outil basé sur de la revue de code comme Gerrit tout ceci ne serait pas arrivé.
En attendant que GitHub fournisse la configuration pour les nonFastForwards, les développeurs Jenkins écrivent un outil pour suivre les push vers le dépôt GitHub et enregistrer les modifications apportées, ainsi que les SHA des commits. Ironiquement, ils proposent d'utiliser rsync pour les sauvegarder à plusieurs endroits.
Une grande puissance implique de grandes responsabilités, et l'utilisation de la force par GitHub en est certainement une. Que GitHub fournisse ou non une option pour éviter cela dans le futur, il faut néanmoins être conscient de ces risques si vous hébergez de grands référentiels d'entreprise qui ne sont pas sauvegardés.