-
1. Erste Schritte
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches auf einen Blick
- 3.2 Einfaches 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 Erstellung eines SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git-Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Von Drittanbietern gehostete Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git Tools
- 7.1 Revisions-Auswahl
- 7.2 Interaktives Stagen
- 7.3 Stashen und Bereinigen
- 7.4 Ihre Arbeit signieren
- 7.5 Suchen
- 7.6 Den Verlauf umschreiben
- 7.7 Reset entzaubert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debuggen mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Replace (Ersetzen)
- 7.14 Anmeldeinformationen speichern
- 7.15 Zusammenfassung
-
8. Git einrichten
- 8.1 Git Konfiguration
- 8.2 Git-Attribute
- 8.3 Git Hooks
- 8.4 Beispiel für Git-forcierte Regeln
- 8.5 Zusammenfassung
-
9. Git und andere Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git Interna
-
A1. Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Schnittstellen
- 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
-
A2. Anhang B: Git in Ihre Anwendungen einbetten
- A2.1 Die Git-Kommandozeile
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Anhang C: Git Kommandos
- A3.1 Setup und Konfiguration
- A3.2 Projekte importieren und erstellen
- A3.3 Einfache Snapshot-Funktionen
- A3.4 Branching und Merging
- A3.5 Projekte gemeinsam nutzen und aktualisieren
- A3.6 Kontrollieren und Vergleichen
- A3.7 Debugging
- A3.8 Patchen bzw. Fehlerkorrektur
- A3.9 E-mails
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Basisbefehle
7.9 Git Tools - Rerere
Rerere
Die Funktion git rerere
ist eine eher versteckte Komponente.
Der Name steht für „reuse recorded resolution“ (dt. „gespeicherte Ergebnisse wiederverwenden“). Der Name bedeutet, dass Sie Git auffordern können, sich zu erinnern, wie Sie einen bestimmten Konflikt gelöst haben. Wenn Git das nächste Mal den gleichen Konflikt sieht, kann es ihn automatisch für Sie lösen.
Es gibt eine Reihe von Szenarien, in denen diese Funktionalität wirklich nützlich sein kann.
Eines der Beispiele, das in der Dokumentation erwähnt wird, ist, sicher zu stellen, dass ein langlebiger Topic-Branch am Ende sauber gemergt wird; aber Sie wollen nicht, dass eine Menge zwischenzeitlicher Merge-Commits Ihre Commit-Historie durcheinander bringen.
Wenn rerere
aktiviert ist, können Sie ab und zu einen Merge starten, die Konflikte lösen und dann den Merge wieder abbrechen.
Falls Sie das kontinuierlich tun, dann sollte der endgültige Merge ganz unkompliziert sein, denn rerere
kann einfach alles für Sie automatisch erledigen.
Dieselbe Taktik kann angewendet werden, wenn Sie einen Branch reorganisiert (engl. rebase) halten wollen, damit Sie sich nicht jedes Mal mit denselben Konflikten beim Rebase auseinandersetzen müssen. Auch wenn Sie einen Branch, den Sie schon gemergt und eine Reihe von Konflikten behoben haben; ihn statt zu verwenden, sich für einen Rebase entscheiden – dann müssen Sie wahrscheinlich nicht alle Konflikte erneut lösen.
Eine weitere Einsatzmöglichkeit von `rerere` ist, wenn man eine Reihe von sich fortentwickelnden Topic-Branches gelegentlich zu einem überprüfbaren Head zusammenfügt, so wie es das Git-Projekt oft selbst praktiziert. Wenn diese Prüfungen fehlschlagen, können Sie die Merges rückgängig machen und sie ohne den fehlerhaften Topic-Branch, erneut starten, ohne die Konflikte erneut auflösen zu müssen.
Um die Funktion rerere
zu aktivieren, müssen Sie nur die folgende Config-Einstellung verwenden:
$ git config --global rerere.enabled true
Sie können sie auch einschalten, indem Sie das Verzeichnis .git/rr-cache
in einem konkreten Repository erstellen. Die Konfigurationseinstellung ist allerdings eindeutiger und aktiviert diese Funktion global für Sie.
Sehen wir uns nun ein einfaches Beispiel an, das unserem vorherigen ähnlich ist.
Nehmen wir an, wir haben eine Datei namens hello.rb
, die so aussieht:
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
In der einen Branch ändern wir das Wort „hello“ in „hola“, in der anderen Branch ändern wir die „world“ in „mundo“, wie gehabt.
![rerere1](png/rerere1.png)
Wenn wir die beiden Branches verschmelzen, bekommen 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 müssen dort die neue Zeile Recorded preimage for FILE
beachten.
Das Übrige sollte genau wie ein normaler Merge-Konflikt aussehen.
An dieser Stelle kann rerere
uns ein paar Dinge sagen.
Normalerweise könnten Sie an diesem Punkt git status
ausführen, um alle Konflikte zu sehen:
$ 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
#
Allerdings wird Ihnen git rerere
auch mitteilen, wozu es den Status vor dem Merge (engl. pre-merge state) mit git rerere status
aufgezeichnet hat:
$ git rerere status
hello.rb
Ein git rerere diff
zeigt den aktuellen Status der Lösung – womit Sie angefangen haben und welche Lösung Sie gefunden 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 nicht wirklich etwas mit rerere
zu tun) können Sie git ls-files -u
verwenden, um sich die in Konflikt stehenden Dateien und die vorherigen, verbliebenen und richtigen Versionen anzusehen:
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
Jetzt können Sie auflösen, indem Sie einfach puts 'hola mundo'
eingeben. Dann können Sie noch einmal git rerere diff
starten, um zu sehen, woran rerere sich erinnern 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 heißt im Grunde genommen: wenn Git in einer hello.rb
Datei, die „hello mundo“ auf der einen Seite und „hola world“ auf der anderen Seite enthält, einen komplizierten Konflikt erkennt, wird es ihn zu „hola mundo“ auflösen.
Jetzt können wir ihn 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 die „Lösung für DATEI gespeichert hat“ (Recorded resolution for FILE).
![rerere2](png/rerere2.png)
Machen wir jetzt diesen Merge rückgängig und legen ihn stattdessen dann auf unseren Branch master
.
Wir können unseren Branch zurückversetzen, indem wir git reset
anwenden, wie wir es in Reset entzaubert beschrieben haben.
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
Unser Merge ist aufgehoben. Lassen Sie uns jetzt den Topic-Branch rebasen.
$ 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
Nun haben wir den erwarteten Merge-Konflikt, aber schauen Sie sich die Zeile Resolved FILE using previous resolution
an.
Wenn wir die Datei betrachten, sehen wir, dass der Konflikt bereits gelöst ist, es gibt keine Marker für den Merge-Konflikt in der Datei.
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Zudem wird Ihnen git diff
zeigen, wie es automatisch erneut gelö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
![rerere3](png/rerere3.png)
Sie können den Status der Konfliktdatei 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 Fortgeschrittenes Merging kennengelernt.
Vorerst sollten wir das Problem allerdings dadurch lösen, dass wir git rerere
noch einmal starten:
$ 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 mit rerere
zwischengespeicherten Lösung erneut gelöst.
Sie können das nun hinzufügen und den Rebase fortsetzen, um ihn fertigzustellen.
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
Wenn Sie also viele Re-Merges machen oder einen Topic-Branch mit Ihrem Branch master
aktuell halten wollen, ohne dass eine Unmenge von Merges durchgeführt wird oder wenn Sie häufig einen Rebase machen, sollten Sie rerere
aktivieren, um sich das Leben ein wenig leichter zu machen.