Github wurde 2008 gestartet. Wenn Ihre Software-Engineering-Karriere, wie meine, nicht älter als Github ist, dann ist Git möglicherweise die einzige Versionskontrollsoftware, die Sie jemals verwendet haben. Während die Leute manchmal über die steile Lernkurve oder die unintuitive Oberfläche meckern, ist Git zu jedermanns Anlaufstelle für Versionskontrolle geworden. In der Entwicklerumfrage 2015 von InStack Overflow verwendeten 69,3% der Befragten Git, fast doppelt so viele wie das zweitbeliebteste Versionskontrollsystem, Subversion.1 Nach 2015 hörte Stack Overflow auf, Entwickler nach den von ihnen verwendeten Versionskontrollsystemen zu fragen, vielleicht weil Git so populär geworden war, dass die Frage uninteressant war.
Git selbst ist nicht viel älter als Github. Linus Torvalds hat den ersten veröffentlichtversion von Git im Jahr 2005. Obwohl es jüngeren Entwicklern heute schwer fallen könnte, sich eine Welt vorzustellen, in der der Begriff „Versionskontrollsoftware“ nicht mehr oder weniger nur Git bedeutete, gab es eine solche Welt noch vor nicht allzu langer Zeit. Es gab viele Alternativen zur Auswahl. Open-Source-Entwickler bevorzugten Subversion, Unternehmen und Videospielunternehmen verwendeten Perforce (einige tun es immer noch), während sich das LINUX-Kernel-Projekt bekanntermaßen auf ein Versionskontrollsystem namens BitKeeper stützte.
Einige dieser Systeme, insbesondere BitKeeper, könnten einem youngGit-Benutzer vertraut vorkommen, der in die Vergangenheit versetzt wurde. Die meisten würden nicht. Abgesehen von BitKeeper funktionierten die Versionskontrollsysteme vor Git nach einem grundlegend anderen Paradigma. In einer Taxonomie von Eric Sink, Autor von VersionControl by Example, ist Git ein Versionskontrollsystem der dritten Generation, während die meisten Vorgänger von Git, die in den 1990er und frühen 2000er Jahren beliebten Systeme, Versionskontrollsysteme der zweiten Generation sind.2 Wo Versionskontrollsysteme der dritten Generation verteilt sind, sind Versionskontrollsysteme der zweiten Generation zentralisiert. Sie haben mit ziemlicher Sicherheit schon einmal gehört, dass Git als „verteiltes“ Versionskontrollsystem beschrieben wird. Ich habe die Unterscheidung zwischen verteilt und zentralisiert nie ganz verstanden, zumindest nicht, bis ich selbst ein zentralisiertes Versionskontrollsystem der zweiten Generation installiert und damit experimentiert habe.
Das System, das ich installiert habe, war CVS. CVS, kurz für Concurrent Versions System, war das allererste Versionskontrollsystem der zweiten Generation. Es war auch das beliebteste Versionskontrollsystem für etwa ein Jahrzehnt, bis es im Jahr 2000 durch Subversion ersetzt wurde. Schon damals sollte Subversion „CVS but better“ sein, was nur unterstreicht, wie dominant CVS in den 1990er Jahren geworden war.
CVS wurde erstmals 1986 von einem niederländischen Informatiker namens Dick Grune entwickelt, der nach einer Möglichkeit suchte, mit seinen Studenten an einem Compiler-Projekt zusammenzuarbeiten.3 CVS war anfangs kaum mehr als eine Sammlung von Shell Scriptswrapping RCS (Revision Control System), ein Versionskontrollsystem der ersten Generation, das Grune verbessern wollte. RCS arbeitet nach einem pessimistischen Sperrmodell, was bedeutet, dass keine zwei Programmierer gleichzeitig an einer einzigen Datei arbeiten können. Um eine Datei zu bearbeiten, müssen Sie zuerst RCS um eine exklusive Sperre für die Datei bitten, die Sie behalten, bis Sie mit der Bearbeitung fertig sind. Wenn jemand anderes bereits eine Datei bearbeitet, die Sie bearbeiten müssen, müssen Sie warten. CVS verbesserte RCS und leitete die zweite Generation von Versionskontrollsystemen ein, indem es das posimistische Verriegelungsmodell gegen ein optimistisches eintauschte. Programmierer konnten nun dieselbe Datei gleichzeitig bearbeiten, ihre Bearbeitungen zusammenführen und Konflikte später lösen. (Brian Berliner, ein Ingenieur, der später das CVS-Projekt übernahm, schrieb 1990 ein sehr lesenswertes Papier über die Innovationen von CVS.)
In diesem Sinne unterschied sich CVS nicht allzu sehr von Git, was auch nach einem optimistischen Modell funktioniert. Aber hier enden die Ähnlichkeiten. Als Linus Torvalds Git entwickelte, war eines seiner Leitprinzipien WWCVSND oder „Was würde CVS nicht tun.“ Wann immer er Zweifel an einer Entscheidung hatte,bemühte er sich, die Option zu wählen, die bei der Gestaltung voncvs nicht gewählt worden war.4 Obwohl CVS über ein Jahrzehnt vor Git liegt, hat es Git als eine Art negatives Template beeinflusst.
Ich habe es wirklich genossen, mit CVS herumzuspielen. Ich denke, es gibt keinen besseren Weg zu verstehen, warum die verteilte Natur von Git eine solche Verbesserung gegenüber dem Vorherigen ist. Also lade ich Sie ein, mit mir auf eine aufregende Reise zu kommen und die nächsten zehn Minuten Ihres Lebens damit zu verbringen, etwas über ein Stück Software zu lernen, das niemand in den letzten zehn Jahren verwendet hat. (Siehe Korrektur.)
Erste Schritte mit CVS
Anweisungen zur Installation von CVS finden Sie auf der Startseite des Projekts. Unter macOS können Sie CVS mit installierenhomebrew.
Da CVS zentralisiert ist, unterscheidet es zwischen dem clientseitigen Universum und dem serverseitigen Universum auf eine Weise, die so etwas wie Git nicht tut. Dasunterschied ist nicht so ausgeprägt, dass es verschiedene ausführbare Dateien gibt. Aber um CVS auch auf Ihrem eigenen Computer verwenden zu können, müssen Sie das CVS-Backend einrichten.
Das CVS-Backend, der zentrale Speicher für Ihren gesamten Code, wird als Repository bezeichnet.Während Sie in Git normalerweise ein Repository für jedes Projekt haben, enthält das Repository in CVSthe alle Ihre Projekte. Es gibt ein zentrales Repository für alles, obwohl es Möglichkeiten gibt, jeweils nur mit einem Projekt zu arbeiten.
Um ein lokales Repository zu erstellen, führen Sie den Befehl init
aus. Sie würden dies irgendwo tun, wo Sie Ihr Home-Verzeichnis mögen.
$ cvs -d ~/sandbox init
Mit CVS können Sie Optionen entweder an den cvs
-Befehl selbst oder an deninit
-Unterbefehl übergeben. Optionen, die nach dem Befehl cvs
angezeigt werden, sind global, während Optionen, die nach dem Unterbefehl angezeigt werden, spezifisch für den Unterbefehl sind. In diesem Fall ist das Flag -d
global. Hier wird CVSwhere mitgeteilt, wo wir unser Repository erstellen möchten, aber im Allgemeinen zeigt das Flag -d
auf den Speicherort des Repositorys, das wir für eine bestimmte Aktion verwenden möchten. Es kann beedious sein, das -d
Flag ständig zu liefern, so dass stattdessen die CVSROOT
environmentvariable gesetzt werden kann.
Da wir lokal arbeiten, haben wir gerade einen Pfad für unser -d
Argument übergeben, aber wir hätten auch einen Hostnamen angeben können.
Der Befehl erstellt ein Verzeichnis mit dem Namen sandbox
in Ihrem Home-Verzeichnis. Wenn Sie den Inhalt von sandbox
überprüfen, werden Sie feststellen, dass es ein anderes Verzeichnis mit dem Namen CVSROOT
. Dieses Verzeichnis, nicht zu verwechseln mit der environmentvariable, enthält Verwaltungsdateien für das Repository.
Herzlichen Glückwunsch! Sie haben gerade Ihr erstes CVS-Repository erstellt.
Code einchecken
Angenommen, Sie haben sich entschieden, eine Liste Ihrer Lieblingsfarben zu führen. Sie sind eine künstlerisch veranlagte, aber äußerst vergessliche Person. Sie geben Ihre Farbliste ein und speichern sie als Datei mit dem Namen favorites.txt
:
blueorangegreendefinitely not yellow
Nehmen wir an, Sie haben Ihre Datei in einem neuen Verzeichnis mit dem Namencolors
gespeichert. Jetzt möchten Sie Ihre Lieblingsfarbenliste unter Versionskontrolle stellen, denn in fünfzig Jahren wird es interessant sein, zurückzublicken und zu sehen, wieIhr Geschmack hat sich im Laufe der Zeit verändert.
Dazu müssen Sie Ihr Verzeichnis als neues CVSproject importieren. Sie können dies mit dem Befehl import
tun:
$ cvs -d ~/sandbox import -m "" colors colors initialN colors/favorites.txtNo conflicts created by this import
Hier geben wir den Speicherort unseres Repositorys mit dem -d
Flag wieder an. Die restlichen Argumente werden an den Unterbefehl import
übergeben. Wir habeneine Nachricht zur Verfügung zu stellen, aber hier brauchen wir nicht wirklich ein, so haben wir itblank links. Das nächste Argument, colors
, gibt den Namen unseres neuen Verzeichnisses im Repository an; Hier haben wir nur den gleichen Namen wie das Verzeichnis verwendet, in dem wir uns befinden.Die letzten beiden Argumente geben das Vendor-Tag bzw. das Release-Tag an.Wir werden in einer Minute mehr über Tags sprechen.
Sie haben gerade Ihr „colors“ -Projekt in das CVS-Repository gezogen. Es gibt acouple verschiedene Weisen, über das Holen des Codes in CVS zu gehen, aber dieses ist themethod, das durch pragmatische Versionskontrolle UsingCVS, das PragmaticProgrammer Buch über CVS empfohlen wird. Was diese Methode etwas umständlich macht, ist, dass Sie Ihre Arbeit neu überprüfen müssen, obwohl Sie bereits ein vorhandenes colors
Verzeichnis haben. Anstatt dieses Verzeichnis zu verwenden, löschen Sie es und überprüfen Sie dann die Version, die CVS bereits kennt:
$ cvs -d ~/sandbox co colorscvs checkout: Updating colorsU colors/favorites.txt
Dadurch wird ein neues Verzeichnis erstellt, auch colors
genannt. In diesem Verzeichnis finden Sie Ihre ursprüngliche favorites.txt
Datei zusammen mit einem Verzeichnis namensCVS
. Das CVS
Verzeichnis ist im Grunde CVS’Äquivalent zum .git
Verzeichnisin jedem Git-Repository.
Änderungen vornehmen
Machen Sie sich bereit für eine Reise.
Genau wie Git hat CVS einen status
Unterbefehl:
Hier sehen die Dinge fremd aus. CVS hat keine Commit-Objekte. Im Obigen gibt es einen sogenannten „Commit-Bezeichner“, aber dies ist möglicherweise nur eine relativ neue Ausgabe — in der 2003 veröffentlichten pragmatischen Versionskontrolle mit CVS wird kein „Commit-Bezeichner“ erwähnt. (Das letzte Update auf CVS wurde in 2008.5 veröffentlicht)
Während Sie bei Git über die Version einer Datei sprechen würden, die commit45de392
, werden in CVS Dateien separat versioniert. Die erste Version von yourfile ist Version 1.1, die nächste Version ist 1.2 und so weiter. Wenn Zweige beteiligt sind, werden zusätzliche Zahlen angehängt, sodass Sie möglicherweise etwas wie das 1.1.1.1
oben erhalten, was in unserem Fall der Standard zu sein scheint, obwohl wir keine Zweige erstellt haben.
Wenn Sie cvs log
(entspricht git log
) in einem Projekt mit vielen Dateien und Commits ausführen würden, würden Sie für jede Datei einen individuellen Verlauf sehen. Sie haben möglicherweise eine Datei in Version 1.2 und eine Datei in Version 1.14 im selben Projekt.
Nehmen wir eine Änderung an Version 1.1 unserer favorites.txt
-Datei vor:
blue orange green+cyan definitely not yellow
Sobald wir die Änderung vorgenommen haben, können wir cvs diff
ausführen, um zu sehen, was CVS denkt, dass wir getan haben:
CVS erkennt, dass wir eine neue Zeile mit der Farbe „cyan“ zur Datei hinzugefügt haben. (Eigentlich heißt es, dass wir Änderungen an der „RCS“ -Datei vorgenommen haben; Sie können sehen, dass CVS seiner ursprünglichen Assoziation mit RCS nie vollständig entkommen ist.) Der angezeigte Unterschied ist der Unterschied zwischen der Kopie von favorites.txt
in unserem Arbeitsverzeichnis und der im Repository gespeicherten Version 1.1.1.1.
Um die im Repository gespeicherte Version zu aktualisieren, müssen wir die Änderung festschreiben. In Git wäre dies ein mehrstufiger Prozess. Wir müssten thechange so inszenieren, dass es in unserem Index erscheint. Dann würden wir die Änderung begehen. Um die Änderung für alle anderen sichtbar zu machen, müssten wir das Commit schließlich in das Ursprungs-Repository verschieben.
In CVS passieren all diese Dinge, wenn Sie cvs commit
. CVS bündelt einfach alle Änderungen, die es finden kann, und legt sie im Repository ab:
Ich bin so an Git gewöhnt, dass mir das erschreckend vorkommt. Ohne die Möglichkeit, Änderungen vorzunehmen, kann jedes alte Ding, das Sie in Ihrem Arbeitsverzeichnis berührt haben, als Teil des öffentlichen Repositorys enden. Haben Sie passiv-aggressiv die schlecht implementierte Funktion eines Kollegen aus kathartischer Notwendigkeit neu geschrieben und nie beabsichtigt, dass er es weiß? Schade, er denkt jetzt, du bist ein Schwanz. Sie können Ihre Commits auch nicht bearbeiten, bevor Sie sie pushen, da ein Commit ein Push ist. Verbringen Sie gerne 40 Minuten damit, git rebase -i
wiederholt auszuführen, bis Ihr localcommit-Verlauf wie die Ableitung eines mathematischen Beweises fließt? Entschuldigung, das können Sie hier nicht tun, und jeder wird herausfinden, dass Sie Ihre Tests nicht zuerst schreiben.
Aber ich verstehe jetzt auch, warum so viele Leute Git unnötig kompliziert finden.Wenn cvs commit
das ist, woran Sie gewöhnt waren, dann bin ich mir sicher, dass Staging und pushingchanges Sie als sinnlose Aufgabe empfinden würden.
Wenn Leute davon sprechen, dass Git ein „verteiltes“ System ist, ist dies in erster Linie derunterschied, den sie meinen. In CVS können Sie keine Commits lokal vornehmen. Ein Commit ist einübermittlung von Code an das zentrale Repository, also können Sie es nicht ohne Verbindung tun. Alles, was Sie lokal haben, ist Ihr Arbeitsverzeichnis. In Git haben Sie ein vollwertiges lokales Repository, sodass Sie den ganzen Tag Commits machen könnenauch wenn die Verbindung unterbrochen ist. Und Sie können diese Commits bearbeiten, rückgängig machen, verzweigen und Cherry auswählen, so viel Sie möchten, ohne dass es jemand anderes wissen muss.
Da Commits eine größere Sache waren, machten CVS-Benutzer sie oft selten.Commits würden so viele Änderungen enthalten, wie wir heute in einem Pull-Request nach dem Commit erwarten könnten. Dies galt insbesondere, wenn Commits ein CIbuild und eine automatisierte Testsuite auslösten.
Wenn wir jetzt cvs status
ausführen, können wir sehen, dass wir eine neue Version unserer Datei haben:
Merging
Wie oben erwähnt, können Sie in CVS eine Datei bearbeiten, die bereits von jemand anderem bearbeitet wird. Das war CVS ‚große Verbesserung gegenüber RCS. Was passiert, wenn Sie Ihre Änderungen wieder zusammenbringen müssen?
Angenommen, Sie haben einige Freunde eingeladen, ihre Lieblingsfarben zu Ihrer Liste hinzuzufügen. Während sie ihre Farben hinzufügen, entscheiden Sie, dass Sie nicht mehrwie die Farbe grün und entfernen Sie es aus der Liste.
Wenn Sie Ihre Änderungen festschreiben, stellen Sie möglicherweise fest, dass CVS ein Problem bemerkt:
Es sieht so aus, als hätten Ihre Freunde ihre Änderungen zuerst festgeschrieben. Ihre Version vonfavorites.txt
ist also nicht mit der Version im Repository auf dem neuesten Stand. Wenn Ihr repository cvs status
, werden Sie sehen, dass Ihre lokale Kopie von favorites.txt
Version 1.2 mit einigen lokalen Änderungen ist, aber die Repository-Version ist 1.3:
Sie können cvs diff
ausführen, um genau zu sehen, was die Unterschiede zwischen 1.2 und1.3 sind:
Es scheint, dass unsere Freunde Pink wirklich mögen. In jedem Fall haben sie einen anderen Teil der Datei bearbeitet als wir, sodass die Änderungen leicht zusammengeführt werden können. CVScan macht das für uns, wenn wir cvs update
ausführen, was git pull
ähnelt:
$ 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
Wenn Sie sich jetzt favorites.txt
, Sie werden finden, dass es beenmodified ist, um die Änderungen einzuschließen, die Ihre Freunde zur Akte machten. Yourchanges sind auch noch da. Jetzt können Sie die Datei festschreiben:
Das Endergebnis ist das, was Sie in Git erhalten würden, indem Sie git pull --rebase
. Yourchanges wurden zusätzlich zu den Änderungen Ihrer Freunde hinzugefügt. Es gibt kein „mergecommit.“
Manchmal sind Änderungen an derselben Datei möglicherweise nicht kompatibel. Wenn Ihre Freunde beispielsweise „grün“ in „Oliv“ geändert hätten, hätte dies dazu geführt, dass yourchange „grün“ vollständig entfernt hätte. In den frühen Tagen von CVS war dies genau der Fall, der dazu führte, dass sich die Leute Sorgen machten, dass CVS nicht sicher war; Die pessimistische Verriegelung von RCS stellte sicher, dass ein solcher Fall niemals auftreten konnte. Aber CVS garantiert Sicherheit, indem es sicherstellt, dass die Änderungen von niemandem automatisch überschrieben werden. Wenn Sie also cvs update
, markiert CVS die Datei mit beiden Änderungen auf die gleiche Weise wie Git, wenn Git einen Zusammenführungskonflikt erkennt. Sie müssen dann die Datei manuell bearbeiten und die Änderung auswählen, die Sie beibehalten möchten.
Das Interessante an dieser Stelle ist, dass Mergekonflikte behoben werden müssen, bevor Sie ein Commit durchführen können. Dies ist eine weitere Folge der Zentralisierung von CVS nature.In Git, Sie müssen sich keine Gedanken über das Auflösen von Zusammenführungen machen, bis Sie die Commits, die Sie lokal haben, pushen.
Tags und Branches
Da CVS keine leicht adressierbaren Commit-Objekte hat, besteht die einzige Möglichkeit, eine Sammlung von Änderungen zu gruppieren, darin, einen bestimmten Arbeitsverzeichnisstatus mit atag zu markieren.
Das Erstellen eines Tags ist einfach:
$ cvs tag VERSION_1_0cvs tag: Tagging .T favorites.txt
Sie können später Dateien in diesen Zustand zurückversetzen, indem Sie cvs update
ausführen und das Tag an das Flag -r
übergeben:
$ cvs update -r VERSION_1_0cvs update: Updating .U favorites.txt
Da Sie ein Tag benötigen, um in einen früheren Arbeitsverzeichnisstatus zurückzuspulen, ermutigt CVSEN zu viel präventivem Tagging. Vor größeren Refactors können Sie beispielsweise ein BEFORE_REFACTOR_01
-Tag erstellen, das Sie später verwenden können, wenn therefactor schief gelaufen ist. Die Leute benutzten auch Tags, wenn sie projektweite Diffs generieren wollten. Grundsätzlich müssen alle Dinge, die wir heute routinemäßig mit Commithashes tun, mit CVS antizipiert und geplant werden, da Sie die Tags bereits verfügbar haben mussten.
Zweige können in CVS erstellt werden. Zweige sind nur eine besondere Art von Zweig:
$ cvs rtag -b TRY_EXPERIMENTAL_THING colorscvs rtag: Tagging colors
Das erstellt nur den Zweig (übrigens in voller Sicht für alle), also dumuss immer noch mit cvs update
:
$ cvs update -r TRY_EXPERIMENTAL_THING
Die obigen Befehle wechseln auf den neuen Zweig in Ihrem aktuellen Arbeitsverzeichnis, aber pragmatische Versionskontrolle Mit CVS empfiehlt tatsächlich, dass Sie ein neues Verzeichnis erstellen, um Ihren neuen Zweig zu halten. Vermutlich fanden seine Autorenverzeichnisse wechseln einfacher als Zweige in CVS wechseln.
Pragmatische Versionskontrolle Mit CVS rät auch davon ab, Branchesoff eines bestehenden Branches zu erstellen. Sie empfehlen, nur Zweige außerhalb des Mainline-Zweigs zu erstellen, der in Git als master
. Im Allgemeinen wurde Verzweigung betrachtetals „fortgeschrittene“ CVS-Fähigkeit. In Git können Sie einen neuen Zweig aus fast jedem trivialen Grund starten, aber in CVS wurde Verzweigung normalerweise nur verwendet, wenn dies wirklich notwendig war, z. B. für Releases.
Ein Zweig könnte später mit cvs update
und dem -j
-Flag wieder in die Hauptleitung eingefügt werden:
$ cvs update -j TRY_EXPERIMENTAL_THING
Danke für die Commit-Historien
2007 hielt Linus Torvalds einen Vortrag über Git bei Google. Git war damals sehr neu, daher war der Vortrag im Grunde ein Versuch, einen Raum voller skeptischer Programmierer davon zu überzeugen, dass sie Git verwenden sollten, obwohl sich Git von allem, was damals verfügbar war, unterschied. Wenn Sie den Vortrag noch nicht gesehen haben, Ich ermutige Sie dringend, ihn anzusehen. Linus ist ein unterhaltsamer Redner, auch wenn er es nie versäumt, sein dreistes Selbst zu sein. Er erklärt hervorragend warumDas verteilte Modell der Versionskontrolle ist besser als das zentralisierte. Ein Großteil seiner Kritik ist insbesondere CVS vorbehalten.
Git ist ein komplexes Werkzeug. Es zu lernen kann eine frustrierende Erfahrung sein. Aber ich bin auch immer wieder erstaunt über die Dinge, die Gitcan tun kann. Im Vergleich dazu ist CVS einfach und unkompliziert, obwohl es oft nicht möglich ist, viele der Vorgänge auszuführen, die wir jetzt für selbstverständlich halten. Zurück zu gehen und CVSfür eine Weile zu verwenden, ist eine hervorragende Möglichkeit, sich mit einer neuen Wertschätzung für die Leistung und Flexibilität von CVSZU finden. Es veranschaulicht gut, warum das Verständnis der Geschichte der Softwareentwicklung so vorteilhaft sein kann – wenn Sie veraltete Tools aufgreifen und erneut untersuchen, erfahren Sie mehr über das Warum hinter den Tools, die wir heute verwenden.
Wenn Ihnen dieser Beitrag gefallen hat, erscheint er alle vier Wochen! Folgen Sie @TwoBitHistory auf Twitter oder abonnieren Sie den RSS-Feed, um sicherzustellen, dass Sie wissen, wann ein neuer Beitrag veröffentlicht wird.
Korrektur
Mir wurde gesagt, dass es viele Organisationen gibt, insbesondere risikoadverse Organisationen, die Dinge wie die Herstellung von Software für medizinische Geräte tun, die immer noch CVS verwenden. Programmierer in diesen Organisationen haben kleine Tricks entwickelt, um die Einschränkungen von CVS zu umgehen, z. B. einen neuen Zweig für fast jede Änderung zu erstellen, um zu vermeiden, dass sie sich direkt an HEAD
. (Danke an Michael Kohne für den Hinweis.)