-
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.1 Git Branching - Branches auf einen Blick
Nahezu jedes VCS unterstützt eine Form von Branching. Branching bedeutet, dass Sie von der Hauptlinie der Entwicklung abzweigen und Ihre Arbeit fortsetzen, ohne die Hauptlinie durcheinanderzubringen. In vielen VCS-Tools ist das ein etwas aufwändiger Prozess, bei dem Sie oft eine neue Kopie Ihres Quellcode-Verzeichnisses erstellen müssen, was bei großen Projekten viel Zeit in Anspruch nehmen kann.
Manche Leute bezeichnen Gits Branching-Modell als dessen „Killer-Feature“, was Git zweifellos vom Rest der VCS-Community abhebt. Was ist das Besondere daran? Die Art und Weise, wie Git Branches anlegt ist unglaublich leichtgewichtig. Branch-Operationen werden nahezu verzögerungsfrei ausgeführt und auch das Hin- und Herschalten zwischen einzelnen Entwicklungszweigen läuft meist genauso schnell ab. Im Gegensatz zu anderen VCS ermutigt Git zu einer Arbeitsweise mit häufigem Branching und Merging, sogar mehrmals am Tag. Wenn Sie diese Funktion verstehen und beherrschen, besitzen Sie ein mächtiges und besonderes Werkzeug, welches Ihre Art zu entwickeln vollständig verändern kann.
Branches auf einen Blick
Um richtig zu verstehen, wie Git das Verzweigen (engl. Branching) realisiert, müssen wir einen Schritt zurück gehen und untersuchen, wie Git seine Daten speichert.
Wie Sie vielleicht aus Kapitel 1 Was ist Git? in Erinnerung haben, speichert Git seine Daten nicht als Serie von Änderungen oder Unterschieden, sondern statt dessen als eine Reihe von Snapshots.
Wenn Sie einen Commit durchführen, speichert Git ein Commit-Objekt, das einen Zeiger auf den Snapshot des von Ihnen bereitgestellten Inhalts enthält. Dieses Objekt enthält auch den Namen und die E-Mail-Adresse des Autors, die Nachricht, die Sie eingegeben haben, und zeigt auf den Commit oder die Commits, die direkt vor diesem Commit stattfanden (zu seinem Vorgänger bzw. seinen Vorgängern): keine Vorgänger für den ersten Commit, einen Vorgänger für einen normalen Commit und mehrere Vorgänger für einen Commit, welcher aus dem Zusammenführen (engl. mergen) von zwei oder mehr Branches resultiert.
Um das zu veranschaulichen, lassen Sie uns annehmen, Sie haben ein Verzeichnis, welches drei Dateien enthält, und Sie fügen alle Dateien zur Staging-Area hinzu und führen einen Commit durch. Durch das Hinzufügen der Dateien zur Staging-Area erzeugt Git für jede Datei eine Prüfsumme (den SHA-1-Hashwert, den wir in Kapitel 1 Was ist Git? erwähnt haben), speichert diese Version der Datei im Git-Repository (Git verweist auf diese als blobs) und fügt die Prüfsumme der Staging-Area hinzu:
$ git add README test.rb LICENSE
$ git commit -m 'Initial commit'
Wenn Sie mit der Anweisung git commit
einen Commit erzeugen, berechnet Git für jedes Unterverzeichnis (in diesem Fall nur das Wurzelverzeichnis des Projektes) eine Prüfsumme und speichert diese als tree-Objekt im Git-Repository.
Git erzeugt dann ein commit-Objekt, welches die Metadaten und einen Zeiger zum tree-Objekt des Wurzelverzeichnisses enthält, sodass es bei Bedarf den Snapshot erneut erzeugen kann.
Ihr Git-Repository enthält jetzt fünf Objekte: drei blobs (die jeweils den Inhalt einer der drei Dateien repräsentieren), ein tree-Objekt, welches den Inhalt des Verzeichnisses auflistet und angibt, welcher Dateiname zu welchem Blob gehört, und ein commit-Objekt mit dem Zeiger, der auf die Wurzel des Projektbaumes und die Metadaten des Commits verweist.
![Ein Commit und sein Tree](png/commit-and-tree.png)
Wenn Sie einige Änderungen vornehmen und wieder einen Commit durchführen, speichert dieser einen Zeiger zu dem Commit, der unmittelbar davor gemacht wurde.
![Commits und ihre Vorgänger](png/commits-and-parents.png)
Ein Branch in Git ist einfach ein leichter, beweglicher Zeiger auf einen dieser Commits.
Die Standardbezeichnung für einen Branch bei Git lautet master
.
Wenn Sie damit beginnen, Commits durchzuführen, erhalten Sie einen master
Branch, der auf den letzten Commit zeigt, den Sie gemacht haben.
Jedes Mal, wenn Sie einen Commit durchführen, bewegt er sich automatisch vorwärts.
Anmerkung
|
Der „master“-Branch in Git ist kein spezieller Branch.
Er ist genau wie jeder andere Branch.
Der einzige Grund dafür, dass nahezu jedes Repository einen „master“-Branch hat, ist der Umstand, dass die Anweisung |
![Ein Branch und sein Commit-Verlauf](png/branch-and-history.png)
Erzeugen eines neuen Branches
Was passiert, wenn Sie einen neuen Branch anlegen?
Nun, wenn Sie das tun, wird ein neuer Zeiger (Pointer) erstellt, mit dem Sie sich in der Entwicklung fortbewegen können.
Nehmen wir an, Sie erzeugen einen neuen Branch mit dem Namen „testing“.
Das machen Sie mit der Anweisung git branch
:
$ git branch testing
Dieser Befehl erzeugt einen neuen Zeiger, der auf denselben Commit zeigt, auf dem Sie sich gegenwärtig befinden.
![Zwei Branches](png/two-branches.png)
Woher weiß Git, auf welchem Branch Sie gegenwärtig sind?
Es besitzt einen speziellen Zeiger namens HEAD
.
Beachten Sie, dass dieser HEAD
sich sehr stark unterscheidet von den HEAD
Konzepten anderer Versionsverwaltungen, mit denen Sie vielleicht vertraut sind, wie Subversion oder CVS.
Bei Git handelt es sich bei HEAD
um einen Zeiger auf den lokalen Branch, auf dem Sie sich gegenwärtig befinden.
In diesem Fall sind Sie noch auf dem master
Branch.
Die Anweisung git branch
hat den neuen Branch nur erzeugt, aber nicht zu diesem gewechselt.
![Auf einen Branch zeigender HEAD](png/head-to-master.png)
Sie können das leicht nachvollziehen, indem Sie den einfachen Befehl git log
ausführen, mit dem Sie sehen, wohin die Zeiger der Branches zeigen.
Diese Option wird --decorate
genannt.
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface
34ac2 Fix bug #1328 - stack overflow under certain conditions
98ca9 Initial commit
Sie können die Branches master
und testing
sehen, die sich rechts neben dem Commit von f30ab
befinden.
Wechseln des Branches
Um zu einem existierenden Branch zu wechseln, führen Sie die Anweisung git checkout
aus.
Lassen Sie uns zu dem neuen testing
Branch wechseln.
$ git checkout testing
Dadurch wird HEAD
verschoben, um auf den Branch testing
zu zeigen.
![HEAD zeigt auf den aktuellen Branch](png/head-to-testing.png)
Was bedeutet das? Nun, lassen Sie uns einen weiteren Commit durchführen.
$ vim test.rb
$ git commit -a -m 'made a change'
![Der Branch](png/advance-testing.png)
Das ist interessant, weil sich jetzt Ihr testing
Branch vorwärts bewegt hat, aber Ihr master
Branch noch auf den Commit zeigt, auf dem Sie sich befanden, als Sie die Anweisung git checkout
ausführten, um die Branches zu wechseln.
Lassen Sie uns zum Branch master
zurückwechseln.
$ git checkout master
Anmerkung
|
git log zeigt nicht immer alle BranchesWenn Sie jetzt Der Branch ist nicht spurlos verschwunden. Git weiß nur nicht, dass Sie sich für diesen Branch interessieren, und es versucht, Ihnen das zu zeigen, woran Sie seiner Meinung nach interessiert sind.
Anders gesagt, standardmäßig zeigt Um die Commit-Historie für den gewünschten Branch anzuzeigen, müssen Sie ihn explizit angeben: |
![HEAD bewegt sich](png/checkout-master.png)
Diese Anweisung hat zwei Dinge bewirkt.
Es bewegte den HEAD-Zeiger zurück, um auf den master
Branch zu zeigen und es setzte die Dateien in Ihrem Arbeitsverzeichnis auf den Snapshot zurück, auf den master
zeigt.
Das bedeutet auch, dass die Änderungen, die Sie von diesem Punkt aus vornehmen, von einer älteren Version des Projekts abzweigen werden.
Sie macht im Grunde genommen die Änderungen rückgängig, die Sie auf Ihrem testing
Branch vorgenommen haben, sodass Sie in eine andere Richtung gehen können.
Anmerkung
|
Das Wechseln der Branches ändert Dateien in Ihrem Arbeitsverzeichnis
Es ist wichtig zu beachten, dass sich die Dateien in Ihrem Arbeitsverzeichnis verändern, wenn Sie in Git die Branches wechseln. Wenn Sie zu einem älteren Branch wechseln, wird Ihr Arbeitsverzeichnis zurückverwandelt, sodass es aussieht wie zu dem Zeitpunkt, als Sie Ihren letzten Commit auf diesem Branch durchgeführt haben. Wenn Git das nicht problemlos durchführen kann, lässt es Sie die Branches überhaupt nicht wechseln. |
Lassen Sie uns ein paar Änderungen vornehmen und noch einen Commit durchführen:
$ vim test.rb
$ git commit -a -m 'made other changes'
Jetzt hat sich Ihr Projektverlauf verzweigt (siehe Verzweigter Verlauf).
Sie haben einen Branch erstellt und sind zu ihm gewechselt, haben einige Arbeiten daran durchgeführt und sind dann wieder zu Ihrem Hauptzweig zurückgekehrt, um andere Arbeiten durchzuführen.
Beide Änderungen sind in separaten Branches isoliert: Sie können zwischen den Branches hin und her wechseln sowie sie zusammenführen, wenn Sie bereit sind.
Und das alles mit den einfachen Befehlen branch
, checkout
und commit
.
![Verzweigter Verlauf](png/advance-master.png)
Sie können sich dies ansehen, wenn Sie die Anweisung git log
ausführen.
Wenn Sie die Anweisung git log --oneline --decorate --graph --all
ausführen, wird Ihnen der Verlauf Ihrer Commits so angezeigt, dass erkennbar ist, wo Ihre Branch-Zeiger sich befinden und wie Ihr Verlauf sich verzweigt hat.
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) Made other changes
| * 87ab2 (testing) Made a change
|/
* f30ab Add feature #32 - ability to add new formats to the central interface
* 34ac2 Fix bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project
Da ein Branch in Git in Wirklichkeit eine einfache Datei ist, welche die 40-Zeichen lange SHA-1-Prüfsumme des Commits enthält, zu dem sie zeigt, können Branches ohne großen Aufwand erzeugt und vernichtet werden. Einen neuen Branch anzulegen, geht so schnell und ist so einfach, wie 41 Bytes in eine Datei zu schreiben (40 Zeichen und einen Zeilenumbruch).
Das steht im krassen Gegensatz zur Art und Weise, wie die meisten älteren Werkzeuge zur Versionsverwaltung Branches anlegen, bei der alle Projektdateien in ein zweites Verzeichnis kopiert werden. Das kann, in Abhängigkeit von der Projektgröße, mehrere Sekunden oder sogar Minuten dauern, während bei Git dieser Prozess augenblicklich erledigt ist. Da wir außerdem immer die Vorgänger mit aufzeichnen, wenn wir einen Commit durchführen, wird die Suche nach einer geeigneten Basis für das Zusammenführen (engl. merging) für uns automatisch durchgeführt, was in der Regel sehr einfach erledigt werden kann. Diese Funktionen tragen dazu bei, dass Entwickler ermutigt werden, häufig Branches zu erstellen und zu nutzen.
Lassen Sie uns herausfinden, warum Sie so handeln sollten.
Anmerkung
|
Einen neuen Branch erzeugen und gleichzeitig dorthin wechseln.
Es ist üblich, einen neuen Branch zu erstellen und gleichzeitig zu diesem neuen Branch zu wechseln – dies kann in einem Arbeitsschritt mit |
Anmerkung
|
Ab Git version 2.23 können sie
|