-
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
3.2 Git Branching - Einfaches Branching und Merging
Einfaches Branching und Merging
Lassen Sie uns ein einfaches Beispiel für das Verzweigen und Zusammenführen (engl. branching and merging) anschauen, wie es Ihnen in einem praxisnahen Workflow begegnen könnte. Stellen sie sich vor, sie führen folgende Schritte aus:
-
Sie arbeiten an einer Website
-
Sie erstellen einen Branch für eine neue Anwendergeschichte (engl. User Story), an der Sie gerade arbeiten
-
Sie erledigen Sie einige Arbeiten in diesem Branch
In diesem Moment erhalten Sie einen Anruf, dass ein anderes Problem kritisch ist und Sie einen Hotfix benötigen. Dazu werden Sie folgendes tun:
-
Sie wechseln zu Ihrem Produktions-Branch
-
Sie erstellen einen Branch, um den Hotfix einzufügen
-
Nachdem der Test abgeschlossen ist, mergen Sie den Hotfix-Branch und schieben ihn in den Produktions-Branch
-
Sie wechseln zurück zu Ihrer ursprünglichen Anwenderstory und arbeiten daran weiter
Einfaches Branching
Lassen Sie uns zunächst annehmen, Sie arbeiten an Ihrem Projekt und haben bereits ein paar Commits in Ihren master
Branch gemacht.
Sie haben sich dafür entschieden, an „Issue #53“ aus irgendeinem Fehlerverfolgungssystem, das Ihre Firma benutzt, zu arbeiten.
Um einen neuen Branch anzulegen und gleichzeitig zu diesem zu wechseln, können Sie die Anweisung git checkout
zusammen mit der Option -b
ausführen:
$ git checkout -b iss53
Switched to a new branch "iss53"
Das ist die Kurzform der beiden folgenden Befehle:
$ git branch iss53
$ git checkout iss53
Sie arbeiten an Ihrer Website und führen einige Commits durch.
Sobald Sie das machen, bewegt das den iss53
Branch vorwärts, weil Sie in ihn gewechselt (engl. checked out) haben. Das bedeutet, Ihr HEAD
zeigt auf diesen Branch:
$ vim index.html
$ git commit -a -m 'Create new footer [issue 53]'
iss53
Branch hat sich bei Ihrer Arbeit vorwärts bewegtJetzt bekommen Sie einen Anruf, dass es ein Problem mit der Website gibt und Sie es umgehend beheben müssen.
Bei Git müssen Sie Ihren Fix nicht zusammen mit den Änderungen bereitstellen, die Sie bereits an iss53
vorgenommen haben. Sie müssen auch keinen großen Aufwand betreiben, diese Änderungen rückgängig zu machen, bevor Sie an den neuen Hotfix arbeiten können, um die Produktionsumgebung zu fixen.
Alles, was Sie machen müssen, ist, zu Ihrem vorherigen master
Branch zu wechseln.
Beachten Sie dabei, dass Git das Wechseln zu einem anderen Branch blockiert, falls Ihr Arbeitsverzeichnis oder Ihr Staging-Bereich nicht committete Modifikationen enthält, die Konflikte verursachen.
Generell ist es am besten, einen sauberen Zustand des Arbeitsbereichs anzustreben, bevor Sie Branches wechseln.
Es gibt Möglichkeiten, das zu umgehen (nämlich das Verstecken (engl. Stashen) und Revidieren (engl. Amending) von Änderungen), die wir später in Kapitel 7 Git Stashing behandeln werden.
Lassen Sie uns vorerst annehmen, Sie haben für alle Ihre Änderungen Commits durchgeführt, sodass Sie zu Ihrem vorherigen master
Branch wechseln können.
$ git checkout master
Switched to branch 'master'
Zu diesem Zeitpunkt befindet sich das Arbeitsverzeichnis des Projektes in exakt dem gleichen Zustand, in dem es sich befand, bevor Sie mit der Arbeit an „Issue #53“ begonnen haben und Sie können sich direkt auf den Hotfix konzentrieren. Das ist ein wichtiger Punkt, den Sie unbedingt beachten sollten: Wenn Sie die Branches wechseln, setzt Git Ihr Arbeitsverzeichnis zurück, um so auszusehen, wie es das letzte Mal war, als Sie in den Branch committed haben. Dateien werden automatisch hinzugefügt, entfernt und verändert, um sicherzustellen, dass Ihre Arbeitskopie auf demselben Stand ist wie zum Zeitpunkt Ihres letzten Commits auf diesem Branch.
Als Nächstes müssen Sie sich um den Hotfix kümmern.
Lassen Sie uns einen hotfix
Branch erstellen, an dem Sie bis zu dessen Fertigstellung arbeiten:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'Fix broken email address'
[hotfix 1fb7853] Fix broken email address
1 file changed, 2 insertions(+)
master
Branch basierender Hotfix-BranchSie können Ihre Tests durchführen, sich vergewissern, dass der Hotfix das macht, was Sie von ihm erwarten und schließlich den Branch hotfix
wieder in Ihren master
Branch integrieren (engl. merge), um ihn in der Produktion einzusetzen.
Das machen Sie mit der Anweisung git merge
:
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
Ihnen wird bei diesem Zusammenführen der Ausdruck „fast-forward“ auffallen.
Da der Commit C4
, auf den der von Ihnen eingebundene Branch hotfix
zeigt, direkt vor dem Commit C2
liegt, auf dem Sie sich befinden, bewegt Git den Pointer einfach nach vorne.
Um es anders auszudrücken: Wenn Sie versuchen, einen Commit mit einem Commit zusammenzuführen, der durch Verfolgen der Historie des ersten Commits erreicht werden kann, vereinfacht Git die Dinge, indem er den Zeiger nach vorne bewegt, da es keine abweichenden Arbeiten gibt, die miteinander gemergt werden müssen – das wird als „fast-forward“ bezeichnet.
Ihre Änderung befindet sich nun im Schnappschuss des Commits, auf den der master
Branch zeigt und Sie können Ihre Fehlerbehebung anwenden.
master
wurde zu hotfix
„fast-forwarded“Nachdem Ihre überaus wichtige Fehlerbehebung bereitgestellt wurde, können Sie sich wieder dem zuwenden, woran Sie gerade gearbeitet haben, als Sie unterbrochen wurden.
Zunächst sollten Sie jedoch den hotfix
Branch löschen, weil Sie diesen nicht länger benötigen – schließlich verweist der master
Branch auf denselben Entwicklungsstand.
Sie können ihn mit der Anweisung git branch
und der Option -d
löschen:
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
Jetzt können Sie zu dem vorherigen Branch wechseln, auf dem Sie mit Ihren Arbeiten an „Issue #53“ begonnen hatten, und daran weiter arbeiten.
$ git checkout iss53
Switched to branch "iss53"
$ vim index.html
$ git commit -a -m 'Finish the new footer [issue 53]'
[iss53 ad82d7a] Finish the new footer [issue 53]
1 file changed, 1 insertion(+)
iss53
fortsetzenErwähnenswert ist, dass die Änderungen, die Sie in Ihrem hotfix
Branch durchgeführt haben, nicht in den Dateien ihres iss53
Branch enthalten sind.
Wenn Sie diese Änderungen übernehmen wollen, können Sie Ihrem master
Branch in den iss53
Branch übernehmen, indem Sie git merge master
ausführen. Sie können aber auch warten und sich später dazu entscheiden, den iss53
Branch in master
zu übernehmen (engl. pullen).
Einfaches Merging
Angenommen, Sie haben entschieden, dass Ihr Issue #53 abgeschlossen ist und Sie bereit sind, ihn in Ihren Branch master
zu integrieren.
Dann werden Sie Ihren iss53
Branch in den master
Branch mergen, so wie Sie es zuvor mit dem hotfix
Branch gemacht haben.
Sie müssen nur mit der Anweisung checkout
zum dem Branch wechseln, in welchen Sie etwas einfließen lassen wollen und dann die Anweisung git merge
ausführen:
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
Das sieht ein bisschen anders aus, als das Merging mit dem hotfix
Branch, welches Sie zuvor gemacht haben.
Hier hat sich der Entwicklungsverlauf an einem früheren Zustand geteilt.
Da der Commit auf dem Branch, auf dem Sie sich gerade befinden, kein unmittelbarer Vorgänger des Branches ist, in den Sie mergen, muss Git einige Arbeiten erledigen.
In diesem Fall führt Git einen einfachen Drei-Wege-Merge durch, indem er die beiden Schnappschüsse verwendet, auf die die Branch-Spitzen und der gemeinsame Vorgänger der beiden zeigen.
merge
benutzt werdenAnstatt einfach den Zeiger des Branches vorwärts zu bewegen, erstellt Git einen neuen Schnappschuss, der aus dem Drei-Wege-Merge resultiert und erzeugt automatisch einen neuen Commit, der darauf zeigt. Das wird auch als Merge-Commit bezeichnet und ist ein Spezialfall, weil er mehr als nur einen Vorgänger hat.
Da Ihre Änderungen jetzt eingeflossen sind, haben Sie keinen weiteren Bedarf mehr für den iss53
Branch.
Sie können den Issue in Ihrem Issue-Tracking-System schließen und den Branch löschen:
$ git branch -d iss53
Einfache Merge-Konflikte
Gelegentlich verläuft der Merge-Prozess nicht ganz reibungslos.
Wenn Sie in den beiden Branches, die Sie zusammenführen wollen, an derselben Stelle in derselben Datei unterschiedliche Änderungen vorgenommen haben, wird Git nicht in der Lage sein, diese sauber zusammenzuführen.
Wenn Ihr Fix für „Issue #53“ den gleichen Teil einer Datei wie der Branch hotfix
geändert hat, erhalten Sie einen Merge-Konflikt, der ungefähr so aussieht:
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git konnte einen neuen Merge-Commit nicht automatisch erstellen.
Es hat den Prozess angehalten, bis Sie den Konflikt beseitigt haben.
Wenn Sie sehen möchten, welche Dateien zu irgendeinem Zeitpunkt nach einem Merge-Konflikt nicht zusammengeführt wurden, können Sie git status
ausführen:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
Alles, was Merge-Konflikte ausgelöst hat und nicht behoben wurde, wird als unmerged
angezeigt.
Git fügt den Dateien, die Konflikte haben, Standardmarkierungen zur Konfliktlösung hinzu, so dass Sie sie manuell öffnen und diese Konflikte lösen können.
Ihre Datei enthält einen Bereich, der in etwa so aussieht:
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
Das bedeutet, die Version in HEAD
(das ist der aktuelle commit master
Branches, denn der wurde per checkout
aktiviert, als Sie den Merge
gestartet haben) ist der obere Teil des Blocks (alles oberhalb von =======
) und die Version aus dem iss53
Branch ist in dem darunter befindliche Teil.
Um den Konflikt zu lösen, müssen Sie sich entweder für einen der beiden Teile entscheiden oder Sie führen die Inhalte selbst zusammen.
Sie können diesen Konflikt beispielsweise lösen, indem Sie den gesamten Block durch diesen ersetzen:
<div id="footer">
please contact us at email.support@github.com
</div>
Diese Lösung hat von beiden Teilen etwas und die Zeilen mit <<<<<<<
, =======
und >>>>>>>
wurden vollständig entfernt.
Nachdem Sie alle problematischen Bereiche in allen von dem Konflikt betroffenen Dateien beseitigt haben, führen Sie einfach die Anweisung git add
für alle betroffenen Dateien aus, um sie als gelöst zu markieren.
Dieses ‚Staging‘ der Dateien markiert sie für Git als bereinigt.
Wenn Sie ein grafisches Tool benutzen möchten, um die Probleme zu lösen, dann können Sie git mergetool
verwenden, welches ein passendes grafisches Merge-Tool startet und Sie durch die Konfliktbereiche führt:
$ git mergetool
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge
Merging:
index.html
Normal merge conflict for 'index.html':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (opendiff):
Wenn Sie ein anderes Merge-Tool anstelle des Standardwerkzeugs verwenden möchten (Git wählte in diesem Fall opendiff
, da die Anweisung auf einem Mac ausgeführt wurde), dann können Sie alle unterstützten Werkzeuge sehen, die oben nach „one of the following tools“ aufgelistet sind.
Tippen Sie einfach den Namen des gewünschten Programms ein.
Anmerkung
|
Wenn Sie fortgeschrittenere Werkzeuge zur Lösung kniffliger Merge-Konflikte benötigen, erfahren Sie mehr darüber in Kapitel 7 Fortgeschrittenes Merging. |
Nachdem Sie das Merge-Tool beendet haben, werden Sie von Git gefragt, ob das Zusammenführen erfolgreich war.
Wenn Sie dem Skript bestätigen, dass es das war, wird die Datei der Staging-Area hinzugefügt und der Konflikt als gelöst markiert.
Sie können den Befehl git status
erneut ausführen, um zu überprüfen, ob alle Konflikte gelöst wurden:
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: index.html
Wenn Sie damit zufrieden sind und Sie geprüft haben, dass alles, was Konflikte aufwies, der Staging-Area hinzugefügt wurde, können Sie die Anweisung git commit
ausführen, um den Merge-Commit abzuschließen.
Die standardmäßige Commit-Nachricht sieht ungefähr so aus:
Merge branch 'iss53'
Conflicts:
index.html
#
# It looks like you may be committing a merge.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# All conflicts fixed but you are still merging.
#
# Changes to be committed:
# modified: index.html
#
Sie können dieser Commit-Nachricht noch Details darüber hinzufügen, wie Sie diesen Merge-Konflikt gelöst haben. Es könnte für künftige Betrachter dieses Commits hilfreich sein, zu verstehen, warum Sie was getan haben, falls es nicht offensichtlich ist.