Je vais me servir d’une analogie pour présenter la gestion de versions. Référez-vous à la page de wikipedia sur la gestion de versions pour une explication plus censée.
J’ai joué à des jeux vidéos presque toute ma vie. Par contre, je n’ai commencé à utiliser des systèmes de gestion de versions qu'à l'âge adulte. Je pense ne pas être le seul dans ce cas et la comparaison entre les deux peut rendre les concepts plus simples à expliquer et à comprendre.
Pensez à l'édition de votre code, ou de votre document, comme s’il s’agissait de jouer à un jeu. Quand vous avez bien progressé, vous aimeriez faire une sauvegarde. Pour cela vous cliquez sur le bouton enregistrer de votre fidèle éditeur.
Mais ceci va écraser l’ancienne version. C’est comme ces anciens jeux qui n’avaient qu’un emplacement : oui vous pouviez faire une sauvegarde mais vous ne pouviez pas revenir dans un état précédent. Quel dommage, vu que votre sauvegarde précédente pouvait éventuellement être située à un passage du jeu particulièrement amusant sur lequel vous seriez bien revenu un de ces jours. Ou, encore pire, votre seule sauvegarde était dans un état qui ne permettait pas de gagner et vous deviez tout recommencer à zéro.
Lorsque vous modifiez un document, dans le but de conserver les anciennes versions, vous pouvez l'"Enregistrer Sous…" un nom de fichier différent ou le recopier ailleurs avant de l’enregistrer. Vous pouvez même compresser ces copies pour gagner de l’espace. C’est une forme primitive et laborieuse de gestion de versions. Les jeux vidéo se sont améliorés sur ce point depuis longtemps puisque la plupart proposent différents emplacements de sauvegarde automatiquement horodatés.
Rendons le problème légèrement plus coriace. Imaginez que vous ayez un ensemble de fichiers qui vont ensemble comme le code source d’un projet ou les fichiers d’un site web. Dans ce cas si vous voulez conserver une ancienne version, vous devez archiver le dossier en entier. Conserver un grand nombre de versions à la main n’est pas pratique et devient rapidement fastidieux.
Dans le cas de certains jeux vidéo, l’enregistrement d’une partie est réellement constitué d’un dossier rempli de fichiers. Ces jeux cachent ce détail au joueur et présentent une interface adaptée pour gérer différentes versions de ce dossier.
Les systèmes de gestion de versions ne font pas autre chose. Ils offrent tous une belle interface pour gérer un dossier rempli de plein de choses. Vous pouvez enregistrer l'état du dossier aussi souvent que vous voulez et, plus tard, vous pouvez recharger l’un des états enregistrés. À la différence de la plupart des jeux vidéos, ils sont généralement habiles pour économiser l’espace nécessaire. Typiquement, seuls quelques fichiers changent d’une version à une autre, et pas de beaucoup. Stocker ces différences au lieu des nouvelles copies complètes économise de l’espace.
Imaginez maintenant un jeu vidéo très difficile. Si difficile à terminer que plein de joueurs expérimentés de toute la planète décident de faire équipe et de partager leurs parties enregistrées pour essayer d’en venir à bout. Les Speedruns en sont un exemple concret : des joueurs qui se spécialisent dans différents niveaux du même jeu collaborent pour produire des résultats surprenants.
Quel système mettriez-vous en place pour qu’ils puissent accéder facilement aux sauvegardes des uns et des autres ? Et pour qu’ils puissent en téléverser de nouvelles ?
Dans le passé, tous les projets utilisaient une gestion de versions centralisée. Quelque part un serveur contenait l’ensemble des sauvegardes du jeu et personne d’autre. Chaque joueur conservait au plus quelques sauvegardes de parties sur leur machine. Quand un joueur voulait progresser, il téléchargeait les dernières sauvegardes du serveur, jouait un moment, puis sauvegardait et téléversait ses nouvelles sauvegardes vers le serveur pour les mettre à disposition de tous les autres.
Qu’en était-il si pour une raison quelconque, des joueurs voulaient obtenir une partie enregistrée antérieurement ? Peut-être la sauvegarde actuelle de la partie était-elle dans un état sans possibilité de victoire parce que quelqu’un avait oublié de prendre un objet au niveau trois, et voulaient-ils retrouver la dernière partie enregistrée au moment où la partie pouvait encore être gagnée. Ou peut-être souhaitaient-ils comparer deux parties enregistrées précédemment pour voir le travail réalisé par un joueur précis.
Il peut y avoir de nombreuses raisons de vouloir récupérer une ancienne version, mais le résultat est le même : ils devaient demander au serveur central cette partie précédemment sauvegardée. Et plus ils voulaient de parties sauvegardées, plus ils devaient communiquer.
La nouvelle génération des systèmes de gestion de versions, dont Git fait partie, sont dits systèmes distribués et peuvent être vus comme une généralisation des systèmes centralisés. Quand les joueurs téléchargent du serveur principal ils obtiennent toutes les parties sauvegardées, pas uniquement la dernière. C’est comme s’ils faisaient un miroir du serveur central.
Cette opération initiale de clonage peut être coûteuse, surtout s’il y a un long historique, mais ça paie sur le long terme. Un avantage immédiat est que lorsqu’on désire une partie enregistrée, quelle qu’en soit la raison, aucune communication avec le serveur central n’est nécessaire.
Un croyance populaire veut que les systèmes distribués ne soient pas adaptés aux projets qui ont besoin d’un dépôt central officiel. Rien n’est moins vrai. Photographier quelqu’un n’a jamais eu pour effet de voler son âme. De même, cloner le dépôt principal ne diminue pas son importance.
Une première approximation assez bonne est que tout ce qu’un système centralisé de gestion de versions peut faire, un système distribué bien conçu peut le faire en mieux. Les ressources réseau sont simplement plus coûteuses que les ressources locales. Bien que nous verrons plus loin qu’il peut y avoir quelques inconvénients à l’approche distribuée, il y a moins de risques de faire des comparaisons erronées en utilisant cette approximation.
Un petit projet peut ne nécessiter qu’une fraction des fonctionnalités offertes par un tel système, mais utiliser un système qui n’autorise pas les changements d'échelle pour les petits projets c’est comme utiliser les chiffres romains pour les calculs sur des petits nombres.
De plus, votre projet peut grossir au-delà de vos prévisions initiales. Utiliser Git même pour les cas simples est comparable au fait d’avoir sur soi un couteau Suisse que vous utilisez surtout pour déboucher des bouteilles. Le jour où vous avez besoin d’un tournevis vous êtes content d’avoir plus qu’un simple tire-bouchon.
Pour aborder ce sujet, notre analogie avec le jeu vidéo serait trop tirée par les cheveux. En revanche, revenons au cas de l'édition d’un document.
Imaginons que Alice insère une ligne au début d’un fichier, et que Bob en ajoute une à la fin de sa propre copie. Ils envoient tout les deux leurs modifications. La plupart des systèmes vont automatiquement déduire un traitement raisonnable des actions : accepter et fusionner leur modifications, ainsi les modifications de Alice et de Bob sont appliquées.
Maintenant imaginez que Alice et Bob ont fait des modifications différentes sur la même ligne. Il devient alors impossible de procéder sans intervention humaine. Celui qui envoie ses modifications en second est informé d’un conflit de fusion (merge conflict), et doit choisir l’une des deux versions de la ligne, ou revoir complètement cette ligne.
Des situations plus complexes peuvent se présenter. Les systèmes de gestion de versions s’occupent eux même des cas les plus simples, et laissent les cas difficiles aux humains. Généralement leur comportement est configurable.