Github a été lancé en 2008. Si votre carrière d’ingénieur logiciel, comme la mienne, n’est pas plus ancienne que Github, alors Git peut être le seul logiciel de contrôle de version que vous ayez jamais utilisé. Alors que les gens se plaignent parfois de sa courbe d’apprentissage abrupte ou de son interface intuitive, Git est devenu le choix de tout le monde pour le contrôle de version. Selon l’enquête des développeurs 2015 d’InStack Overflow, 69,3% des répondants ont utilisé Git, presque autant que le deuxième système de contrôle de version le plus populaire, Subversion.1 Après 2015, Stack Overflow a cessé de poser des questions aux développeurs sur les systèmes de contrôle de version qu’ils utilisent, peut-être parce que Git était devenu si populaire que la question était inintéressante.
Git lui-même n’est pas beaucoup plus ancien que Github. Linus Torvalds a publié le premierversion de Git en 2005. Bien qu’aujourd’hui les jeunes développeurs aient du mal à comprendre un monde où le terme « logiciel de contrôle de version” ne signifiait plus ou moins simplement Git, un tel monde existait il n’y a pas si longtemps. Il y avait beaucoup d’alternatives parmi lesquelles choisir. Les développeurs Open source préféraient Subversion, les entreprises et les sociétés de jeux vidéo utilisaient Perforce (certaines le font encore), tandis que le projet noyau Linux reposait sur un système de contrôle de version appelé BitKeeper.
Certains de ces systèmes, en particulier BitKeeper, peuvent sembler familiers à un utilisateur de youngGit transporté dans le temps. La plupart ne le feraient pas. BitKeeper mis à part, les systèmes de contrôle de version qui ont précédé Git fonctionnaient selon un paradigme fondamentalement différent. Dans une taxonomie proposée par Eric Sink, auteur de VersionControl by Example, Git est un système de contrôle de version de troisième génération, tandis que la plupart des prédécesseurs de Git, les systèmes populaires dans les années 1990 et au début des années 2000, sont des systèmes de contrôle de version de deuxième génération.2 Là où les systèmes de contrôle de version de troisième génération sont distribués, les systèmes de contrôle de version de deuxième génération sont centralisés. Vous avez presque certainement entendu Git décrit comme un système de contrôle de version ”distribué » auparavant. Je n’ai jamais tout à fait compris la distinction distribuée / centralisée, du moins pas avant d’avoir installé et expérimenté un système de contrôle de version centralisé de deuxième génération.
Le système que j’ai installé était CVS. CVS, abréviation de Système de versions simultanées, étaitle tout premier système de contrôle de version de deuxième génération. C’était également le système de contrôle de version le plus populaire pendant environ une décennie jusqu’à ce qu’il soit remplacé en 2000 par Subversion. Même alors, Subversion était censée être « CV mais mieux », ce qui souligne seulement à quel point les CV étaient devenus dominants tout au long des années 1990.
CVS a été développé pour la première fois en 1986 par un informaticien néerlandais nommé Dick Grune, qui cherchait un moyen de collaborer avec ses étudiants sur un projet de compilation.3 CVS était initialement un peu plus qu’une collection de scripts shell enveloppant RCS (Revision Control System), un système de contrôle de version de première génération que Grune souhaitait améliorer. RCS fonctionne selon un modèle de verrouillage pessimiste, ce qui signifie qu’il n’y a pas deux programmeurs qui peuvent travailler sur un seul fichier à une fois. Pour éditer un fichier, vous devez d’abord demander à RCS un verrouillage exclusif sur le fichier, que vous conservez jusqu’à ce que vous ayez terminé l’édition. Si quelqu’un d’autredéjà modifier un fichier que vous devez modifier, vous devez attendre. CVS s’est amélioré sur RCSET a inauguré la deuxième génération de systèmes de contrôle de version en échangeant le modèle de verrouillage pessimiste contre un modèle optimiste. Les programmeurs pouvaient désormais éditer le même fichier en même temps, en fusionnant leurs modifications et en résolvant tous les conflits plus tardifs. (Brian Berliner, un ingénieur qui a ensuite repris le projet CVS, a écrit un document très lisible sur les innovations de CVS en 1990.)
En ce sens, CVS n’était pas si différent de Git, qui fonctionne également selon un modèle optimiste. Mais c’est là que s’arrêtent les similitudes. En fait, lorsque Linus Torvalds développait Git, l’un de ses principes directeurs ÉTAITWWCVSND, ou « Que ne Ferait pas CVS. » Chaque fois qu’il doutait d’une décision, il s’efforçait de choisir l’option qui n’avait pas été choisie dans la conception des CV.4 Donc, même si CVS précède Git de plus d’une décennie, il a influencé Git comme une sorte de modèle négatif.
J’ai vraiment aimé jouer avec les CV. Je pense qu’il n’y a pas de meilleur moyen de comprendre pourquoi la nature distribuée de Git est une telle amélioration par rapport à ce qui est arrivé auparavant. Je vous invite donc à venir avec moi pour un voyage passionnant et à passer les dix prochaines minutes de votre vie à apprendre un morceau de softwarenobody a utilisé au cours de la dernière décennie. (Voir correction.)
Mise en route avec CVS
Les instructions d’installation de CVS se trouvent sur la page d’accueil du projet. Sur macOS, vous pouvez installer CVS en utilisanthomebrew.
Puisque CVS est centralisé, il fait la distinction entre l’univers côté client et l’univers côté serveur d’une manière que quelque chose comme Git ne fait pas. La distinction n’est pas si prononcée qu’il existe différents exécutables. Mais pour commencer à utiliser CVS, même sur votre propre machine, vous devrez configurer le backend de CVS.
Le backend CVS, le magasin central de tout votre code, s’appelle le référentiel.Alors que dans Git, vous auriez généralement un référentiel pour chaque projet, dans CVSLE référentiel contient tous vos projets. Il existe un référentiel central pour toujours, bien qu’il existe des moyens de travailler uniquement avec un projet à la fois.
Pour créer un dépôt local, vous exécutez la commande init
. Vous feriez cela partout dans le monde comme votre répertoire personnel.
$ cvs -d ~/sandbox init
CVS vous permet de passer des options à la commande cvs
elle-même ou à la sous-commande init
. Les options qui apparaissent après la commande cvs
sont de nature globale, tandis que les options qui apparaissent après la sous-commande sont spécifiques à la sous-commande. Dans ce cas, l’indicateur -d
est global. Ici, il arrive de dire à CVSwhere que nous voulons créer notre référentiel, mais en général, l’indicateur -d
pointe vers l’emplacement du référentiel que nous voulons utiliser pour une action donnée. Il peut être nécessaire de fournir l’indicateur -d
tout le temps, de sorte que l’environnement variable CVSROOT
peut être défini à la place.
Puisque nous travaillons localement, nous venons de passer un chemin pour notre argument -d
, mais nous aurions également pu inclure un nom d’hôte.
La commande crée un répertoire appelé sandbox
dans votre répertoire personnel. Si vous listez le contenu de sandbox
, vous constaterez qu’il contient un autre directeurappelé CVSROOT
. Ce répertoire, à ne pas confondre avec environmentvariable, contient des fichiers administratifs pour le référentiel.
Félicitations! Vous venez de créer votre premier référentiel CVS.
Vérification du code
Disons que vous avez décidé de garder une liste de vos couleurs préférées. Vous êtes une personne artistiquement encline mais extrêmement oublieuse. Vous tapez votre liste de couleurs et l’enregistrez dans un fichier appelé favorites.txt
:
blueorangegreendefinitely not yellow
Supposons également que vous avez enregistré votre fichier dans un nouveau répertoire appelé colors
. Maintenant, vous souhaitez mettre votre liste de couleurs préférées sous contrôle de version, car dans cinquante ans, il sera intéressant de regarder en arrière et de voir commentvos goûts ont changé au fil du temps.
Pour ce faire, vous devrez importer votre répertoire en tant que nouveau CVSproject. Vous pouvez le faire en utilisant la commande import
:
$ cvs -d ~/sandbox import -m "" colors colors initialN colors/favorites.txtNo conflicts created by this import
Nous spécifions ici l’emplacement de notre référentiel avec le drapeau -d
. Les arguments restants sont passés à la sous-commande import
. Nous devons fournir un message, mais ici, nous n’en avons pas vraiment besoin, alors nous l’avons laissé vide. L’argument suivant, colors
, spécifie le nom de notre nouveau répertoire dans le référentiel; ici, nous venons d’utiliser le même nom que le répertoire dans lequel nous nous trouvons.Les deux derniers arguments spécifient respectivement la balise vendor et la balise release.Nous parlerons plus des tags dans une minute.
Vous venez de retirer votre projet « colors » dans le référentiel CVS. Il existe plusieurs façons d’introduire du code dans CVS, mais c’est la méthode recommandée par le Contrôle de version pragmatique à l’aide de CVS, le livre PragmaticProgrammer sur CVS. Ce qui rend cette méthode un peu gênante, c’est que les jeunes doivent vérifier votre travail, même si vous avez déjà un répertoire colors
existant. Au lieu d’utiliser ce répertoire, vous allez le supprimer, puis vérifier la version que CVS connaît déjà:
$ cvs -d ~/sandbox co colorscvs checkout: Updating colorsU colors/favorites.txt
Cela créera un nouveau répertoire, également appelé colors
. Dans ce répertoire, vous trouverez votre fichier favorites.txt
d’origine avec un répertoire appelé CVS
. Le répertoire CVS
est fondamentalement l’équivalent de CVS du répertoire .git
dans chaque dépôt Git.
Faire des modifications
Préparez-vous pour un voyage.
Tout comme Git, CVS a une sous-commande status
:
C’est là que les choses commencent à paraître étrangères. CVS n’a pas d’objets commit. Dans ce qui précède, il y a quelque chose appelé un « Identifiant de validation”, mais cela pourrait n’être qu’une édition relativement récente — aucune mention d’un « Identifiant de validation” n’apparaît dans le Contrôle de version provisoire Utilisant CVS, publié en 2003. (La dernière date vers CVS a été publiée en 2008.5)
Alors qu’avec Git, vous parleriez de la version d’un fichier associé à commit 45de392
, dans CVS, les fichiers sont versionnés séparément. La première version de yourfile est la version 1.1, la prochaine version est la 1.2, etc. Lorsque les branches sont impliquées, des nombres supplémentaires sont ajoutés, de sorte que vous pourriez vous retrouver avec quelque chose comme le 1.1.1.1
ci-dessus, ce qui semble être la valeur par défaut dans notre cas même si wehaven n’a créé aucune branche.
Si vous deviez exécuter cvs log
(équivalent à git log
) dans un projet avec beaucoup de fichiers et de commits, vous verriez un historique individuel pour chaque fichier. Vous pourriez avoir un fichier à la version 1.2 et un fichier à la version 1.14 dans le même projet.
Allons de l’avant et modifions la version 1.1 de notre fichier favorites.txt
:
blue orange green+cyan definitely not yellow
Une fois que nous avons effectué le changement, nous pouvons exécuter cvs diff
pour voir ce que CVS pense que nous avons fait:
CVS reconnaît que nous avons ajouté une nouvelle ligne contenant la couleur « cyan” au fichier. (En fait, il dit que nous avons apporté des modifications au fichier « RCS »; vous pouvez voir QUECVS n’a jamais complètement échappé à son association d’origine avec RCS.) Le diff que nous montrons est le diff entre la copie de favorites.txt
dans notre répertoire de travail et la version 1.1.1.1 stockée dans le référentiel.
Pour mettre à jour la version stockée dans le référentiel, nous devons valider le changement. Dans Git, ce serait un processus en plusieurs étapes. Nous devions mettre en scène le changement pour qu’il apparaisse dans notre index. Ensuite, nous commettions le changement. Enfin, pour que la modification soit visible par quiconque, nous devions pousser le commit jusqu’au dépôt d’origine.
Dans CVS, toutes ces choses se produisent lorsque vous exécutez cvs commit
. CVS regroupe simplement tous les changements qu’il peut trouver et les place dans le référentiel:
Je suis tellement habitué à Git que cela me semble terrifiant. Sans possibilité de mettre en scène des changements, toute vieille chose que vous avez touchée dans votre direction de travail se retrouve dans le dépôt public. Avez-vous réécrit de manière passive et agressive la fonction mal mise en œuvre d’un collègue par nécessité cathartique, sans jamais avoir l’intention qu’il le sache? Dommage, il te prend pour un con. Vous ne pouvez pas non plus modifier vos commits avant de les pousser, car un commit est un push. Aimez-vous passer 40 minutes à exécuter à plusieurs reprises git rebase -i
jusqu’à ce que votre historique d’engagement local s’écoule comme la dérivation d’une preuve mathématique? Désolé, vous ne pouvez pas le faire ici, et tout le monde va découvrir que vous n’écrivez pas en fait vos tests en premier.
Mais je comprends aussi maintenant pourquoi tant de gens trouvent Git inutilement compliqué.Si cvs commit
est ce à quoi vous étiez habitué, alors je suis sûr que la mise en scène et les changements poussés vous passeraient pour une corvée inutile.
Lorsque les gens parlent de Git comme d’un système ”distribué », c’est principalement la différence qu’ils signifient. Dans CVS, vous ne pouvez pas effectuer de commits localement. Un commit est une soumission de code au référentiel central, ce n’est donc pas quelque chose que vous pouvez faire sans connexion. Tout ce que vous avez localement est votre répertoire de travail. Dans Git, vous disposez d’un référentiel local à part entière, vous pouvez donc effectuer des commits toute la journée même lorsque vous êtes déconnecté. Et vous pouvez modifier ces commits, revenir, branche et choisir autant que vous le souhaitez, sans que personne d’autre n’ait à le savoir.
Comme les commits étaient plus importants, les utilisateurs de CVS les faisaient souvent rarement.Les commits contiendraient autant de changements qu’aujourd’hui, nous pourrions nous attendre à voir dans la demande d’extraction aten-commit. Cela était particulièrement vrai si les commits déclenchaient un CIbuild et une suite de tests automatisée.
Si nous exécutons maintenant cvs status
, nous pouvons voir que nous avons une nouvelle version de notre fichier:
Fusion
Comme mentionné ci-dessus, dans CVS, vous pouvez éditer un fichier que quelqu’un d’autre est déjà en train d’éditer. C’était la grande amélioration de CVS par rapport à RCS. Que se passe-t-il lorsque vous avez besoin d’apporter vos changements ensemble?
Disons que vous avez invité des amis à ajouter leurs couleurs préférées à notre liste. Pendant qu’ils ajoutent leurs couleurs, vous décidez que vous n’aimez plus la couleur verte et supprimez-la de la liste.
Lorsque vous allez valider vos modifications, vous découvrirez peut-être que CVS remarque un problème :
Il semble que vos amis aient commis leurs modifications en premier. Ainsi, votre version de favorites.txt
n’est pas à jour avec la version du référentiel. Si yourun cvs status
, vous verrez que votre copie locale de favorites.txt
est la version1.2 avec quelques modifications locales, mais la version du référentiel est 1.3:
Vous pouvez exécuter cvs diff
pour voir exactement quelles sont les différences entre 1.2 et 1.3:
Il semble que nos amis aiment vraiment le rose. Dans tous les cas, ils ont modifié une partie du fichier différente de celle que nous avons, de sorte que les modifications sont faciles à fusionner. CVScan le fait pour nous lorsque nous exécutons cvs update
, ce qui est similaire à git pull
:
$ cvs updatecvs update: Updating .RCS file: /Users/sinclairtarget/sandbox/colors/favorites.txt,vretrieving revision 1.2retrieving revision 1.3Merging differences between 1.2 and 1.3 into favorites.txtM favorites.txt
Si vous regardez maintenant favorites.txt
, vous constaterez qu’il a été modifié pour inclure les modifications que vos amis ont apportées au fichier. Vos échanges sont toujours là aussi. Maintenant, vous êtes libre de valider le fichier:
Le résultat final est ce que vous obtiendrez dans Git en exécutant git pull --rebase
. Vos modifications ont été ajoutées en plus des modifications de vos amis. Il n’y a pas de » mergecommit ». »
Parfois, les modifications apportées au même fichier peuvent être incompatibles. Si vos amis avaient changé « vert » en ”olive », par exemple, cela aurait été en conflit avec votre changement supprimant complètement ”vert ». Dans les premiers jours de CVS, c’était exactement le genre de cas qui faisait craindre aux gens que CVS n’était pas sûr; Le verrouillage esthétique de RCS garantissait qu’un tel cas ne pourrait jamais se produire. Mais CVS garantit la sécurité en s’assurant que les changements de personne ne sont automatiquement écrasés. Vous devez indiquer à CVS quelle modification vous souhaitez continuer, donc lorsque vous exécutez cvs update
, CVS marque le fichier avec les deux modifications de la même manière que Git lorsque Git détecte un conflit de fusion. Vous devez ensuite modifier manuellement le fichier et choisir la modification que vous souhaitez conserver.
La chose intéressante à noter ici est que les conflits de fusion doivent être corrigés avant de pouvoir être validés. C’est une autre conséquence de la centralisation de CVS nature.In Git, vous n’avez pas à vous soucier de résoudre les fusions jusqu’à ce que vous poussiez les engagements que vous avez localement.
Balises et branches
Comme CVS n’a pas d’objets de validation facilement adressables, la seule façon de grouper une collection de modifications est de marquer un état de répertoire de travail particulier avec atag.
Créer une balise est facile:
$ cvs tag VERSION_1_0cvs tag: Tagging .T favorites.txt
Vous pourrez plus tard retourner les fichiers à cet état en exécutant cvs update
et en passant la balise au -r
drapeau:
$ cvs update -r VERSION_1_0cvs update: Updating .U favorites.txt
Parce que vous avez besoin d’une balise pour revenir à un état de répertoire de travail antérieur, Cvsencourage beaucoup de marquage préventif. Avant les refactors majeurs, par exemple, vous pouvez créer une balise BEFORE_REFACTOR_01
que vous pourrez utiliser plus tard si le facteur a mal tourné. Les gens ont également utilisé des balises s’ils voulaient générer des diffs à l’échelle du projet. Fondamentalement, toutes les choses que nous faisons régulièrement aujourd’hui avec les commithashes doivent être anticipées et planifiées avec CVS, car vous deviez déjà avoir les balises disponibles.
Les branches peuvent être créées en CVS, en quelque sorte. Les branches ne sont qu’un type spécial d’étiquette:
$ cvs rtag -b TRY_EXPERIMENTAL_THING colorscvs rtag: Tagging colors
Qui ne crée que la branche (à la vue de tout le monde, d’ailleurs), vous devez donc toujours y passer en utilisant cvs update
:
$ cvs update -r TRY_EXPERIMENTAL_THING
Les commandes ci-dessus basculent sur la nouvelle branche dans votre répertoire de travail actuel, mais un contrôle de version pragmatique à l’aide de CVS vous conseille en fait de créer un nouveau répertoire pour contenir votre nouvelle branche. Ses auteurs ont probablement trouvé que la commutation de répertoires était plus facile que de changer de branche dans CVS.
Le contrôle de version pragmatique à l’aide de CVS déconseille également de créer des branchesoff d’une branche existante. Ils recommandent de créer uniquement des branches à partir de la branche mainline, qui dans Git est connue sous le nom de master
. En général, la ramification étaitconsidéré comme une compétence CVS « avancée ». Dans Git, vous pouvez démarrer une nouvelle branche pour presque n’importe quelle raison triviale, mais dans CVS, la branche n’était généralement utilisée que lorsque cela était vraiment nécessaire, comme pour les versions.
Une branche pourrait ensuite être fusionnée dans la ligne principale en utilisant cvs update
et le drapeau -j
:
$ cvs update -j TRY_EXPERIMENTAL_THING
Merci pour les historiques de validation
En 2007, Linus Torvalds a parlé de Git chez Google. Git était très nouveau à l’époque, donc la discussion était essentiellement une tentative de persuader une salle remplie de programmeurs sceptiques qu’ils devraient utiliser Git, même si Git était si différent de tout ce qui était alors disponible. Si vous n’avez pas déjà vu la conférence, je vous encourage fortement à la regarder. Linus est un orateur divertissant, même s’ilne jamais être son moi impétueux. Il fait un excellent travail pour expliquer pourquoile modèle distribué de contrôle de version est meilleur que le modèle centralisé. Une grande partie de sa critique est réservée aux CV en particulier.
Git est un outil complexe. L’apprendre peut être une expérience enrichissante. Mais je suis aussi continuellement étonné par les choses que fait Gitcan. En comparaison, CVS est simple et direct, bien qu’il soit souvent impossible de faire bon nombre des opérations que nous tenons maintenant pour acquises. Revenir en arrière et utiliser CVSF pendant un certain temps est un excellent moyen de vous retrouver avec une nouvelle appréciation de la puissance et de la flexibilité de forGit. Cela illustre bien pourquoi comprendre l’histoire du développement de logiciels peut être si bénéfique — ramasser et réexaminer les outils d’obsolete vous en apprendra beaucoup sur le pourquoi des outils que nous utilisons aujourd’hui.
Si vous avez apprécié ce post, plus comme il sort toutes les quatre semaines! Suivez @TwoBitHistory sur Twitter ou abonnez-vous au flux RSS pour vous assurer de savoir quand un nouveau message est publié.
Correction
On m’a dit qu’il existe de nombreuses organisations, en particulier les organisations à risque, qui font des choses comme fabriquer des logiciels de dispositifs médicaux, qui utilisent encore des CV. Les programmeurs de ces organisations ont développé de petites astuces pourtravailler autour des limites de CVS, comme créer une nouvelle branche pour presque tous les changements pour éviter de s’engager directement sur HEAD
. (Merci à Michael Kohne d’avoir indiqué cela.)