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
.hgtags
Datei 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 bisect
Befehl in Mercurial (ehemals halbierte Erweiterung ) vom git bisect
Befehl in Git inspiriert , während die Idee von git bundle
inspiriert 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 .hgtags
Datei 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/localtags
sind 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
, remotes
oder tags
, zum Beispiel local-tags
fü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 .hgtags
spezielle Behandlung erforderlich ist (Datei im Baum ist übertragbar, aber normalerweise versioniert) oder nur lokale Tags ( .hg/localtags
nicht 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/bookmarks
Datei 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.default
Konfigurationsvariablen) 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 --all
Option 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 ^n
das n-te übergeordnete Element eines Zusammenführungs-Festschreibungsobjekts. Ein Suffix ~n
fü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..B
Syntax, 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..B
Bereichs vollständig vorhersehbar (und sehr nützlich) ist, auch wenn A kein Vorfahr von B ist: A..B
bedeutet 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:B
Syntax 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...B
Syntax). 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...B
fü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 addremove
zu 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 --follow
Option, 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 blame
Befehl 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-serve
laufende 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