-
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
7.9 Git-Tools - Rerere
Rerere
Die git rerere Funktionalität ist ein wenig versteckt. Der Name steht für „reuse recorded resolution“ (wiederverwendete aufgezeichnete Auflösung) und, wie der Name schon sagt, erlaubt sie Ihnen, Git anzuweisen, sich zu merken, wie Sie einen Hunk-Konflikt gelöst haben, damit Git ihn beim nächsten Mal, wenn derselbe Konflikt auftritt, automatisch für Sie lösen kann.
Es gibt eine Reihe von Szenarien, in denen diese Funktionalität sehr nützlich sein kann. Eines der Beispiele, das in der Dokumentation erwähnt wird, ist, wenn Sie sicherstellen möchten, dass ein langlebiger Topic-Branch letztendlich sauber zusammengeführt werden kann, Sie aber nicht möchten, dass viele Zwischen-Merge-Commits Ihre Commit-Historie unübersichtlich machen. Mit aktiviertem rerere können Sie gelegentliche Merges versuchen, die Konflikte lösen und sich dann vom Merge zurückziehen. Wenn Sie dies kontinuierlich tun, sollte der finale Merge einfach sein, da rerere alles automatisch für Sie erledigen kann.
Diese gleiche Taktik kann angewendet werden, wenn Sie einen Branch rebased halten möchten, damit Sie sich nicht jedes Mal mit denselben Rebase-Konflikten auseinandersetzen müssen. Oder wenn Sie einen Branch, den Sie zusammengeführt und bei dem Sie eine Reihe von Konflikten behoben haben, dann doch lieber rebasen möchten – wahrscheinlich müssen Sie nicht alle dieselben Konflikte erneut lösen.
Eine weitere Anwendung von rerere ist, wenn Sie eine Reihe von sich entwickelnden Topic-Branches gelegentlich zu einem testbaren Head zusammenführen, so wie es das Git-Projekt selbst oft tut. Wenn die Tests fehlschlagen, können Sie die Merges zurückrollen und sie neu durchführen, ohne den Topic-Branch, der die Tests fehlschlagen ließ, und ohne die Konflikte erneut lösen zu müssen.
Um die rerere Funktionalität zu aktivieren, müssen Sie lediglich diesen Konfigurationsbefehl ausführen
$ git config --global rerere.enabled true
Sie können es auch aktivieren, indem Sie das Verzeichnis .git/rr-cache in einem bestimmten Repository erstellen, aber die Konfigurationseinstellung ist klarer und aktiviert diese Funktion global für Sie.
Sehen wir uns nun ein einfaches Beispiel an, ähnlich dem vorherigen. Nehmen wir an, wir haben eine Datei namens hello.rb, die so aussieht
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
In einem Branch ändern wir das Wort „hello“ in „hola“, dann in einem anderen Branch ändern wir „world“ in „mundo“, genau wie zuvor.
Wenn wir die beiden Branches zusammenführen, erhalten wir einen Merge-Konflikt
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
Sie sollten die neue Zeile Recorded preimage for FILE darin bemerken. Ansonsten sollte es genau wie ein normaler Merge-Konflikt aussehen. An diesem Punkt kann uns rerere einige Dinge sagen. Normalerweise würden Sie an diesem Punkt git status ausführen, um zu sehen, was alles kollidierte.
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
git rerere wird Ihnen jedoch auch mitteilen, wofür es den Pre-Merge-Zustand aufgezeichnet hat, mit git rerere status.
$ git rerere status
hello.rb
Und git rerere diff zeigt den aktuellen Zustand der Auflösung an – womit Sie begonnen haben zu lösen und wozu Sie es gelöst haben.
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
Außerdem (und das hat nichts wirklich mit rerere zu tun) können Sie git ls-files -u verwenden, um die konfliktrelevanten Dateien und die Versionen davor, links und rechts anzuzeigen.
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
Jetzt können Sie es zu nur puts 'hola mundo' auflösen und erneut git rerere diff ausführen, um zu sehen, was rerere sich merken wird.
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
Das besagt im Grunde, dass Git, wenn es einen Hunk-Konflikt in einer hello.rb-Datei sieht, die auf der einen Seite „hello mundo“ und auf der anderen „hola world“ hat, ihn zu „hola mundo“ auflöst.
Jetzt können wir es als gelöst markieren und committen.
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
Sie können sehen, dass es "Recorded resolution for FILE" aufgezeichnet hat.
Nun machen wir diesen Merge rückgängig und rebasen ihn stattdessen auf unseren master-Branch. Wir können unseren Branch mit git reset zurücksetzen, wie wir in Reset Demystified gesehen haben.
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
Unser Merge ist rückgängig gemacht. Nun rebasen wir den Topic-Branch.
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
Jetzt haben wir denselben Merge-Konflikt wie erwartet, aber schauen Sie sich die Zeile Resolved FILE using previous resolution an. Wenn wir uns die Datei ansehen, werden wir sehen, dass sie bereits aufgelöst wurde, es gibt keine Merge-Konfliktmarker darin.
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Außerdem zeigt Ihnen git diff, wie es automatisch wieder aufgelöst wurde.
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end
Sie können den konfliktrelevanten Dateizustand auch mit git checkout wiederherstellen.
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
Ein Beispiel dafür haben wir in Advanced Merging gesehen. Vorerst lösen wir es jedoch erneut auf, indem wir einfach git rerere erneut ausführen.
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Wir haben die Datei automatisch mit der zwischengespeicherten rerere-Auflösung wieder aufgelöst. Sie können jetzt hinzufügen und mit dem Rebase fortfahren, um ihn abzuschließen.
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
Wenn Sie also viele Re-Merges durchführen, einen Topic-Branch ohne viele Merges mit Ihrem master-Branch aktuell halten möchten oder oft rebasen, können Sie rerere aktivieren, um Ihr Leben ein wenig zu erleichtern.