Git und Mercurial - Vergleichen und Kontrastieren


520

Seit einiger Zeit verwende ich Subversion für meine persönlichen Projekte.

Immer mehr höre ich großartige Dinge über Git und Mercurial und DVCS im Allgemeinen.

Ich würde dem ganzen DVCS-Ding gerne einen Strudel geben, aber ich bin mit beiden Optionen nicht allzu vertraut.

Was sind einige der Unterschiede zwischen Mercurial und Git?

Hinweis: Ich versuche nicht herauszufinden, welches "am besten" ist oder mit welchem ​​ich beginnen soll. Ich suche hauptsächlich nach Schlüsselbereichen, in denen sie ähnlich und unterschiedlich sind, weil ich interessiert bin, wie sie sich in Bezug auf Implementierung und Philosophie unterscheiden.



Antworten:


451

Haftungsausschluss: Ich benutze Git, verfolge die Git-Entwicklung auf der Git-Mailingliste und trage sogar ein bisschen zu Git bei (hauptsächlich Gitweb). Ich kenne Mercurial aus der Dokumentation und einige aus der Diskussion über den IRC-Kanal #revctrl auf FreeNode.

Vielen Dank an alle Leute auf dem #mercurial IRC-Kanal, die Hilfe zu Mercurial für diesen Artikel geleistet haben



Zusammenfassung

Hier wäre es schön, eine Syntax für die Tabelle zu haben, etwa in der PHPMarkdown / MultiMarkdown / Maruku-Erweiterung von Markdown

  • Repository-Struktur: Mercurial erlaubt keine Octopus-Zusammenführungen (mit mehr als zwei übergeordneten Elementen) und keine Kennzeichnung von nicht festgeschriebenen Objekten.
  • Tags: Mercurial verwendet eine versionierte .hgtagsDatei mit speziellen Regeln für Tags pro Repository und unterstützt auch lokale Tags in .hg/localtags. In Git-Tags befinden sich Refs, die sich im refs/tags/Namespace befinden. Standardmäßig werden sie beim Abrufen automatisch verfolgt und erfordern explizites Pushing.
  • Zweige: In Mercurial basiert der grundlegende Workflow auf anonymen Köpfen . Git verwendet leichtgewichtige benannte Zweige und verfügt über spezielle Arten von Zweigen ( Remote-Tracking-Zweige ), die den Zweigen im Remote-Repository folgen.
  • Revisionsnamen und -bereiche: Mercurial stellt lokale Revisionsnummern für das Repository bereit und stützt relative Revisionen (ab Tipp, dh aktueller Zweig) und Revisionsbereiche auf diese lokale Nummerierung. Git bietet eine Möglichkeit, sich auf die Revision relativ zur Verzweigungsspitze zu beziehen, und die Revisionsbereiche sind topologisch (basierend auf dem Revisionsdiagramm).
  • Mercurial verwendet die Umbenennungsverfolgung , während Git die Umbenennungserkennung verwendet , um die Umbenennung von Dateien zu verarbeiten
  • Netzwerk: Mercurial unterstützt "intelligente" SSH- und HTTP-Protokolle sowie statische HTTP-Protokolle. Das moderne Git unterstützt die "intelligenten" SSH-, HTTP- und GIT-Protokolle sowie das "dumme" HTTP (S) -Protokoll. Beide unterstützen Bundles-Dateien für den Offline-Transport.
  • Mercurial verwendet Erweiterungen (Plugins) und eine etablierte API. Git hat Skriptfähigkeit und etablierte Formate.

Es gibt einige Dinge, die Mercurial von Git unterscheiden, aber es gibt andere Dinge, die sie ähnlich machen. Beide Projekte leihen sich Ideen aus. Zum Beispiel wurde der hg bisectBefehl in Mercurial (ehemals halbierte Erweiterung ) vom git bisectBefehl in Git inspiriert , während die Idee von git bundleinspiriert wurde hg bundle.

Repository-Struktur, in der Revisionen gespeichert werden

In Git gibt es vier Arten von Objekten in seiner Objektdatenbank: Blob- Objekte, die den Inhalt einer Datei enthalten, hierarchische Baumobjekte , die die Verzeichnisstruktur speichern, einschließlich Dateinamen und relevanter Teile von Dateiberechtigungen (ausführbare Berechtigung für Dateien, als symbolischer Link) , Commit- Objekt, das Autoreninformationen enthält, Zeiger auf die Momentaufnahme des Repository-Status bei der Revision, dargestellt durch ein Commit (über ein Baumobjekt im obersten Projektverzeichnis) und Verweise auf null oder mehr übergeordnete Commits, und Tag Objekte, die auf andere Objekte verweisen und können mit PGP / GPG signiert sein.

Git verwendet zwei Möglichkeiten zum Speichern von Objekten: das lose Format, bei dem jedes Objekt in einer separaten Datei gespeichert wird (diese Dateien werden einmal geschrieben und nie geändert), und das gepackte Format, bei dem viele Objekte deltakomprimiert in einer einzigen Datei gespeichert werden. Die Atomizität von Operationen wird durch die Tatsache bereitgestellt, dass der Verweis auf ein neues Objekt nach dem Schreiben eines Objekts geschrieben wird (atomar unter Verwendung des Tricks zum Erstellen + Umbenennen).

Git-Repositorys müssen regelmäßig gewartet werden git gc(um den Speicherplatz zu reduzieren und die Leistung zu verbessern), obwohl Git dies heutzutage automatisch tut. (Diese Methode bietet eine bessere Komprimierung von Repositorys.)

Mercurial (soweit ich es verstehe) speichert den Verlauf einer Datei in einem Dateiprotokoll (zusammen mit zusätzlichen Metadaten wie Umbenennungsverfolgung und einigen Hilfsinformationen ). Es verwendet eine flache Struktur namens Manifest zum Speichern der Verzeichnisstruktur und eine Struktur namens Changelog der Informationen zu Änderungssätzen (Revisionen) gespeichert werden, einschließlich Festschreibungsnachricht und null, einem oder zwei übergeordneten Elementen.

Mercurial verwendet Transaktionsjournal Unteilbarkeit von Operationen zur Verfügung zu stellen, und stützt sich auf Kürzen Dateien clean-up nach gescheiterter oder unterbrochenen Betrieb. Revlogs können nur angehängt werden.

Wenn man sich die Repository-Struktur in Git im Vergleich zu Mercurial ansieht, kann man sehen, dass Git eher einer Objektdatenbank (oder einem inhaltsadressierten Dateisystem) und Mercurial eher einer herkömmlichen relationalen Datenbank mit festem Feld ähnelt.

Unterschiede:
In Git bilden die Baumobjekte eine hierarchische Struktur; in Mercurial Manifest Datei ist flache Struktur. Speichern Sie im Git- Blob- Objekt eine Version eines Inhalts einer Datei. In Mercurial speichert Filelog den gesamten Verlauf einer einzelnen Datei. (wenn wir hier keine Komplikationen bei der Umbenennung berücksichtigen). Dies bedeutet, dass es verschiedene Bereiche gibt, in denen Git schneller als Mercurial ist, alle anderen Dinge als gleich angesehen werden (z. B. Zusammenführungen oder Anzeigen des Projektverlaufs) und Bereiche, in denen Mercurial schneller als Git ist (z. B. Anwenden von Patches oder Anzeigen) Verlauf einer einzelnen Datei).Dieses Problem ist für den Endbenutzer möglicherweise nicht wichtig.

Aufgrund der festen Datensatzstruktur der Changelog- Struktur von Mercurial können Commits in Mercurial nur bis zu zwei Elternteile haben . Commits in Git können mehr als zwei Eltern haben (sogenannte "Octopus Merge"). Während Sie (theoretisch) die Octopus-Zusammenführung durch eine Reihe von Zusammenführungen mit zwei übergeordneten Elementen ersetzen können, kann dies bei der Konvertierung zwischen Mercurial- und Git-Repositorys zu Komplikationen führen.

Soweit ich weiß, hat Mercurial kein Äquivalent zu kommentierten Tags (Tag-Objekten) von Git. Ein Sonderfall von mit Anmerkungen versehenen Tags sind signierte Tags (mit PGP / GPG-Signatur). Äquivalente in Mercurial können mit GpgExtension erstellt werden , wobei diese Erweiterung zusammen mit Mercurial verteilt wird. Sie können in Mercurial kein nicht festgeschriebenes Objekt wie in Git markieren , aber das ist meiner Meinung nach nicht sehr wichtig (einige Git-Repositorys verwenden einen getaggten Blob, um den öffentlichen PGP-Schlüssel zu verteilen und signierte Tags zu überprüfen).

Referenzen: Zweige und Tags

In Git befinden sich Referenzen (Zweige, Fernverfolgungszweige und Tags) außerhalb der DAG von Commits (wie sie sollten). Verweise im refs/heads/Namespace ( lokale Zweige ) verweisen auf Commits und werden normalerweise durch "git commit" aktualisiert. Sie zeigen auf die Spitze (den Kopf) des Zweigs, deshalb so ein Name. Verweise im refs/remotes/<remotename>/Namespace ( Remote-Tracking-Zweige ) verweisen auf das Festschreiben, folgen Zweigen im Remote-Repository <remotename>und werden durch "git fetch" oder ein gleichwertiges Element aktualisiert. Verweise im refs/tags/Namespace ( Tags ) verweisen normalerweise auf Commits (Lightweight-Tags) oder Tag-Objekte (mit Anmerkungen versehene und signierte Tags) und sollen sich nicht ändern.

Stichworte

In Mercurial können Sie der Revision mithilfe eines Tags einen dauerhaften Namen geben . Tags werden ähnlich wie die Ignoriermuster gespeichert. Dies bedeutet, dass global sichtbare Tags in einer revisionsgesteuerten .hgtagsDatei in Ihrem Repository gespeichert werden. Dies hat zwei Konsequenzen: Erstens muss Mercurial spezielle Regeln für diese Datei verwenden, um die aktuelle Liste aller Tags abzurufen und diese Datei zu aktualisieren (z. B. liest es die zuletzt festgeschriebene Revision der Datei, nicht die derzeit ausgecheckte Version). Zweitens müssen Sie Änderungen an dieser Datei vornehmen, damit ein neues Tag für andere Benutzer / andere Repositorys sichtbar ist (soweit ich das verstehe).

Mercurial unterstützt auch lokale Tags , die in gespeichert hg/localtagssind und für andere nicht sichtbar sind (und natürlich nicht übertragbar sind).

In Git-Tags werden feste (konstante) benannte Verweise auf andere Objekte (normalerweise Tag-Objekte, die wiederum auf Commits verweisen) im refs/tags/Namespace gespeichert . Standardmäßig ruft git beim Abrufen oder Verschieben einer Revision automatisch Tags ab oder schiebt sie, die darauf hinweisen, dass Revisionen abgerufen oder verschoben werden. Trotzdem können Sie bis zu einem gewissen Grad steuern , welche Tags abgerufen oder gepusht werden.

Git behandelt Lightweight-Tags (die direkt auf Commits verweisen) und kommentierte Tags (die auf Tag-Objekte zeigen, die Tag-Nachrichten enthalten, die optional eine PGP-Signatur enthalten, die wiederum auf Commit verweist) etwas anders. Beispielsweise werden bei der Beschreibung standardmäßig nur kommentierte Tags berücksichtigt Commits mit "git beschreiben".

Git hat kein striktes Äquivalent zu lokalen Tags in Mercurial. Trotzdem empfehlen die Best Practices von git, ein separates öffentliches Bare-Repository einzurichten, in das Sie fertige Änderungen übertragen und von dem andere klonen und abrufen. Dies bedeutet, dass Tags (und Zweige), die Sie nicht pushen, für Ihr Repository privat sind. Auf der anderen Seite können Sie auch anderen Namensraum als verwenden heads, remotesoder tags, zum Beispiel local-tagsfür lokale Variablen.

Persönliche Meinung: Meiner Meinung nach sollten sich Tags außerhalb des Revisionsdiagramms befinden, da sie außerhalb des Revisionsdiagramms liegen (sie sind Zeiger auf das Revisionsdiagramm). Tags sollten nicht versioniert, aber übertragbar sein. Die Entscheidung von Mercurial, einen ähnlichen Mechanismus wie das Ignorieren von Dateien zu verwenden, bedeutet, dass entweder eine .hgtagsspezielle Behandlung erforderlich ist (Datei im Baum ist übertragbar, aber normalerweise versioniert) oder nur lokale Tags ( .hg/localtagsnicht versioniert). aber nicht übertragbar).

Geäst

In Git ist der lokale Zweig (Verzweigungsspitze oder Verzweigungskopf) ein benannter Verweis auf ein Commit, in dem neue Commits erstellt werden können. Zweig kann auch eine aktive Entwicklungslinie bedeuten, dh alle Commits, die von der Zweigspitze aus erreichbar sind. Lokale Zweige befinden sich im refs/heads/Namespace, z. B. lautet der vollständig qualifizierte Name des 'Master'-Zweigs' refs / Heads / Master '.

Der aktuelle Zweig in Git (dh ausgecheckter Zweig und Zweig, in den das neue Commit verschoben wird) ist der Zweig, auf den in der HEAD-Referenz verwiesen wird. Man kann HEAD direkt auf ein Commit zeigen lassen, anstatt eine symbolische Referenz zu sein. Diese Situation in einem anonymen, nicht benannten Zweig wird als losgelöster HEAD bezeichnet ("Git-Zweig" zeigt an, dass Sie sich in "(kein Zweig)" befinden).

In Mercurial gibt es anonyme Zweige (Zweigköpfe), und man kann Lesezeichen verwenden (über die Lesezeichenerweiterung ). Solche Lesezeichenzweige sind rein lokal und diese Namen waren (bis Version 1.6) mit Mercurial nicht übertragbar. Sie können rsync oder scp verwenden, um die .hg/bookmarksDatei in ein Remote-Repository zu kopieren . Sie können auch hg id -r <bookmark> <url>die Revisions-ID eines aktuellen Tippes eines Lesezeichens abrufen.

Da 1.6 Lesezeichen geschoben / gezogen werden können. Die Seite BookmarksExtension enthält einen Abschnitt zum Arbeiten mit Remote-Repositorys . Es gibt einen Unterschied darin, dass in Mercurial Lesezeichen global sind , während die Definition von 'remote' in Git auch die Zuordnung von Zweignamen von den Namen im Remote-Repository zu den Namen lokaler Remote-Tracking-Zweige beschreibt. Zum Beispiel refs/heads/*:refs/remotes/origin/*bedeutet Mapping, dass man den Status des 'Master'-Zweigs (' refs / Heads / Master ') im Remote-Repository im' Origin / Master'-Remote-Tracking-Zweig ('Refs / Remotes / Origin / Master') finden kann.

Mercurial hat auch sogenannte benannte Zweige , bei denen der Zweigname in ein Commit (in einem Änderungssatz) eingebettet ist . Dieser Name ist global (wird beim Abrufen übertragen). Diese Zweignamen werden permanent als Teil der Metadaten des Änderungssatzes aufgezeichnet. Mit dem modernen Mercurial können Sie den "benannten Zweig" schließen und die Aufzeichnung des Zweignamens beenden. Bei diesem Mechanismus werden Astspitzen im laufenden Betrieb berechnet.

Mercurials "benannte Zweige" sollten meiner Meinung nach stattdessen Commit-Labels genannt werden, weil es das ist, was sie sind. Es gibt Situationen, in denen "benannter Zweig" mehrere Tipps (mehrere kinderlose Festschreibungen) haben kann und auch aus mehreren nicht zusammenhängenden Teilen des Revisionsdiagramms bestehen kann.

Es gibt kein Äquivalent zu diesen Mercurial "eingebetteten Zweigen" in Git; Darüber hinaus ist Gits Philosophie, dass man zwar sagen kann, dass der Zweig ein Commit enthält, dies aber nicht bedeutet, dass ein Commit zu einem Zweig gehört.

Beachten Sie, dass in der Mercurial-Dokumentation weiterhin vorgeschlagen wird, separate Klone (separate Repositorys) zu verwenden, zumindest für langlebige Zweige (einzelner Zweig pro Repository-Workflow), auch bekannt als Verzweigen durch Klonen .

Zweige beim Schieben

Mercurial drückt standardmäßig alle Köpfe . Wenn Sie einen einzelnen Zweig (einen einzelnen Kopf ) verschieben möchten , müssen Sie die Spitzenrevision des Zweigs angeben, den Sie verschieben möchten. Sie können die Verzweigungsspitze anhand der Versionsnummer (lokal für das Repository), der Revisionskennung, des Lesezeichennamens (lokal für das Repository, wird nicht übertragen) oder des Namens der eingebetteten Verzweigung (benannter Zweig) angeben.

Soweit ich weiß, haben Sie diesen "benannten Zweig" in dem Repository, in das Sie pushen, wenn Sie eine Reihe von Revisionen pushen, die Commits enthalten, die im Mercurial-Sprachgebrauch als "benannter Zweig" gekennzeichnet sind. Dies bedeutet, dass die Namen solcher eingebetteten Zweige ("benannte Zweige") global sind (in Bezug auf Klone eines bestimmten Repositorys / Projekts).

Standardmäßig (abhängig von der push.defaultKonfigurationsvariablen) würde "git push" oder "git push < fern >" Git passende Zweige pushen , dh nur die lokalen Zweige, deren Entsprechung bereits im Remote-Repository vorhanden ist, in das Sie pushen. Sie können mit --allOption git-push ( "git push --all") drücken Alle Branchen , können Sie "git push <verwenden Remote > < branch >" ein schieben gegebenen einzelnen Zweig , und Sie können „git push verwenden < remote > HEAD ", um den aktuellen Zweig zu verschieben .

Bei alledem wird davon ausgegangen, dass Git nicht konfiguriert ist, welche Zweige über remote.<remotename>.push Konfigurationsvariablen übertragen werden sollen.

Zweige beim Abrufen

Hinweis: Hier verwende ich die Git-Terminologie, bei der "Abrufen" das Herunterladen von Änderungen aus dem Remote-Repository bedeutet, ohne diese Änderungen in die lokale Arbeit zu integrieren. Dies ist, was " git fetch" und " hg pull" tun.

Wenn ich es richtig verstehe, ruft Mercurial standardmäßig alle Köpfe aus dem Remote-Repository ab, aber Sie können einen Zweig angeben, der über " hg pull --rev <rev> <url>" oder " hg pull <url>#<rev>" abgerufen werden soll , um einen einzelnen Zweig zu erhalten . Sie können <rev> mithilfe der Revisionskennung, des Namens "benannter Zweig" (in das Änderungsprotokoll eingebetteter Zweig) oder des Lesezeichennamens angeben. Der Name des Lesezeichens wird jedoch (zumindest derzeit) nicht übertragen. Alle "benannten Zweige" -Revisionen, die Sie erhalten, gehören zum Übertragen. "hg pull" speichert Spitzen von Zweigen, die es als anonyme, unbenannte Köpfe abgerufen hat.

In Git werden standardmäßig (für 'origin' remote, das von "git clone" erstellt wurde, und für Fernbedienungen, die mit "git remote add" erstellt wurden) " git fetch" (oder " git fetch <remote>") alle Zweige aus dem Remote-Repository (aus dem refs/heads/Namespace) abgerufen und in gespeichert refs/remotes/Namespace. Dies bedeutet zum Beispiel, dass der Zweig mit dem Namen 'master' (vollständiger Name: 'refs / heads / master') in remote 'origin' als Remote-Tracking-Zweig 'origin / master' (vollständiger Name: 'refs / ' gespeichert) gespeichert (gespeichert) wird. Fernbedienungen / Herkunft / Master ').

Sie können einen einzelnen Zweig in Git git fetch <remote> <branch>abrufen, indem Sie - Git die angeforderten Zweige in FETCH_HEAD speichern, was Mercurial unbenannten Köpfen ähnelt.

Dies sind nur Beispiele für Standardfälle mit leistungsstarker Refspec- Git-Syntax: Mit Refspecs können Sie angeben und / oder konfigurieren, welche Zweige abgerufen werden sollen und wo sie gespeichert werden sollen. Zum Beispiel wird der Standardfall "Alle Zweige abrufen" durch "+ refs / Heads / *: refs / remotes / origin / *" als Platzhalter-Referenz angegeben, und "Einzelne Zweige abrufen" ist die Abkürzung für "refs / Heads / <branch>:". . Refspecs werden verwendet, um Namen von Zweigen (Refs) im Remote-Repository lokalen Refs-Namen zuzuordnen. Sie müssen jedoch nicht (viel) über refspecs wissen, um effektiv mit Git arbeiten zu können (hauptsächlich dank des Befehls "git remote").

Persönliche Meinung: Ich persönlich denke, dass "benannte Zweige" (mit in Änderungssatz-Metadaten eingebetteten Zweignamen) in Mercurial ein falsches Design mit seinem globalen Namespace sind, insbesondere für ein verteiltes Versionskontrollsystem. Nehmen wir zum Beispiel den Fall, dass sowohl Alice als auch Bob in ihren Repositories einen "benannten Zweig" mit dem Namen "for-joe" haben, Zweige, die nichts gemeinsam haben. In Joes Repository würden diese beiden Zweige jedoch als ein einziger Zweig misshandelt. Sie haben sich also irgendwie eine Konvention ausgedacht, die vor Zusammenstößen von Filialnamen schützt. Dies ist kein Problem mit Git, wo in Joes Repository "for-joe" -Zweig von Alice "alice / for-joe" und von Bob "bob / for-joe" wäre.

In den "Lesezeichenzweigen" von Mercurial fehlt derzeit ein zentraler Vertriebsmechanismus.

Unterschiede:
Dieser Bereich ist einer der Hauptunterschiede zwischen Mercurial und Git, wie James Woodyatt und Steve Losh in ihren Antworten sagten. Mercurial verwendet standardmäßig anonyme Lightweight-Codelines, die in ihrer Terminologie als "Köpfe" bezeichnet werden. Git verwendet leichtgewichtige benannte Zweige mit injektiver Zuordnung, um Namen von Zweigen im Remote-Repository Namen von Remote-Tracking-Zweigen zuzuordnen. Git "zwingt" Sie, Zweige zu benennen (nun, mit Ausnahme eines einzelnen unbenannten Zweigs, Situation namens "losgelöster HEAD"), aber ich denke, dies funktioniert besser mit verzweigungsintensiven Workflows wie dem Workflow für Themenverzweigungen, dh mehreren Zweigen in einem einzelnen Repository-Paradigma.

Namensrevisionen

In Git gibt es viele Möglichkeiten, Revisionen zu benennen (beschrieben zB in der git rev-parse manpage):

  • Der vollständige SHA1-Objektname (40-Byte-Hexadezimalzeichenfolge) oder ein Teilstring davon, der innerhalb des Repositorys eindeutig ist
  • Ein symbolischer Referenzname, z. B. 'master' (bezieht sich auf den Zweig 'master') oder 'v1.5.0' (bezieht sich auf den Tag) oder 'origin / next' (bezieht sich auf den Zweig für die Fernverfolgung)
  • Ein Suffix ^zum Revisionsparameter bedeutet das erste übergeordnete Element eines Festschreibungsobjekts und ^ndas n-te übergeordnete Element eines Zusammenführungs-Festschreibungsobjekts. Ein Suffix ~nfür den Revisionsparameter bedeutet den n-ten Vorfahren eines Commits in der geraden ersten übergeordneten Zeile. Diese Suffixe können kombiniert werden, um einen Revisionsspezifizierer zu bilden, der dem Pfad einer symbolischen Referenz folgt, z. B. 'pu ~ 3 ^ 2 ~ 3'.
  • Ausgabe von "git description", dh einem nächstgelegenen Tag, optional gefolgt von einem Bindestrich und einer Anzahl von Commits, gefolgt von einem Bindestrich, einem 'g' und einem abgekürzten Objektnamen, z. B. 'v1.6.5.1-75- g5bf8097 '.

Es gibt auch Revisionsspezifizierer mit Reflog, die hier nicht erwähnt werden. In Git hat jedes Objekt, sei es Commit, Tag, Tree oder Blob, seine SHA-1-Kennung. Es gibt eine spezielle Syntax wie z. B. 'next: Documentation' oder 'next: README', um auf den Baum (Verzeichnis) oder den Blob (Dateiinhalt) bei der angegebenen Revision zu verweisen.

Mercurial hat auch viele Möglichkeiten, Änderungssätze zu benennen (zB in der hg- Manpage beschrieben):

  • Eine einfache Ganzzahl wird als Revisionsnummer behandelt. Man muss bedenken, dass die Revisionsnummern für das jeweilige Repository lokal sind . In anderen Repositorys können sie unterschiedlich sein.
  • Negative Ganzzahlen werden als sequentielle Offsets von der Spitze behandelt, wobei -1 die Spitze, -2 die Revision vor der Spitze usw. bezeichnet. Sie sind auch lokal im Repository.
  • Eine eindeutige Revisionskennung (40-stellige hexadezimale Zeichenfolge) oder ein eindeutiges Präfix.
  • Ein Tag-Name (symbolischer Name, der mit einer bestimmten Revision verknüpft ist) oder ein Lesezeichenname (mit der Erweiterung: symbolischer Name, der mit einem bestimmten Kopf verknüpft ist, lokal für das Repository) oder ein "benannter Zweig" (Commit-Label; Revision angegeben durch "benannter Zweig") Tipp (kinderloses Festschreiben) aller Festschreibungen mit angegebenem Festschreibungsetikett, mit der größten Versionsnummer, wenn es mehr als einen solchen Tipp gibt)
  • Der reservierte Name "tip" ist ein spezielles Tag, das immer die neueste Revision identifiziert.
  • Der reservierte Name "null" gibt die Nullrevision an.
  • Der reservierte Name "." gibt das übergeordnete Arbeitsverzeichnis an.

Unterschiede
Wie Sie beim Vergleich der obigen Listen sehen können, bietet Mercurial Revisionsnummern an, die lokal im Repository gespeichert sind, während Git dies nicht tut. Auf der anderen Seite bietet Mercurial relative Offsets nur von 'tip' (aktueller Zweig) an, die lokal für das Repository sind (zumindest ohne ParentrevspecExtension ), während Git es erlaubt, jedes Commit anzugeben, das von jedem Tipp folgt.

Die neueste Version heißt HEAD in Git und "tip" in Mercurial. Es gibt keine Null-Revision in Git. Sowohl Mercurial als auch Git können viele root haben (können mehr als ein übergeordnetes Commit haben; dies ist normalerweise das Ergebnis von ehemals getrennten Projekten, die beitreten).

Siehe auch: Viele verschiedene Arten von Artikeln über Revisionsspezifizierer in Elijahs Blog (Newren's).

Persönliche Meinung: Ich denke, dass Revisionsnummern überbewertet sind (zumindest für verteilte Entwicklung und / oder nichtlineare / verzweigte Historie). Erstens müssen sie für ein verteiltes Versionskontrollsystem entweder lokal im Repository sein oder ein Repository auf besondere Weise als zentrale Nummerierungsbehörde behandeln. Zweitens können größere Projekte mit längerer Historie eine Anzahl von Revisionen im 5-stelligen Bereich aufweisen, sodass sie nur einen geringen Vorteil gegenüber auf 6-7 Zeichen verkürzten Revisionskennungen bieten und eine strikte Reihenfolge implizieren, während Revisionen nur teilweise geordnet sind (ich meine hier das Die Revisionen n und n + 1 müssen nicht Eltern und Kind sein.

Revisionsbereiche

In Git sind Revisionsbereiche topologisch . Die häufig verwendete A..BSyntax, die für den linearen Verlauf einen Revisionsbereich bedeutet, der bei A beginnt (aber A ausschließt) und bei B endet (dh der Bereich ist von unten offen ), ist eine Abkürzung ("syntaktischer Zucker") für ^A B, die für den Verlaufsdurchlauf Befehle alle bedeutet Commits, die von B aus erreichbar sind, mit Ausnahme derjenigen, die von A aus erreichbar sind. Dies bedeutet, dass das Verhalten des A..BBereichs vollständig vorhersehbar (und sehr nützlich) ist, auch wenn A kein Vorfahr von B ist: A..Bbedeutet dann den Bereich der Revisionen von gemeinsamen Vorfahren von A und B (Zusammenführungsbasis) ) zur Überarbeitung B.

In Mercurial basieren die Revisionsbereiche auf dem Bereich der Revisionsnummern . Der Bereich wird mithilfe der A:BSyntax angegeben und fungiert im Gegensatz zum Git-Bereich als geschlossenes Intervall . Auch Bereich B: A ist der Bereich A: B in umgekehrter Reihenfolge, was bei Git nicht der Fall ist (siehe jedoch den folgenden Hinweis zur A...BSyntax). Eine solche Einfachheit ist jedoch mit einem Preis verbunden: Der Revisionsbereich A: B ist nur dann sinnvoll, wenn A Vorfahr von B ist oder umgekehrt, dh mit linearer Historie; Andernfalls (ich denke das) ist der Bereich unvorhersehbar und das Ergebnis ist lokal für das Repository (da die Revisionsnummern lokal für das Repository sind).

Dies wird mit Mercurial 1.6 behoben, das einen neuen topologischen Revisionsbereich hat , wobei 'A..B' (oder 'A :: B') als die Menge von Änderungssätzen verstanden wird, die sowohl Nachkommen von X als auch Vorfahren von Y sind Ich denke, entspricht '--ancestry-path A..B' in Git.

Git hat auch Notation A...Bfür symmetrische Unterschiede von Revisionen; Dies bedeutet A B --not $(git merge-base A B), dass alle Commits von A oder B aus erreichbar sind, jedoch alle von beiden erreichbaren Commits (von gemeinsamen Vorfahren erreichbar) ausgeschlossen sind.

Umbenennen

Mercurial verwendet die Umbenennungsverfolgung , um die Umbenennung von Dateien zu verarbeiten. Dies bedeutet, dass die Informationen über die Tatsache, dass eine Datei umbenannt wurde, zum Festschreibungszeitpunkt gespeichert werden. In Mercurial werden diese Informationen im Formular "Enhanced Diff" in Filelog- Metadaten (File Revlog) gespeichert. Die Folge davon ist, dass Sie hg rename/ hg mv... verwenden müssen oder daran denken müssen, ausgeführt hg addremovezu werden, um eine auf Ähnlichkeit basierende Umbenennungserkennung durchzuführen.

Git ist unter Versionskontrollsystemen insofern einzigartig, als es die Umbenennungserkennung verwendet , um mit dem Umbenennen von Dateien umzugehen. Dies bedeutet, dass die Tatsache, dass die Datei umbenannt wurde, zu dem Zeitpunkt erkannt wird, zu dem sie benötigt wird: beim Zusammenführen oder beim Anzeigen eines Unterschieds (falls angefordert / konfiguriert). Dies hat den Vorteil, dass der Umbenennungserkennungsalgorithmus verbessert werden kann und zum Zeitpunkt des Festschreibens nicht eingefroren wird.

Sowohl Git als auch Mercurial erfordern die Verwendung der --followOption, um Umbenennungen zu folgen, wenn der Verlauf einer einzelnen Datei angezeigt wird. Beide können Umbenennungen folgen, wenn der zeilenweise Verlauf einer Datei in git blame/ angezeigt wird hg annotate.

In Git kann der git blameBefehl der Codebewegung folgen und auch Code von einer Datei in die andere verschieben (oder kopieren), selbst wenn die Codebewegung nicht Teil der vollständigen Umbenennung von Dateien ist. Soweit ich weiß, ist diese Funktion nur bei Git verfügbar (zum Zeitpunkt des Schreibens, Oktober 2009).

Netzwerkprotokolle

Sowohl Mercurial als auch Git unterstützen das Abrufen von und das Verschieben in Repositorys auf demselben Dateisystem, wobei die Repository-URL nur ein Dateisystempfad zum Repository ist. Beide unterstützen auch das Abrufen von Bundle-Dateien .

Mercurial-Unterstützung beim Abrufen und Pushing über SSH und über HTTP-Protokolle. Für SSH benötigt man ein zugängliches Shell-Konto auf dem Zielcomputer und eine Kopie von hg installiert / verfügbar. Für den HTTP-Zugriff ist das hg-servelaufende oder Mercurial CGI-Skript erforderlich, und Mercurial muss auf dem Server installiert werden.

Git unterstützt zwei Arten von Protokollen für den Zugriff auf das Remote-Repository:

  • Für "intelligente" Protokolle , die den Zugriff über SSH und über das benutzerdefinierte git: // -Protokoll (von git-daemon) umfassen, muss git auf dem Server installiert sein. Der Austausch in diesen Protokollen besteht darin, dass Client und Server darüber verhandeln, welche Objekte sie gemeinsam haben, und dann eine Packdatei generieren und senden. Modern Git unterstützt das "intelligente" HTTP-Protokoll.
  • Für "dumme" Protokolle , zu denen HTTP und FTP (nur zum Abrufen) und HTTPS (zum Pushen über WebDAV) gehören, muss kein Git auf dem Server installiert sein. Das Repository muss jedoch zusätzliche Informationen enthalten, die von git update-server-info(normalerweise von einem Hook ausgeführt) generiert werden ). Der Austausch besteht darin, dass der Client die Festschreibungskette durchläuft und bei Bedarf lose Objekte und Packdateien herunterlädt. Der Nachteil ist, dass das Herunterladen mehr als unbedingt erforderlich ist (z. B. in Eckfällen, in denen nur eine einzige Packdatei vorhanden ist, wird es sogar dann heruntergeladen, wenn nur wenige Revisionen abgerufen werden), und dass zum Abschluss viele Verbindungen erforderlich sein können.

Erweiterung: Skriptfähigkeit vs. Erweiterungen (Plugins)

Mercurial ist in Python implementiert , wobei einige Kerncodes für die Leistung in C geschrieben sind. Es bietet eine API zum Schreiben von Erweiterungen (Plugins), um zusätzliche Funktionen hinzuzufügen. Einige Funktionen, wie "Lesezeichenzweige" oder Signaturrevisionen, werden in Erweiterungen bereitgestellt, die mit Mercurial verteilt werden, und müssen aktiviert werden.

Git ist in C- , Perl- und Shell-Skripten implementiert . Git bietet viele Low-Level-Befehle ( Plumbing ), die für die Verwendung in Skripten geeignet sind. Die übliche Art, eine neue Funktion einzuführen, besteht darin, sie als Perl- oder Shell-Skript zu schreiben. Wenn sich die Benutzeroberfläche stabilisiert, schreiben Sie sie in C neu, um Leistung, Portabilität und im Fall von Shell-Skripten Eckfälle zu vermeiden (dieses Verfahren wird als integrierte Integration bezeichnet ).

Git basiert auf [Repository] -Formaten und [Netzwerk] -Protokollen. Anstelle von Sprachbindungen gibt es (teilweise oder vollständige) Neuimplementierungen von Git in anderen Sprachen (einige davon sind teilweise Neuimplementierungen und teilweise Umhüllungen von Git-Befehlen): JGit (Java, verwendet von EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), Git # (C #).


TL; DR


32
Was hinzugefügt werden könnte, ist, dass hg sehr bemüht ist, das Umschreiben des Verlaufs zu verhindern (dies kann nur mit den Erweiterungen mq, histedit, rebase durchgeführt werden), während git dies sofort tut (und es sieht aus wie ein Teil der Community) ermutigt es sogar).
Tonfa

80
Ich denke, "Geschichte neu schreiben" klingt unnötig negativ. Was ich in git ermutige, ist, dass die Leute über die Geschichte nachdenken, die sie veröffentlichen. Andere Menschen müssen diese Geschichte konsumieren. Niemand (nicht einmal Sie) interessiert sich für all Ihre Commits "Ups, habe eine Datei vergessen". Die Reihe der eingehenden Zusammenführungen, die Sie während der Verfolgung eines Upstream-Zweigs bei der Arbeit an einer neuen Funktion durchlaufen haben, interessiert niemanden. Diese Art von Dingen macht die Geschichte (und verwandte Werkzeuge) viel schwieriger zu verstehen und bietet keinen Wert.
Dustin

5
@Jakub: Benannte Zweige gibt es in git nicht. Es ist einfach ein Feld in der cset-Beschreibung (und das ist Teil des Verlaufs, daher ist es unveränderlich, es sei denn, Sie ändern Hashes usw.). So etwas wie Git-Zweige sind Lesezeichen ("benannte Köpfe"), aber sie sind derzeit nicht übertragbar (Sie importieren die entfernten Lesezeichen beim Ziehen nicht). stevelosh.com/blog/entry/2009/8/30/… erklärt es sehr gut.
Tonfa

28
"Mercurial hat ursprünglich nur einen Zweig pro Repository-Workflow unterstützt, und das zeigt es." Oh nein. Mercurial hat ursprünglich keine benannten Zweige unterstützt, aber Sie konnten immer so viele anonyme Zweige in einem einzigen Repo haben, wie Ihr Herz begehrt. Vergleichen Sie das mit git, was die anonyme Verzweigung zu einem großen Schmerz macht. Sie ziemlich viel haben für jeden kleinen Zweig eines Namens zu denken , wenn Sie etwas tun wollen (und zu vermeiden , dass Ihre Arbeit Müll gesammelt haben).
Steve Losh

17
@SteveLosh: Sie scheinen zu denken, dass es eine gute Sache ist, viele anonyme Filialen in Mercurial zu haben, aber für mich scheint es schrecklich. Wie unterscheidet man sie alle? Und Sie scheinen zu glauben, dass das Benennen von Zweigen in Git eine enorme Schwierigkeit darstellt, aber wenn Sie einen Zweck zum Erstellen des Zweigs haben, haben Sie einen vorgefertigten Namen. Wenn Sie keinen Zweck haben, verzweigen Sie nicht. Ich sehe nicht ein, wie Mercurial hier Vorteile bietet. Ich sehe nur Schmerz und Verwirrung.
Bilderstürmer

57

Ich denke, Sie können ein Gefühl dafür bekommen, wie ähnlich oder unterschiedlich diese Systeme sind, wenn Sie diese beiden Videos ansehen:

Linus Torvalds auf Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan auf Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )

Beide sind im Design sehr ähnlich, aber in den Implementierungen sehr unterschiedlich.

Ich benutze Mercurial. Soweit ich Git verstehe, ist eine wichtige Sache, die Git anders macht, dass es den Inhalt von Dateien anstelle von Dateien selbst verfolgt. Linus sagt, wenn Sie eine Funktion von einer Datei in eine andere verschieben, wird Git Ihnen den Verlauf dieser einzelnen Funktion während der Verschiebung mitteilen.

Sie sagen auch, dass Git über HTTP langsamer ist, aber es hat ein eigenes Netzwerkprotokoll und einen eigenen Server.

Git funktioniert als SVN-Thick-Client besser als Mercurial. Sie können gegen einen SVN-Server ziehen und drücken. Diese Funktionalität wird in Mercurial noch entwickelt

Sowohl Mercurial als auch Git bieten sehr gute Webhosting-Lösungen an (BitBucket und GitHub), aber Google Code unterstützt nur Mercurial. Übrigens haben sie einen sehr detaillierten Vergleich von Mercurial und Git, den sie durchgeführt haben, um zu entscheiden, welche unterstützt werden sollen ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Es hat viele gute Infos.


8
Ich würde empfehlen, alle Kommentare auf dieser Google-Codepage zu lesen. Die Informationen fühlen sich etwas voreingenommen an und passen nicht gut zu meiner Erfahrung. Ich mag hg und habe es ungefähr ein Jahr lang ausgiebig benutzt . Ich benutze jetzt fast ausschließlich Git. Es gibt Dinge, die ich tun muss, damit git einfach und hg fast unmöglich macht (obwohl manche dies gerne als "Komplikation" bezeichnen). Basic git ist so einfach wie base hg.
Dustin

11
Dustin, vielleicht einige dieser "git easy, hg nicht so sehr" Fälle auflisten?
Gregg Lind

1
@knittl nein tut es nicht. Hauptsächlich, weil es für sie schwierig wäre, es bereitzustellen, da git kein intelligentes http-Protokoll hat (die meisten Google-Frontends sind http-basiert).
Tonfa

2
@tonfa: Das intelligente HTTP-Protokoll für Git wird derzeit entwickelt (wie in: Es gibt Patches auf der Git-Mailingliste und sie befinden sich im Zweig 'pu' = vorgeschlagene Updates im git.git-Repository).
Jakub Narębski

4
Ab sofort unterstützt Google Code auch Git.
Andrej Kirejeŭ

30

Ich habe vor einiger Zeit einen Blogeintrag über die Verzweigungsmodelle von Mercurial geschrieben und Vergleiche mit dem Verzweigungsmodell von git aufgenommen. Vielleicht finden Sie es interessant: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/


@Steve Losh: Ich wollte einen Kommentar zu diesem Blogeintrag abgeben (über unbenannte Zweige, auch bekannt als losgelöster HEAD, und über Git-Fetch, der alle Zweige abruft, nicht einen), aber ich habe 500 Serverfehler erhalten.
Jakub Narębski

1
@ Jakub Narębski Ich wette, das Problem ist das Nicht-ASCII-Zeichen in Ihrem Namen. Ich bin mir ziemlich sicher, dass ich auf einer anderen Site auf dasselbe Problem gestoßen bin, und es stellte sich heraus, dass die Python Askimet-Bindung unter Unicode erstickt. Ich werde einen Blick darauf werfen.
Steve Losh

@Steve Losh: Danke für eine Info, nachdem ich meinen Namen "entschlüsselt" hatte, konnte ich einen Kommentar posten. Sehr gute Beschreibung der Verzweigung in Mercurial (aber ich denke immer noch, dass es minderwertig ist ;-))
Jakub Narębski

@SteveLosh Ich ermutige Sie, diese Antwort auf eine umfassendere Überprüfung von Quecksilber zu erweitern. Im Moment ist die Top-Antwort leider größtenteils eine Anzeige für Git, da der Autor Mercurial nicht ausgiebig verwendet hat und nicht versteht, wie man es effektiv einsetzt. Es wäre schön, wenn eine andere Antwort sozusagen den Quecksilber-Standpunkt liefern würde.
Warren Dew

25

Ich benutze beide ziemlich regelmäßig. Der Hauptfunktionsunterschied besteht in der Art und Weise, wie Git- und Mercurial-Namen innerhalb von Repositorys verzweigt werden. Mit Mercurial werden Zweignamen geklont und zusammen mit ihren Änderungssätzen abgerufen. Wenn Sie Änderungen an einem neuen Zweig in Mercurial hinzufügen und in ein anderes Repository verschieben, wird gleichzeitig der Name des Zweigs übertragen. Daher sind Zweigstellennamen in Mercurial mehr oder weniger global, und Sie müssen die Lesezeichenerweiterung verwenden, um nur lokale Lightweight-Namen zu erhalten (wenn Sie dies möchten; Mercurial verwendet standardmäßig anonyme Lightweight-Codelines, die in seiner Terminologie verwendet werden genannt "Köpfe"). In Git werden Zweignamen und ihre injektive Zuordnung zu Remote-Zweigen lokal gespeichert, und Sie müssen sie explizit verwalten. Dies bedeutet, dass Sie wissen, wie das geht.

Wie andere hier bemerken werden, gibt es viele, viele kleine Unterschiede. Die Sache mit den Zweigen ist das große Unterscheidungsmerkmal.


2
Siehe auch diesen Beitrag für eine gute Erklärung über die vier Arten von Zweigen in Mercurial: stevelosh.com/blog/entry/2009/8/30/…
Martin Geisler


11

Mercurial ist fast vollständig in Python geschrieben. Der Kern von Git ist in C geschrieben (und sollte schneller sein als der von Mercurial) und die Tools sind in sh, perl, tcl geschrieben und verwenden Standard-GNU-Utils. Daher müssen alle diese Dienstprogramme und Interpreter auf ein System gebracht werden, das sie nicht enthält (z. B. Windows).

Beide Unterstützungen funktionieren mit SVN, obwohl die AFAIK-SVN-Unterstützung für Git unter Windows unterbrochen ist (möglicherweise bin ich nur unglücklich / lahm, wer weiß). Es gibt auch Erweiterungen, die die Zusammenarbeit zwischen Git und Mercurial ermöglichen.

Mercurial hat eine schöne Visual Studio-Integration . Als ich das letzte Mal nachgesehen habe, funktionierte das Plugin für Git, war aber extrem langsam.

Die grundlegenden Befehlssätze sind sehr ähnlich (Init, Klonen, Hinzufügen, Status, Festschreiben, Drücken, Ziehen usw.). Der grundlegende Workflow ist also der gleiche. Außerdem gibt es für beide einen TortoiseSVN-ähnlichen Client.

Erweiterungen für Mercurial können in Python geschrieben werden (keine Überraschung!) Und für Git können sie in jeder ausführbaren Form (ausführbare Binärdatei, Shell-Skript usw.) geschrieben werden. Einige Erweiterungen sind verrückt mächtig, wie git bisect.


9
Mercurial Core ist zu Ihrer Information in C geschrieben (aber es ist wahrscheinlich ein kleinerer Core als Git).
Tonfa

1
Ich benutze git-svn unter Windows ohne Probleme. Das ist Cygwin (der einzig richtige Weg, um Git unter Windows zu verwenden, wenn Sie mich fragen). Ich kann nicht für msysgit sprechen.
Dan Moulding

@ Dan Moulding: Ja, ich habe Probleme mit msysgit. Vielleicht muss ich versuchen, den Cygwin-Port zu testen (ich hatte früher einige schlechte Erfahrungen mit Cygwin, also habe ich es vermieden). Danke für den Rat!
Elder_george

Ich persönlich mag Cygwins Eindringen in die Registrierung zum Speichern von Benutzerdaten nicht. Es ist eine PITA, damit der USB-Stick ausgeführt wird und eine lokale Kopie des Laufwerks c: \ synchronisiert bleibt, wenn ich schneller ausgeführt werden möchte, als mein USB-Stick funktionieren kann. : - /
Chris K

1
Ich verwende das oben erwähnte Git-Plugin für Visual Studio und die Leistung der aktuellen Version ist gut. Die Befehlszeilentools müssen die Arbeit erledigen, daher denke ich nicht, dass die Leistung bei großen Projekten erheblich beeinträchtigt wird.
Stuart Ellis

11

Wenn Sie eine gute Windows-Unterstützung benötigen, bevorzugen Sie möglicherweise Mercurial. TortoiseHg (Windows Explorer Plugin) bietet eine einfach zu verwendende grafische Oberfläche für ein ziemlich komplexes Tool. Als Status hier haben Sie auch ein Visual Studio-Plugin . Als ich es das letzte Mal versuchte, funktionierte die SVN-Oberfläche unter Windows nicht so gut.

Wenn Ihnen die Befehlszeilenschnittstelle nichts ausmacht, würde ich Git empfehlen. Nicht aus technischen Gründen, sondern aus strategischen Gründen. Die Adoptionsrate von Git ist viel höher. Sehen Sie nur, wie viele berühmte Open Source-Projekte von cvs / svn zu Mercurial wechseln und wie viele zu Git wechseln. Sehen Sie, wie viele Code- / Projekt-Hosting-Anbieter Sie mit Git-Unterstützung im Vergleich zu Mercurial-Hosting finden können.


Es gibt auch TortoiseGit, wenn Sie die Befehlszeile nicht verwenden möchten. (Aber es erfordert die Installation von msysgit.)
Ben James

2
Unser Unternehmen hat sich wegen seiner großartigen Unterstützung unter Windows für git entschieden - sehen Sie sich Git Extensions an . Ich bin voreingenommen, weil ich jetzt ein Mitwirkender bin, aber ich war es nicht, als wir anfingen, es zu benutzen.
Jacob Stanley

11

Nachdem ich überall gelesen hatte, dass Mercurial einfacher ist (was ich immer noch glaube, nachdem die gesamte Internet-Community der Meinung ist), fühlte ich, dass es für mich relativ einfacher ist, mich an Git anzupassen, als ich anfing, mit Git und Mercurial zu arbeiten (ich begann mit Mercurial mit TortoiseHg) bei der Arbeit über die Befehlszeile, hauptsächlich weil die git-Befehle meiner Meinung nach entsprechend benannt wurden und weniger zahlreich sind. Mercurial hat unterschiedliche Namen für jeden Befehl, der einen bestimmten Job ausführt, während Git-Befehle je nach Situation für mehrere Zwecke verwendet werden können (z.checkout). Während Git damals schwieriger war, ist der Unterschied jetzt kaum noch wesentlich. YMMV .. Mit einem guten GUI-Client wie TortoiseHg war es zwar viel einfacher, mit Mercurial zu arbeiten, und ich musste mich nicht an die etwas verwirrenden Befehle erinnern. Ich gehe nicht ins Detail, wie sich jeder Befehl für dieselbe Aktion unterschied, aber hier sind zwei umfassende Listen: 1 von Mercurials eigener Site und die2. von Wikivs .

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Git speichert intern eine Aufzeichnung jeder Version festgeschriebener Dateien, während Hg nur die Änderungssätze speichert, die einen geringeren Platzbedarf haben können. Git macht es einfacher, den Verlauf im Vergleich zu Hg zu ändern, aber es ist auch eine Hass-es-oder-Liebe-es-Funktion. Ich mag Hg für erstere und Git für letztere.

Was ich in Hg vermisse, ist das Submodul-Feature von Git. Hg hat Subrepos, aber das ist nicht genau das Git-Submodul.

Das Ökosystem um die beiden kann auch die Wahl beeinflussen: Git muss populärer sein (aber das ist trivial), Git hat GitHub, während Mercurial BitBucket hat , Mercurial TortoiseHg, für das ich kein Äquivalent für Git gesehen habe.

Jedes hat seine Vor- und Nachteile, mit beiden werden Sie nicht verlieren.


8

Schauen Sie sich den Beitrag von Scott Chacon an von vor einiger Zeit an.

Ich denke, Git hat den Ruf, "komplizierter" zu sein, obwohl es meiner Erfahrung nach nicht komplizierter ist, als es sein muss. IMO, das Git-Modell ist übrigens einfacher zu verstehen (Tags enthalten Commits (und Zeiger auf null oder mehr übergeordnete Commits) enthalten Bäume, die Blobs enthalten, und andere Bäume ... erledigt).

Es ist nicht nur meine Erfahrung, dass Git nicht verwirrender ist als Quecksilber. Ich würde empfehlen, diesen Blog-Beitrag von Scott Chacon zu diesem Thema noch einmal zu lesen .


1
Das Mercurial-Modell ist eigentlich fast identisch: Änderungsprotokoll zeigt auf Manifestpunkt auf Dateirevisionen / Blob ... fertig. Wenn Sie das Format auf der Festplatte verglichen haben, haben Sie wahrscheinlich die Packs-Datei nicht berücksichtigt, die schwieriger zu erklären ist als das einfache Revlog-Format von hg.
Tonfa

Nun, dieses vereinfachte Modell ignoriert das Tagging, was in der Praxis in hg erheblich umständlicher ist (obwohl ich behaupte, dass das Git-Tag etwas verwirrend ist, weil es standardmäßig kein Tag-Objekt erstellt). Das On-Disk-Format war besonders teuer für beide Projekte, bei denen in der Vergangenheit viele Dateinamen verwendet wurden.
Dustin

1
Ich glaube nicht, dass das Modell das Markieren ignoriert: Das Markieren ist in Mercurial trivial - wie Sie wissen, ist es nur eine Datei, die SHA-1-Hashes Namen gibt. Es gibt keine Vermutungen darüber, wie Tags im System herumfließen: Sie bewegen sich mit Drücken und Ziehen. Und wenn es einen Tag-Konflikt gibt, ist es auch trivial, ihn zu lösen: Sie lösen ihn wie jeden anderen Konflikt. Immerhin ist es nur eine Zeile in einer Textdatei. Ich denke, die Einfachheit dieses Modells ist eine sehr schöne Eigenschaft.
Martin Geisler

Dustin: Ja, Benutzer sind oft verwirrt darüber, dass Sie das 1.0-Tag .hgtagsbeim Auschecken von Version 1.0 nicht sehen können. Sie müssen jedoch nicht nach innen schauen .hgtagsund werden feststellen, dass hg tagsimmer noch alle Tags aufgelistet sind. Darüber hinaus ist dieses Verhalten eine einfache Folge des Speicherns von Tags in einer versionierten Datei - auch hier ist das Modell leicht zu erfassen und sehr vorhersehbar .
Martin Geisler

1
Martin Geisler Ich würde argumentieren, dass Regeln für Tags in Mercurial, die erforderlich sind, weil sie eine versionierte Datei für den Transport verwenden und spezielle Regeln enthalten, um Tags nicht versioniert zu machen, alles andere als einfach zu verstehen sind.
Jakub Narębski

5

Ich habe Git für etwas mehr als ein Jahr in meinem jetzigen Job verwendet und zuvor Mercurial für etwas mehr als ein Jahr in meinem vorherigen Job. Ich werde eine Bewertung aus der Sicht eines Benutzers abgeben.

Erstens sind beide verteilte Versionskontrollsysteme. Verteilte Versionskontrollsysteme erfordern eine Änderung der Denkweise gegenüber herkömmlichen Versionskontrollsystemen, funktionieren jedoch in vielerlei Hinsicht viel besser, sobald man sie versteht. Aus diesem Grund halte ich sowohl Git als auch Mercurial für viel besser als Subversion, Perforce usw. Der Unterschied zwischen verteilten Versionskontrollsystemen und herkömmlichen Versionskontrollsystemen ist viel größer als der Unterschied zwischen Git und Mercurial.

Es gibt jedoch auch signifikante Unterschiede zwischen Git und Mercurial, die jedes für seine eigene Teilmenge von Anwendungsfällen besser geeignet machen.

Mercurial ist einfacher zu lernen. Nach einigen Wochen mit Mercurial musste ich selten auf Unterlagen oder Notizen zurückgreifen. Ich muss immer noch regelmäßig mit Git auf meine Notizen zurückgreifen, auch nachdem ich sie ein Jahr lang verwendet habe. Git ist wesentlich komplizierter.

Dies liegt zum Teil daran, dass Mercurial einfach sauberer ist. In Mercurial müssen Sie selten manuell verzweigen. Mercurial erstellt automatisch einen anonymen Zweig für Sie, wenn Sie ihn benötigen. Die Mercurial-Nomenklatur ist intuitiver. Sie müssen sich nicht um den Unterschied zwischen "Fetch" und "Pull" kümmern, wie Sie es mit Git tun. Mercurial ist etwas weniger fehlerhaft. Es gibt Probleme mit der Groß- und Kleinschreibung von Dateinamen, die Probleme verursacht haben, wenn Projekte plattformübergreifend mit Git und Mercurial übertragen wurden. Dies wurde vor einiger Zeit in Mercurial behoben, während sie nicht zuletzt in Git behoben wurden. Sie können Mercurial über das Umbenennen von Dateien informieren. Wenn bei Git die Umbenennung nicht automatisch erkannt wird - meiner Erfahrung nach ein Hit oder Miss -, kann die Umbenennung überhaupt nicht verfolgt werden.

Der andere Grund für die zusätzliche Komplikation von Git ist jedoch, dass ein Großteil davon benötigt wird, um zusätzliche Funktionen und Leistung zu unterstützen. Ja, es ist komplizierter, die Verzweigung in Git zu handhaben - aber andererseits ist es nicht allzu schwierig, Dinge mit den Verzweigungen zu tun, die in Mercurial praktisch unmöglich sind, sobald Sie die Verzweigungen haben. Das Wiederherstellen von Zweigen ist eines der folgenden Dinge: Sie können Ihren Zweig so verschieben, dass seine Basis jetzt der Zustand des Stammes ist, anstatt der Zustand des Stammes zu sein, wenn Sie verzweigt haben. Dies vereinfacht den Versionsverlauf erheblich, wenn viele Personen an derselben Codebasis arbeiten, da jeder Push an den Trunk sequentiell und nicht miteinander verflochten sein kann. Ebenso ist es viel einfacher, mehrere Commits in Ihrem Zweig zu einem einzigen Commit zusammenzufassen.

Letztendlich denke ich, dass die Wahl zwischen Mercurial und Git davon abhängen sollte, wie groß Ihre Versionskontrollprojekte sind, gemessen an der Anzahl der Personen, die gleichzeitig daran arbeiten. Wenn beispielsweise eine Gruppe von einem Dutzend oder mehr an einer einzelnen monolithischen Webanwendung arbeitet, passen die leistungsstärkeren Tools für die Zweigstellenverwaltung von Git besser zu Ihrem Projekt. Wenn Ihr Team jedoch ein heterogen verteiltes System entwickelt, bei dem jeweils nur ein oder zwei Entwickler an einer Komponente arbeiten, ermöglicht die Verwendung eines Mercurial-Repositorys für jedes der Komponentenprojekte einen reibungsloseren Entwicklungsprozess mit weniger Overhead für die Repository-Verwaltung.

Fazit: Wenn Sie ein großes Team haben, das eine einzige große Anwendung entwickelt, verwenden Sie Git. Wenn Ihre einzelnen Anwendungen klein sind und eine Skala eher von der Anzahl als von der Größe solcher Anwendungen abhängt, verwenden Sie Mercurial.


4

Ein Unterschied, der völlig unabhängig von den DVCS selbst ist:

Git scheint bei C-Entwicklern sehr beliebt zu sein. Git ist das De-facto-Repository für den Linux-Kernel und dies könnte der Grund sein, warum es bei C-Entwicklern so beliebt ist. Dies gilt insbesondere für diejenigen, die den Luxus haben, nur in der Linux / Unix-Welt zu arbeiten.

Java-Entwickler scheinen Mercurial gegenüber Git zu bevorzugen. Dafür gibt es möglicherweise zwei Gründe: Einer ist, dass eine Reihe sehr großer Java-Projekte auf Mercurial gehostet werden, einschließlich des JDK selbst. Ein weiterer Grund ist, dass die Struktur und die saubere Dokumentation von Mercurial Personen ansprechen, die aus dem Java-Lager kommen, während diese Personen Git als inkonsistente Benennung von Wrt-Befehlen und mangelnde Dokumentation empfinden. Ich sage nicht, dass das tatsächlich wahr ist, ich sage, dass sich die Leute an etwas aus ihrem gewohnten Lebensraum gewöhnt haben und dann dazu neigen, DVCS daraus zu wählen.

Ich würde annehmen, dass Python-Entwickler Mercurial fast ausschließlich bevorzugen. Es gibt eigentlich keinen vernünftigen Grund dafür außer der Tatsache, dass Mercurial auf Python basiert. (Ich benutze auch Mercurial und verstehe wirklich nicht, warum die Leute sich über die Implementierungssprache des DVCS aufregen. Ich verstehe kein Wort von Python und wenn es nicht die Tatsache wäre, dass es irgendwo aufgelistet ist, dass es basiert auf Python, dann hätte ich es nicht gewusst).

Ich glaube nicht, dass man sagen kann, dass ein DVCS besser zu einer Sprache passt als ein anderes, also sollte man nicht daraus wählen. In Wirklichkeit wählen die Menschen (teilweise) anhand des DVCS, dem sie als Teil ihrer Community am meisten ausgesetzt sind.

(Nein, ich habe keine Nutzungsstatistik, um meine obigen Behauptungen zu stützen. Alles basiert auf meiner eigenen Subjektivität.)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.