-
1. Erste Schritte
- 1.1 Über Versionskontrolle
- 1.2 Eine kurze Geschichte von Git
- 1.3 Was ist Git?
- 1.4 Die Kommandozeile
- 1.5 Git installieren
- 1.6 Erstmalige Git-Einrichtung
- 1.7 Hilfe bekommen
- 1.8 Zusammenfassung
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches im Überblick
- 3.2 Grundlegendes Branching und Merging
- 3.3 Branch-Management
- 3.4 Branching-Workflows
- 3.5 Remote-Branches
- 3.6 Rebasing
- 3.7 Zusammenfassung
-
4. Git auf dem Server
- 4.1 Die Protokolle
- 4.2 Git auf einem Server einrichten
- 4.3 Generieren Ihres SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Drittanbieter-Hosting-Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git-Werkzeuge
- 7.1 Revisionsauswahl
- 7.2 Interaktives Staging
- 7.3 Stashing und Bereinigen
- 7.4 Ihre Arbeit signieren
- 7.5 Suchen
- 7.6 Historie umschreiben
- 7.7 Reset entmystifiziert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debugging mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Ersetzen
- 7.14 Credential-Speicher
- 7.15 Zusammenfassung
-
8. Git anpassen
-
9. Git und andere Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git-Interna
- 10.1 Plumbing und Porcelain
- 10.2 Git-Objekte
- 10.3 Git-Referenzen
- 10.4 Packfiles
- 10.5 Die Refspec
- 10.6 Übertragungsprotokolle
- 10.7 Wartung und Datenwiederherstellung
- 10.8 Umgebungsvariablen
- 10.9 Zusammenfassung
-
Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Oberflächen
- A1.2 Git in Visual Studio
- A1.3 Git in Visual Studio Code
- A1.4 Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git in Sublime Text
- A1.6 Git in Bash
- A1.7 Git in Zsh
- A1.8 Git in PowerShell
- A1.9 Zusammenfassung
-
Anhang B: Git in Ihre Anwendungen einbetten
- A2.1 Kommandozeilen-Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
Anhang C: Git-Befehle
- A3.1 Einrichtung und Konfiguration
- A3.2 Projekte abrufen und erstellen
- A3.3 Grundlegendes Snapshotting
- A3.4 Branching und Merging
- A3.5 Projekte teilen und aktualisieren
- A3.6 Inspektion und Vergleich
- A3.7 Debugging
- A3.8 Patching
- A3.9 E-Mail
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Plumbing-Befehle
5.3 Distributed Git - Ein Projekt pflegen
Ein Projekt pflegen
Zusätzlich zur Fähigkeit, effektiv zu einem Projekt beizutragen, müssen Sie wahrscheinlich auch wissen, wie man eines pflegt. Dies kann das Akzeptieren und Anwenden von Patches beinhalten, die per format-patch generiert und per E-Mail an Sie gesendet wurden, oder das Integrieren von Änderungen in Remote-Branches von Repositories, die Sie als Remotes zu Ihrem Projekt hinzugefügt haben. Ob Sie ein kanonisches Repository pflegen oder helfen möchten, indem Sie Patches überprüfen oder genehmigen, Sie müssen wissen, wie Sie Arbeit auf eine Weise akzeptieren, die für andere Mitwirkende am klarsten und für Sie auf lange Sicht am nachhaltigsten ist.
Arbeiten in Topic-Branches
Wenn Sie erwägen, neue Arbeiten zu integrieren, ist es im Allgemeinen eine gute Idee, sie in einem Topic-Branch auszuprobieren – einem temporären Branch, der speziell für das Ausprobieren dieser neuen Arbeit erstellt wurde. Auf diese Weise ist es einfach, einen Patch einzeln anzupassen und ihn zu belassen, wenn er nicht funktioniert, bis Sie Zeit haben, sich ihm wieder zuzuwenden. Wenn Sie einen einfachen Branch-Namen basierend auf dem Thema der Arbeit erstellen, die Sie ausprobieren möchten, wie z. B. ruby_client oder etwas ähnlich Beschreibendes, können Sie ihn leicht wiederfinden, wenn Sie ihn eine Weile aufgeben und später darauf zurückkommen müssen. Der Maintainer des Git-Projekts neigt dazu, diese Branches auch zu namentlich zu kennzeichnen – wie z. B. sc/ruby_client, wobei sc kurz für die Person ist, die die Arbeit beigesteuert hat. Wie Sie sich erinnern werden, können Sie den Branch von Ihrem master-Branch aus wie folgt erstellen:
$ git branch sc/ruby_client master
Oder, wenn Sie auch sofort zu ihm wechseln möchten, können Sie die Option checkout -b verwenden.
$ git checkout -b sc/ruby_client master
Jetzt sind Sie bereit, die beigesteuerte Arbeit, die Sie erhalten haben, in diesen Topic-Branch aufzunehmen und zu entscheiden, ob Sie sie in Ihre längerfristigen Branches integrieren möchten.
Patches per E-Mail anwenden
Wenn Sie per E-Mail einen Patch erhalten, den Sie in Ihr Projekt integrieren müssen, müssen Sie den Patch in Ihrem Topic-Branch anwenden, um ihn zu bewerten. Es gibt zwei Möglichkeiten, einen per E-Mail gesendeten Patch anzuwenden: mit git apply oder mit git am.
Patch mit apply anwenden
Wenn Sie den Patch von jemandem erhalten haben, der ihn mit git diff oder einer Variante des Unix-Befehls diff generiert hat (was nicht empfohlen wird; siehe nächster Abschnitt), können Sie ihn mit dem Befehl git apply anwenden. Angenommen, Sie haben den Patch unter /tmp/patch-ruby-client.patch gespeichert, können Sie den Patch wie folgt anwenden:
$ git apply /tmp/patch-ruby-client.patch
Dies modifiziert die Dateien in Ihrem Arbeitsverzeichnis. Es ist fast identisch mit dem Ausführen eines Befehls patch -p1 zum Anwenden des Patches, obwohl es paranoider ist und weniger Fuzzy-Übereinstimmungen als patch akzeptiert. Es behandelt auch das Hinzufügen, Löschen und Umbenennen von Dateien, wenn diese im git diff-Format beschrieben sind, was patch nicht tut. Schließlich ist git apply ein "alles anwenden oder alles abbrechen"-Modell, bei dem entweder alles angewendet wird oder nichts. Während patch Patchdateien teilweise anwenden kann und Ihr Arbeitsverzeichnis in einem seltsamen Zustand hinterlässt. git apply ist insgesamt wesentlich konservativer als patch. Es erstellt keinen Commit für Sie – nach der Ausführung müssen Sie die eingeführten Änderungen manuell vorbereiten und committen.
Sie können git apply auch verwenden, um zu sehen, ob ein Patch sauber angewendet werden kann, bevor Sie versuchen, ihn tatsächlich anzuwenden – Sie können git apply --check mit dem Patch ausführen.
$ git apply --check 0001-see-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Wenn keine Ausgabe erfolgt, sollte der Patch sauber angewendet werden. Dieser Befehl bricht auch mit einem Nicht-Null-Status ab, wenn die Prüfung fehlschlägt, sodass Sie ihn bei Bedarf in Skripten verwenden können.
Patch mit am anwenden
Wenn der Mitwirkende ein Git-Benutzer ist und gut genug war, den Befehl format-patch zur Generierung seines Patches zu verwenden, ist Ihre Arbeit einfacher, da der Patch Autoreninformationen und eine Commit-Nachricht für Sie enthält. Wenn möglich, ermutigen Sie Ihre Mitwirkenden, format-patch anstelle von diff zum Generieren von Patches für Sie zu verwenden. Sie sollten git apply nur für Legacy-Patches und ähnliches verwenden.
Um einen von format-patch generierten Patch anzuwenden, verwenden Sie git am (der Befehl heißt am, da er verwendet wird, um "eine Reihe von Patches aus einer Mailbox anzuwenden"). Technisch gesehen ist git am darauf ausgelegt, eine mbox-Datei zu lesen, die ein einfaches, plattformunabhängiges Textformat zum Speichern einer oder mehrerer E-Mail-Nachrichten in einer Textdatei ist. Sie sieht ungefähr so aus:
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] Add limit to log function
Limit log functionality to the first 20
Dies ist der Anfang der Ausgabe des Befehls git format-patch, den Sie im vorherigen Abschnitt gesehen haben; es stellt auch ein gültiges mbox-E-Mail-Format dar. Wenn jemand Ihnen den Patch ordnungsgemäß mit git send-email zugesendet hat und Sie ihn in mbox-Format heruntergeladen haben, können Sie git am auf diese mbox-Datei verweisen, und er beginnt, alle Patches anzuwenden, die er findet. Wenn Sie einen Mail-Client verwenden, der mehrere E-Mails im mbox-Format speichern kann, können Sie ganze Patch-Serien in einer Datei speichern und dann git am verwenden, um sie einzeln anzuwenden.
Wenn jemand jedoch eine Patch-Datei, die über git format-patch generiert wurde, in ein Ticketing-System oder etwas Ähnliches hochgeladen hat, können Sie die Datei lokal speichern und diese gespeicherte Datei an git am übergeben, um sie anzuwenden:
$ git am 0001-limit-log-function.patch
Applying: Add limit to log function
Sie können sehen, dass es sauber angewendet wurde und automatisch den neuen Commit für Sie erstellt hat. Die Autoreninformationen werden aus den E-Mail-Headern From und Date übernommen, und die Nachricht des Commits wird aus dem Subject und dem Körper (vor dem Patch) der E-Mail entnommen. Wenn dieser Patch beispielsweise aus dem obigen mbox-Beispiel angewendet worden wäre, würde der generierte Commit ungefähr so aussehen:
$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author: Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit: Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700
Add limit to log function
Limit log functionality to the first 20
Die Informationen Commit geben die Person an, die den Patch angewendet hat, und die Zeit, zu der er angewendet wurde. Die Informationen Author sind die Person, die den Patch ursprünglich erstellt hat, und wann er ursprünglich erstellt wurde.
Es ist jedoch möglich, dass der Patch nicht sauber angewendet werden kann. Möglicherweise hat sich Ihr Haupt-Branch zu weit vom Branch entfernt, auf dem der Patch erstellt wurde, oder der Patch hängt von einem anderen Patch ab, den Sie noch nicht angewendet haben. In diesem Fall schlägt der git am-Prozess fehl und fragt Sie, was Sie tun möchten:
$ git am 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".
Dieser Befehl fügt Konfliktmarker in alle Dateien ein, mit denen er Probleme hat, ähnlich wie bei einem konfliktreichen Merge- oder Rebase-Vorgang. Sie lösen dieses Problem auf ähnliche Weise – bearbeiten Sie die Datei, um den Konflikt zu lösen, bereiten Sie die neue Datei vor und führen Sie dann git am --resolved aus, um zum nächsten Patch zu gelangen.
$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: See if this helps the gem
Wenn Sie möchten, dass Git versucht, den Konflikt etwas intelligenter zu lösen, können Sie ihm eine Option -3 übergeben, die Git veranlasst, einen Drei-Wege-Merge zu versuchen. Diese Option ist nicht standardmäßig aktiviert, da sie nicht funktioniert, wenn der Commit, auf dem der Patch basiert, nicht in Ihrem Repository vorhanden ist. Wenn Sie diesen Commit haben – wenn der Patch auf einem öffentlichen Commit basiert –, dann ist die Option -3 im Allgemeinen wesentlich intelligenter beim Anwenden eines konfliktreichen Patches.
$ git am -3 0001-see-if-this-helps-the-gem.patch
Applying: See if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
In diesem Fall wäre der Patch ohne die Option -3 als Konflikt betrachtet worden. Da die Option -3 verwendet wurde, wurde der Patch sauber angewendet.
Wenn Sie eine Reihe von Patches aus einer mbox-Datei anwenden, können Sie den Befehl am auch im interaktiven Modus ausführen, der bei jedem gefundenen Patch stoppt und fragt, ob Sie ihn anwenden möchten.
$ git am -3 -i mbox
Commit Body is:
--------------------------
See if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
Das ist praktisch, wenn Sie eine Reihe von Patches gespeichert haben, da Sie den Patch zuerst anzeigen können, wenn Sie sich nicht mehr daran erinnern, was er ist, oder den Patch nicht anwenden, wenn Sie ihn bereits getan haben.
Wenn alle Patches für Ihr Thema angewendet und in Ihren Branch committet wurden, können Sie entscheiden, ob und wie Sie sie in einen längerfristigen Branch integrieren möchten.
Remote-Branches auschecken
Wenn Ihr Beitrag von einem Git-Benutzer stammt, der sein eigenes Repository eingerichtet, eine Reihe von Änderungen darin gepusht und Ihnen dann die URL des Repositories und den Namen des Remote-Branches, in dem sich die Änderungen befinden, gesendet hat, können Sie ihn als Remote hinzufügen und lokal mergen.
Wenn Jessica Ihnen beispielsweise eine E-Mail sendet, in der sie sagt, dass sie eine großartige neue Funktion im Branch ruby-client ihres Repositories hat, können Sie sie testen, indem Sie das Remote hinzufügen und diesen Branch lokal auschecken:
$ git remote add jessica https://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
Wenn sie Ihnen später mit einem weiteren Branch mit einer weiteren großartigen Funktion eine E-Mail sendet, könnten Sie direkt fetch und checkout verwenden, da Sie das Remote bereits eingerichtet haben.
Dies ist am nützlichsten, wenn Sie konsistent mit einer Person arbeiten. Wenn jemand nur einen Patch beisteuern muss und das nur gelegentlich tut, ist es weniger zeitaufwendig, ihn per E-Mail zu akzeptieren, als zu verlangen, dass jeder seinen eigenen Server betreibt und ständig Remotes hinzufügen und entfernen muss, um ein paar Patches zu erhalten. Wahrscheinlich möchten Sie auch nicht Hunderte von Remotes haben, jedes für jemanden, der nur ein oder zwei Patches beiträgt. Skripte und gehostete Dienste können dies jedoch erleichtern – es hängt stark davon ab, wie Sie entwickeln und wie Ihre Mitwirkenden entwickeln.
Der andere Vorteil dieses Ansatzes ist, dass Sie auch die Historie der Commits erhalten. Obwohl Sie legitime Merge-Probleme haben können, wissen Sie, wo in Ihrer Historie ihre Arbeit basiert; ein ordnungsgemäßes Drei-Wege-Merge ist der Standard, anstatt ein -3 angeben zu müssen und zu hoffen, dass der Patch auf einem öffentlichen Commit basiert, auf den Sie Zugriff haben.
Wenn Sie nicht konsistent mit einer Person arbeiten, aber trotzdem auf diese Weise von ihr ziehen möchten, können Sie die URL des Remote-Repositories an den Befehl git pull übergeben. Dies führt einen einmaligen Pull durch und speichert die URL nicht als Remote-Referenz.
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
Bestimmen, was eingeführt wird
Nun haben Sie einen Topic-Branch, der beigesteuerte Arbeit enthält. An diesem Punkt können Sie bestimmen, was Sie damit tun möchten. Dieser Abschnitt wiederholt einige Befehle, damit Sie sehen können, wie Sie sie verwenden können, um genau zu überprüfen, was Sie einführen werden, wenn Sie dies in Ihren Haupt-Branch integrieren.
Es ist oft hilfreich, eine Übersicht über alle Commits zu erhalten, die in diesem Branch enthalten sind, aber nicht in Ihrem master-Branch. Sie können Commits im master-Branch ausschließen, indem Sie die Option --not vor dem Branch-Namen hinzufügen. Dies bewirkt dasselbe wie das Format master..contrib, das wir zuvor verwendet haben. Wenn Ihnen Ihr Mitwirkender beispielsweise zwei Patches sendet und Sie einen Branch namens contrib erstellen und diese Patches dort anwenden, können Sie dies ausführen:
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
See if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
Update gemspec to hopefully work better
Um zu sehen, welche Änderungen jeder Commit einführt, denken Sie daran, dass Sie die Option -p an git log übergeben können und sie den Diff, der mit jedem Commit eingeführt wurde, anhängt.
Um einen vollständigen Diff dessen zu sehen, was passieren würde, wenn Sie diesen Topic-Branch mit einem anderen Branch zusammenführen würden, müssen Sie möglicherweise einen seltsamen Trick anwenden, um die korrekten Ergebnisse zu erzielen. Sie denken vielleicht, Sie würden dies ausführen:
$ git diff master
Dieser Befehl gibt Ihnen einen Diff, aber er kann irreführend sein. Wenn sich Ihr master-Branch weiterentwickelt hat, seit Sie den Topic-Branch davon erstellt haben, erhalten Sie scheinbar seltsame Ergebnisse. Dies geschieht, weil Git die Snapshots des letzten Commits des Topic-Branches, auf dem Sie sich befinden, und den Snapshot des letzten Commits im master-Branch direkt vergleicht. Wenn Sie beispielsweise eine Zeile in einer Datei im master-Branch hinzugefügt haben, sieht ein direkter Vergleich der Snapshots so aus, als würde der Topic-Branch diese Zeile entfernen.
Wenn master ein direkter Vorfahre Ihres Topic-Branches ist, ist dies kein Problem; aber wenn sich die beiden Historien verzweigt haben, sieht der Diff so aus, als würden Sie all die neuen Dinge in Ihrem Topic-Branch hinzufügen und alles entfernen, was für den master-Branch einzigartig ist.
Was Sie wirklich sehen möchten, sind die Änderungen, die dem Topic-Branch hinzugefügt wurden – die Arbeit, die Sie einführen werden, wenn Sie diesen Branch mit master zusammenführen. Dies erreichen Sie, indem Sie Git den letzten Commit Ihres Topic-Branches mit dem ersten gemeinsamen Vorfahren vergleichen, den er mit dem master-Branch hat.
Technisch gesehen können Sie dies tun, indem Sie explizit den gemeinsamen Vorfahren ermitteln und dann Ihren Diff darauf ausführen:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
oder, prägnanter:
$ git diff $(git merge-base contrib master)
Keine dieser Optionen ist jedoch besonders praktisch, daher bietet Git eine weitere Abkürzung dafür: die Dreipunkt-Syntax. Im Kontext des Befehls git diff können Sie drei Punkte nach einem anderen Branch setzen, um einen diff zwischen dem letzten Commit des Branches, auf dem Sie sich befinden, und seinem gemeinsamen Vorfahren mit einem anderen Branch durchzuführen.
$ git diff master...contrib
Dieser Befehl zeigt Ihnen nur die Arbeit, die Ihr aktueller Topic-Branch seit seinem gemeinsamen Vorfahren mit master eingeführt hat. Das ist eine sehr nützliche Syntax, die Sie sich merken sollten.
Beigesteuerte Arbeit integrieren
Wenn alle Arbeiten in Ihrem Topic-Branch bereit sind, in einen Haupt-Branch integriert zu werden, stellt sich die Frage, wie das geschehen soll. Darüber hinaus, welchen allgemeinen Workflow möchten Sie verwenden, um Ihr Projekt zu pflegen? Sie haben eine Reihe von Optionen, daher werden wir einige davon abdecken.
Merge-Workflows
Ein grundlegender Workflow ist, einfach all diese Arbeit direkt in Ihren master-Branch zu mergen. In diesem Szenario haben Sie einen master-Branch, der im Grunde stabilen Code enthält. Wenn Sie Arbeit in einem Topic-Branch haben, die Sie für abgeschlossen halten, oder Arbeit, die jemand anderes beigesteuert hat und die Sie überprüft haben, mergen Sie sie in Ihren Master-Branch, löschen Sie diesen gerade gemergten Topic-Branch und wiederholen Sie den Vorgang.
Wenn wir beispielsweise ein Repository mit Arbeit in zwei Branches namens ruby_client und php_client haben, das wie in Historie mit mehreren Topic-Branches aussieht, und wir ruby_client gefolgt von php_client mergen, wird Ihre Historie wie in Nach einem Topic-Branch-Merge aussehen.
Das ist wahrscheinlich der einfachste Workflow, aber er kann problematisch sein, wenn Sie mit größeren oder stabileren Projekten arbeiten, bei denen Sie sehr vorsichtig sein möchten, was Sie einführen.
Wenn Sie ein wichtigeres Projekt haben, möchten Sie vielleicht einen Zwei-Phasen-Merge-Zyklus verwenden. In diesem Szenario haben Sie zwei langfristige Branches, master und develop, in denen Sie festlegen, dass master nur aktualisiert wird, wenn eine sehr stabile Version veröffentlicht wird und aller neuer Code in den develop-Branch integriert wird. Sie pushen beide Branches regelmäßig in das öffentliche Repository. Jedes Mal, wenn Sie einen neuen Topic-Branch zum Mergen haben (Vor einem Topic-Branch-Merge), mergen Sie ihn in develop (Nach einem Topic-Branch-Merge); dann, wenn Sie eine Version taggen, führen Sie master auf den nun stabilen develop-Branch vorwärts (Nach einer Projektveröffentlichung).
Auf diese Weise können Personen, die das Repository Ihres Projekts klonen, entweder master auschecken, um die neueste stabile Version zu erstellen und leicht auf dem neuesten Stand zu bleiben, oder sie können develop auschecken, das den moderneren Inhalt enthält. Sie können dieses Konzept auch erweitern, indem Sie einen integrate-Branch haben, in dem alle Arbeiten zusammengeführt werden. Dann, wenn die Codebasis dieses Branches stabil ist und Tests besteht, mergen Sie sie in einen develop-Branch; und wenn dieser eine Weile lang stabil geblieben ist, führen Sie Ihren master-Branch vorwärts.
Workflows für große Merges
Das Git-Projekt hat vier langfristige Branches: master, next und seen (früher 'pu' – vorgeschlagene Updates) für neue Arbeiten und maint für Wartungs-Backports. Wenn neue Arbeiten von Mitwirkenden eingeführt werden, werden sie in Topic-Branches im Repository des Maintainers gesammelt, ähnlich wie wir es beschrieben haben (siehe Verwaltung einer komplexen Serie paralleler Topic-Branches). Zu diesem Zeitpunkt werden die Themen bewertet, um zu bestimmen, ob sie sicher und zur Aufnahme bereit sind oder ob sie weitere Arbeit benötigen. Wenn sie sicher sind, werden sie in next gemergt und dieser Branch wird hochgepusht, damit jeder die integrierten Themen gemeinsam ausprobieren kann.
Wenn die Themen noch Arbeit benötigen, werden sie stattdessen in seen gemergt. Wenn festgestellt wird, dass sie absolut stabil sind, werden die Themen erneut in master gemergt. Die Branches next und seen werden dann aus master neu erstellt. Das bedeutet, dass master fast immer voranschreitet, next gelegentlich rebased wird und seen noch häufiger rebased wird.
Wenn ein Topic-Branch endlich in master gemergt wurde, wird er aus dem Repository entfernt. Das Git-Projekt hat auch einen maint-Branch, der vom letzten Release abzweigt, um Backport-Patches bereitzustellen, falls ein Wartungsrelease erforderlich ist. Wenn Sie also das Git-Repository klonen, haben Sie vier Branches, die Sie auschecken können, um das Projekt in verschiedenen Entwicklungsphasen zu bewerten, abhängig davon, wie aktuell Sie sein möchten oder wie Sie beitragen möchten; und der Maintainer hat einen strukturierten Workflow, der ihm hilft, neue Beiträge zu überprüfen. Der Workflow des Git-Projekts ist spezialisiert. Um dies klar zu verstehen, könnten Sie sich die Git Maintainer's Guide ansehen.
Rebase- und Cherry-Pick-Workflows
Andere Maintainer bevorzugen es, beigesteuerte Arbeit auf ihren master-Branch zu rebasen oder zu cherry-picken, anstatt sie zu mergen, um eine meist lineare Historie beizubehalten. Wenn Sie Arbeit in einem Topic-Branch haben und entschieden haben, dass Sie sie integrieren möchten, wechseln Sie zu diesem Branch und führen Sie den Rebase-Befehl aus, um die Änderungen auf Ihrer aktuellen master- (oder develop-, usw.) Branch neu zu erstellen. Wenn dies gut funktioniert, können Sie Ihren master-Branch vorwärts verschieben, und Sie erhalten eine lineare Projektgeschichte.
Die andere Möglichkeit, eingeführte Arbeit von einem Branch zu einem anderen zu verschieben, ist das Cherry-Picking. Ein Cherry-Pick in Git ist wie ein Rebase für einen einzelnen Commit. Es nimmt den Patch, der in einem Commit eingeführt wurde, und versucht, ihn auf dem Branch anzuwenden, auf dem Sie sich gerade befinden. Dies ist nützlich, wenn Sie eine Reihe von Commits in einem Topic-Branch haben und nur einen davon integrieren möchten, oder wenn Sie nur einen Commit in einem Topic-Branch haben und es vorziehen, ihn zu cherry-picken, anstatt einen Rebase auszuführen. Angenommen, Sie haben ein Projekt, das so aussieht:
Wenn Sie den Commit e43a6 in Ihren master-Branch ziehen möchten, können Sie ausführen:
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
Dies zieht die gleiche Änderung, die in e43a6 eingeführt wurde, aber Sie erhalten einen neuen Commit SHA-1-Wert, da das Anwendungsdatum anders ist. Jetzt sieht Ihre Historie so aus:
Jetzt können Sie Ihren Topic-Branch entfernen und die Commits löschen, die Sie nicht ziehen wollten.
Rerere
Wenn Sie viele Merges und Rebase durchführen oder einen langlebigen Topic-Branch pflegen, hat Git eine Funktion namens "rerere", die helfen kann.
Rerere steht für "reuse recorded resolution" (Wiederverwendung aufgezeichneter Lösungen) – es ist eine Möglichkeit, manuelles Konfliktmanagement zu umgehen. Wenn rerere aktiviert ist, behält Git einen Satz von Vor- und Nachbildern erfolgreicher Merges bei, und wenn es bemerkt, dass ein Konflikt auftritt, der genau wie einer aussieht, den Sie bereits behoben haben, verwendet es einfach die Behebung von letztem Mal, ohne Sie damit zu belästigen.
Diese Funktion besteht aus zwei Teilen: einer Konfigurationseinstellung und einem Befehl. Die Konfigurationseinstellung ist rerere.enabled, und sie ist praktisch genug, um sie in Ihre globale Konfiguration aufzunehmen:
$ git config --global rerere.enabled true
Jetzt wird jedes Mal, wenn Sie einen Merge durchführen, der Konflikte löst, die Lösung im Cache aufgezeichnet, falls Sie sie in Zukunft benötigen.
Wenn nötig, können Sie mit dem Befehl git rerere mit dem rerere-Cache interagieren. Wenn er allein aufgerufen wird, prüft Git seine Datenbank mit Lösungen und versucht, eine Übereinstimmung mit aktuellen Merge-Konflikten zu finden und diese zu lösen (obwohl dies automatisch geschieht, wenn rerere.enabled auf true gesetzt ist). Es gibt auch Unterbefehle, um anzuzeigen, was aufgezeichnet wird, um eine bestimmte Lösung aus dem Cache zu löschen und den gesamten Cache zu löschen. Wir werden rerere im Detail in Rerere behandeln.
Ihre Releases taggen
Wenn Sie sich entschieden haben, eine Version zu erstellen, möchten Sie wahrscheinlich ein Tag zuweisen, damit Sie diese Version zu jedem zukünftigen Zeitpunkt neu erstellen können. Sie können ein neues Tag erstellen, wie in Git Basics beschrieben. Wenn Sie sich als Maintainer entscheiden, das Tag zu signieren, kann das Taggen etwa so aussehen:
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
Wenn Sie Ihre Tags signieren, haben Sie möglicherweise das Problem, den öffentlichen PGP-Schlüssel zu verteilen, der zum Signieren Ihrer Tags verwendet wird. Der Maintainer des Git-Projekts hat dieses Problem gelöst, indem er seinen öffentlichen Schlüssel als Blob im Repository aufgenommen und dann ein Tag hinzugefügt hat, das direkt auf diesen Inhalt verweist. Um dies zu tun, können Sie herausfinden, welchen Schlüssel Sie möchten, indem Sie gpg --list-keys ausführen.
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
Dann können Sie den Schlüssel direkt in die Git-Datenbank importieren, indem Sie ihn exportieren und durch git hash-object leiten, was einen neuen Blob mit diesem Inhalt in Git schreibt und Ihnen die SHA-1-Adresse des Blobs zurückgibt.
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
Nachdem Sie den Inhalt Ihres Schlüssels in Git haben, können Sie ein Tag erstellen, das direkt darauf verweist, indem Sie den neuen SHA-1-Wert angeben, den der Befehl hash-object Ihnen gegeben hat.
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
Wenn Sie git push --tags ausführen, wird das Tag maintainer-pgp-pub mit allen geteilt. Wenn jemand ein Tag überprüfen möchte, kann er Ihren PGP-Schlüssel direkt importieren, indem er den Blob direkt aus der Datenbank abruft und in GPG importiert.
$ git show maintainer-pgp-pub | gpg --import
Er kann diesen Schlüssel verwenden, um alle Ihre signierten Tags zu überprüfen. Wenn Sie auch Anweisungen in der Tag-Nachricht aufnehmen, können Sie mit git show <tag> dem Endbenutzer spezifischere Anweisungen zur Tag-Überprüfung geben.
Generieren einer Build-Nummer
Da Git keine monoton steigenden Nummern wie 'v123' oder das Äquivalent für jeden Commit hat, können Sie, wenn Sie einen lesbaren Namen für einen Commit haben möchten, git describe für diesen Commit ausführen. Als Antwort generiert Git eine Zeichenkette, die aus dem Namen des letzten Tags vor diesem Commit besteht, gefolgt von der Anzahl der Commits seit diesem Tag, gefolgt von einem partiellen SHA-1-Wert des beschriebenen Commits (vorangestellt mit dem Buchstaben "g", was für Git steht).
$ git describe master
v1.6.2-rc1-20-g8c5b85c
Auf diese Weise können Sie einen Snapshot oder Build exportieren und ihm einen für Menschen verständlichen Namen geben. Tatsächlich, wenn Sie Git aus dem Quellcode kompilieren, der aus dem Git-Repository geklont wurde, gibt git --version Ihnen etwas Ähnliches aus. Wenn Sie einen Commit beschreiben, den Sie direkt getaggt haben, gibt es einfach den Tag-Namen aus.
Standardmäßig erfordert der Befehl git describe annotierte Tags (Tags, die mit den Flags -a oder -s erstellt wurden); wenn Sie auch leichte (nicht annotierte) Tags nutzen möchten, fügen Sie der Option --tags den Befehl hinzu. Sie können diese Zeichenkette auch als Ziel eines git checkout- oder git show-Befehls verwenden, obwohl dies vom abgekürzten SHA-1-Wert am Ende abhängt, sodass sie nicht ewig gültig sein könnte. Zum Beispiel sprang der Linux-Kernel kürzlich von 8 auf 10 Zeichen, um die Einzigartigkeit des SHA-1-Objekts zu gewährleisten, sodass ältere git describe-Ausgabenamen ungültig wurden.
Vorbereiten einer Freigabe
Nun möchten Sie einen Build freigeben. Eines der Dinge, die Sie tun möchten, ist, ein Archiv des neuesten Snapshots Ihres Codes zu erstellen, für die armen Seelen, die Git nicht verwenden. Der Befehl dafür ist git archive.
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
Wenn jemand dieses Tarball öffnet, erhält er den neuesten Snapshot Ihres Projekts unter einem Verzeichnis namens project. Sie können auch auf ähnliche Weise ein Zip-Archiv erstellen, indem Sie die Option --format=zip an git archive übergeben.
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
Jetzt haben Sie ein schönes Tarball- und ein Zip-Archiv Ihrer Projekt-Release, die Sie auf Ihre Website hochladen oder per E-Mail versenden können.
Der Shortlog
Es ist Zeit, Ihre Mailingliste von Leuten zu informieren, die wissen wollen, was in Ihrem Projekt vor sich geht. Eine gute Möglichkeit, schnell eine Art Changelog darüber zu erhalten, was seit Ihrer letzten Freigabe oder E-Mail zu Ihrem Projekt hinzugefügt wurde, ist die Verwendung des Befehls git shortlog. Er fasst alle Commits im von Ihnen angegebenen Bereich zusammen; zum Beispiel gibt Ihnen der folgende Befehl eine Zusammenfassung aller Commits seit Ihrer letzten Freigabe, wenn Ihre letzte Freigabe v1.0.1 hieß:
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
Sie erhalten eine saubere Zusammenfassung aller Commits seit v1.0.1, gruppiert nach Autor, die Sie an Ihre Liste senden können.