In diesem kurzen Tutorial zeige ich, wie man Git einrichtet und wie die alltäglichen Nutzungs-Szenarien funktionieren.
Git ist ein Arbeitsmittel für Programmierer, um
Unter Linux installiert man Git üblicherweise mit dem Paketmanager der jeweiligen Linux Distribution. Ansonsten findest du die offiziellen Downloads auf der Seite Git Downloads.
Richte die Umgebungsvariable PATH ein, so dass der "git" Befehl im Terminalfenster (Eingabeaufforderung) gefunden wird. Konfiguriere deinen Namen und Email Adresse mit dem Befehl:
git config --global user.name "John Doe" git config --global user.email johndoe@example.com
Zuerst erkläre ich, wie man Git ganz alleine benutzt, um Änderungen zu protokollieren. Alle weiteren Funktionen bauen nämlich darauf auf.
Fangen wir mit einem Projektverzeichnis "MeinProjekt" an, in dem sich nur eine Datei "brief.txt" befindet:
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass ... ja was denn?
Bevor man Git in diesem Projekt verwenden kann, muss man es initialisieren. Führe dazu den Befehl "git init" im Projektverzeichnis aus:
cd MeinProjekt git init
Dabei wird ein versteckter Ordner mit dem Namen ".git" angelegt, in dem Git später die Schnappschüsse von den Quelltexten abspeichert:
Der Inhalt dieses Ordners ist uninteressant und sollte niemals manuell verändert werden!
Die Funktion von Git beruht darauf, Schnappschüsse von deinem Projektverzeichnis zu erstellen. Später kannst du Schnappschüsse miteinander vergleichen und unerwünschte Änderungen rückgängig machen.
Erstelle deinen ersten Schnappschuss, indem du folgende Befehle im Projektverzeichnis eingibst:
git add brief.txt git commit -m "Projekt begonnen"
Mit dem Befehl git add legst du fest, welche Datei(en) in den nächsten Schnappschuss aufgenommen werden sollen. Der Befehl git commit erstellt den Schnappschuss, mit einem kurzen Beschreibungstext.
Wenn du den Parameter -m weglässt, öffnet sich ein Text-Editor wo du den Kommentar eingeben sollst.
Schreibe den Brief zuende:
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns in der Zeit per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihr Schreibwaren Spezialist
Und erstelle ein weiteres Dokument mit dem Dateinamen "pakete.txt":
Lieber Paketbote, bitte geben Sie Pakete für den Schreibwaren-Laden nebenan im Kiosk ab. Danke
Mit dem Befehl git status schauen wir uns den Zustand des Projektes an:
git status
Wir erstellen einen zweiten Schnappschuss.
git add brief.txt pakete.txt git commit -m "Brief ergänzt und Schild für Pakete erstellt"
Kontrolliere das Ergebnis mit
gitk
Gitk zeigt uns die Historie des Projektes grafisch an:
Wir erstellen noch einen dritten Schnappschuss, wo wir den Brief verbessern:
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihr Schreibwaren Spezialist
Da dieses mal keine neue Datei dazu gekommen ist, können wir auf den git add Befehl verzichten. Wir müssen dann aber beim commit den Parameter -a angeben, welcher alle geänderten (nicht neue) Dateien erfasst.
git commit -a -m "A121 Brief verbessert" gitk
Mache dich mit gitk vertraut. Schau Dir an, wie es die Historie deiner Änderungen anzeigt. Jeder Schnappschuss hat eine eindeutige SHA1 ID. Darunter werden die Änderungen gegenüber dem vorherigen Schnappschuss angezeigt.
Der Beschreibungstext sollte möglichst die zugrunde liegende Auftrags- oder Ticket-Nummer enthalten (hier die A121), damit man später nachvollziehen kann, warum etwas geändert wurde und welche Anforderungen zugrunde lagen.
Wir haben jetzt drei Schnappschüsse, deren Inhalt wir mit gitk anzeigen können. Wenn du nur die Änderungen von einer einzelnen Datei sehen willst, kannst du den Dateinamen als Parameter angeben, zum Beispiel:
gitk brief.txt
Im rechten Bereich von gitk kannst du mit der rechten Maustaste auf einen Dateinamen klicken und dann auf "Externes Diff Programm". Die folgende Ansicht variiert je nach Betriebssystem und welches Diff-Programm installiert wurde:
Alternativ zur grafischen Oberfläche kannst du Unterschiede zwischen zwei Schnappschüssen mit dem Befehl git diff anzeigen:
git diff b083b22940a82a4acd58c90c99601de5a3ca11ba c55bd76de32c5fc5cbc88b648aedad087f4dfd01
Man darf die SHA1 IDs abkürzen, solange sie eindeutig sind:
git diff b083 c55b
Probieren wir einen Wechsel zum ersten Schnappschuss:
git checkout b239
Dabei werden alle Arbeitsdateien im Projekt auf die angegebene Version gebracht. Die Datei pakete.txt ist nun verschwunden und du siehst wieder den alten Entwurf vom Brief.
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass ... ja was denn?
Wenn du jetzt gitk startest, siehst du nicht mehr alle Schnappschüsse, denn Gitk zeigt standardmäßig nämlich nur die Historie bis zum aktuellen Schnappschuss an. Benutze den Parameter --all um alle Schnappschüsse zu sehen:
gitk --all
Der gelbe Punkt kennzeichnet, auf welchem Schnappschuss du dich gerade befindest.
Um zum neuesten Stand zurück zu wechseln, kannst du anstelle der ID auch den grün hinterlegten Namen des Zweiges angeben. Der erste Zweig heisst immer "master" und wird automatisch angelegt. Also:
git checkout master gitk --all
Nun hast du wieder den neuesten Brief im Projektverzeichnis, und auch die pakete.txt ist wieder da.
Wenn ein Projekt abgeliefert wird, bekommt es eine besondere Markierung - ein Tag. Diese werden in gitk deutlich hervorgehoben, so dass man sie schneller wieder findet.
Bevor du Markierungen hinzufügst, wechsle immer zum neuesten Schnappschuss des jeweiligen Zweiges, ansonsten werden die Markierungen später nicht korrekt angezeigt!
Lass uns die aktuelle Version als "1.0.0" kennzeichnen:
git checkout master git tag "1.0.0"
Wir wollen außerdem die allererste Version als "0.9.0" kennzeichnen. Diese können wir anhand ihrer ID bestimmen:
git tag "0.9.0" b239 gitk --all
Wir haben jetzt zwei der drei Schnappschüsse mit einer Versionsmarkierung versehen. Man kann Markierungen nachträglich verschieben. Um dies zu probieren, ändern wir den Brief:
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihre Erika Zinker
Nun erstellen wir davon einen neuen Schnappschuss und versetzen die Markierung hierhin:
git commit -a -m "A122 Name der Cheffin eingetragen" git tag -f "1.0.0" gitk --all
Der Paramter -f (force) erlaubt uns, die bestehende Markierung durch eine neue zu ersetzen.
Anmerkung:
Für Git ist die Schreibweise der Tags ziemlich egal, aber manche andere Programme verlangen ein
bestimmtes Muster. Bei der Programmiersprache go muss die erste Version z.B. "v1.0.0" heissen
(siehe Module version numbering).
Um dies auszuprobieren, führen wir zwei fiktive Änderungsaufträge ein:
Wir starten einen Zweig für den ersten Änderungsauftrag:
git checkout -b A140
Nun nehmen wir die angeforderte Änderung am Brief vor:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihre Erika Zinker
Davon machen wir einen Schnappschuss:
git commit -a -m "A140 Eine weniger förmliche Anrede"
Nun fällt uns auf, dass zwischen der Begrüßung und dem Text etwas mehr Abstand sein sollte. Also korrigieren wir das und erstellen einen weiteren Schnappschuss:
Liebe Kunden, <--- Leerzeile wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihre Erika Zinker
git commit -a -m "A140 Angeben, wann wir wieder da sind" gitk --all
Wir sehen hier in grün, dass nach der Version 1.0.0 ein Zweig mit dem Namen "A140" angelegt wurde. Dieser Zweig enthält zwei Schnappschüsse.
Nun schlüpfen wir in die Rolle eines Kollegen, der den zweiten Änderungsauftrag A141 bearbeiten soll. Dieser beginnt ebenfalls mit dem Master Zweig für seine Arbeit, deswegen wechseln wir zuerst dorthin bevor wir den neuen Zweig erstellen:
git checkout master git checkout -b A141
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind am 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Erika Zinker
Davon erstellen wir einen Schnappschuss.
git commit -a -m "A141 Angeben, wann wir wieder da sind"
Nun ändern wir noch eine Kleinigkeit:
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Erika Zinker
Davon erstellen wir wieder einen Schnappschuss.
git commit -a -m "A141 Angeben, wann wir wieder da sind (ab dem)" gitk --all
Du siehst hier, dass die Entwicklung nach der Version 1.0.0 in zwei unabhängige Zweige mit den Namen A140 und A141 aufgeteilt wurde. Diese Zweige haben jeweils zwei Änderungen vorgenommen.
Wenn ein Projekt mehrere Zweige hat, kann Git Änderungen von einem Zweig in den anderen Zweig übertragen. Hierzu bietet Git zwei Möglichkeiten:
Ausgehend von den vorherigen Versuchen wollen wir nun alle Änderungen der Zweige A140 und A141 in den Haupt-Zweig (master) übertragen. Zuerst muss man zu dem Zweig wechseln, wo die Änderungen hin gehen sollen:
git checkout master
Dann übertragen wir die Änderungen vom Zweig A140 in den aktuellen (master) Zweig:
git merge A140
Außerdem übertragen wir auch die Änderungen vom Zweig A141 in den aktuellen (master) Zweig:
git merge A141 gitk --all
Die Änderungen der beiden Zweige wurden zusammen geführt uns stellen nun den aktuellen Hauptzweig (master) dar. Kontrolliere die Datei brief.txt:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Erika Zinker
Sie enthält nun die Änderungen von beiden Aufträgen: Die Anrede von A140 und das Datum von A141.
Wir können diesen Stand nun als Version 1.1.0 markieren:
git tag "1.1.0" gitk --all
Die beiden Zweige für A140 und A141 sind sehr klein. In echten Projekten dauert die Entwicklung von neuen Funktionen oft mehrere Tage bis Wochen, so dass viel mehr Schnappschüsse erstellt werden. Dort macht das Abzweigen mehr Sinn, als in diesem kurzen Beispiel.
Cherry Pick überträgt nicht ganze Zweige, sondern nur einzelne Commits (das was Gitk unter einem Punkt in der grafischen Darstellung zeigt).
Angenommen wir sollen zum Brief in Version 1.0.0 noch eine Zeile hinzufügen und nur diese eine Änderung auch nach Version 1.1.0 übertragen, dann ist die Vorgehensweise folgendermaßen:
Ändere zuerst die Datei brief.txt in der Version 1.0.0:
git checkout 1.0.0
Sehr geehrte Damen und Herren, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. mit freundlichem Gruß ihre Erika Zinker Filialleiterin
git commit -a -m "Filialleiterin hinzugefügt" git tag "1.0.1" gitk --all
Nun wechseln wir zum master Zweig, cherry-picken die vorherige Änderung dorthin, und markieren das dann als Version 1.1.1:
git checkout master git cherry-pick 69e0 git tag "1.1.1" gitk --allAll diese Schritte sind anschließend in gitk sichtbar:
Kontrolliere das Ergebnis in der Datei brief.txt:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Erika Zinker Filialleiterin
Wenn man Änderungen mit merge oder cherry-pick zusammen führt kann es passieren, dass eine Zeile Text in den beiden betroffenen Zweigen widersprüchlich geändert wurde. Oder git konnte nicht eindeutig heraus finden, wohin die ausgewählte Änderung gehört. Solche Konflikte muss man manuell auflösen. Ich zeige hier, wie man das macht.
Zuerst müssen wir einen Konflikt erzeugen. Ändere dazu in dem Brief die unteren Zeilen:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Filialleiterin Erika Zinker
Erstelle davon einen Schnappschuss:
git commit -a -m "Die letzten zwei Zeilen zusammen gefasst" gitk --all
Nun wechseln wir in die Rolle eines Kollegen, der basierend auf dem gleichen vorherigen Stand eine andere kollidierende Änderung in der selben Zeile vornimmt:
git checkout 5058Ändere jetzt den Brief wie folgt:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Erika Zinker (Filialleitung)
Erstelle einen Schnappschuss:
git commit -a -m "Filialleitung in Klammern hinzugefügt" gitk --all
Die zwei obersten Änderungen betreffen die gleiche Textzeile im Brief. Versuche, diese Änderungen zusammen zu fühen:
git merge master
Es ist ein Konflikt aufgetreten. Git hatte ein Problem, die Änderung automatisch zu übertragen. Du sollst jetzt die Datei brief.txt in einem Editor öffnen und das Problem dort manuell beheben.
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß <<<<<<< HEAD ihre Erika Zinker (Filialleitung) ======= ihre Filialleiterin Erika Zinker >>>>>>> master
Zwischen den auffälligen Markierungen befinden sich die kollidierenden Varianten der letzten Textzeile. Git kann nicht wissen, welche Variante nun die gewünschte ist. Korrigiere die Datei manuell und entferne dabei die Markierungen:
Liebe Kunden, wir möchten Sie darauf hinweisen, dass unser Geschäft an der Elbstraße in den Sommerferien geschlossen bleibt. Sie können uns weiterhin per Email erreichen und dringende Waren in der Filiale Rumbelweg bekommen. Wir sind ab dem 21.08.2023 wieder für sie da. mit freundlichem Gruß ihre Filialleitung Erika Zinker
Nun kannst du die Zusammenführung mit folgenden Befehlen fortsetzen:
git commit -a -m "Merge-Konflikt bei der Filialleitung behoben" gitk --all
Das Ergebnis sieht in gitk so aus:
Es gibt grafische "merge Editoren", mit denen man solche Änderungen komfortabler vornehmen kann. Unter Linux benutze ich dazu gerne das Programm Meld, indem ich im Projektverzeichnis eingebe:
meld .
Das Programm zeigt links und rechts die beiden kollidierenden Änderungen an. In der Mitte sollst du die Datei nun so editieren, wie sie am Ende aussehen soll.
Du kannst dazu auf die Pfeile klicken, oder die Zwischenablage benutzen, oder manuell tippen. Ich habe mich für die rechte Variante entschieden:
Beim Abspeichern committed das Meld Programm die Änderung automatisch.
Für Windows empfehle ich dazu das ähnliche Programm WinMerge.
Der tägliche Arbeitsablauf im Team könnte dann so aussehen:
Die Verbindung zum Server läuft üblicherweise über ein gemeinsames Dateisystem/Netzlaufwerk oder SSH.
Ich zeige das zuerst am Beispiel eines gemeinsamen Netzlaufwerkes. Auf dem Server ist abgesehen von der Dateifreigabe keine weitere Installation oder Konfiguration notwendig. In den folgenden Beispielen ist "/repository" das gemeinsame Netzlaufwerk auf das alle Entwickler Zugriff haben.
Damit du dein Passwort (vom Server) nicht immer wieder eingeben musst, empfehle ich dir, den Credential-Helper zu aktivieren:
git config --global credential.helper store
Damit der Server Schnappschüsse speichern kann, muss man dort zunächst ein leeres Projektverzeichnis anlegen und als "bare" Repository initialisieren:
cd /repository git init --bare MeinProjekt.git
Dabei wird ein Verzeichnis mit dem Namen "/repository/MeinProjekt.git" angelegt, worin Git die gleichen Verwaltung-Dateien ablegt, wie lokal im versteckten ".git" Verzeichnis.
Git unterscheidet zwischen normalen Projekt-Repositories für den Arbeitsplatz, und "bare" Repositories für den Server. Der Unterschied ist, dass bare Repositories keine Arbeitsdateien (also die eigentlichen Quelltexte, die man editiert) enthalten. Dennoch können beide Varianten zum pushen und pullen verwendet werden. Entwickler haben damit prinzipiell die Möglichkeit, Schnappschüsse am Server vorbei zu teilen. Außerdem kann man Schnappschüsse von einem Server zu einem anderen übertragen.
Wenn du das Projekt bereits lokal begonnen hast, kannst du deine Schnappschüsse wie folgt auf den Server übertragen:
cd MeinProjekt git remote add origin /repository/MeinProjekt.git git push --all --set-upstream origin
In diesem Fall ist "origin" ein symbolischer Name für die Verbindung zum Netzlaufwerk "/repository/MeinProjekt.git". Der Parameter --all sorgt dafür, dass alle Zweige bereit gestellt werden. Ansonsten würde Git nur den aktuellen Zweig senden.
Die anderen Team-Mitglieder müssen das Projekt anschließend vom Server klonen, um daran teilzunehmen.
Beim Klonen wird ein komplettes Projekt vom Server auf den lokalen Computer als Arbeitsprojekt kopiert:
cd Projekte git clone /repository/MeinProjekt.git cd MeinProjekt
Das funktioniert auch mit leeren Projekten. Anschließend kannst du die Namen der verfügbaren Zweige auflisten:
git branch --all
Der Parameter --all sorgt dafür, dass alle Zweige angezeigt werden. Ohne diesen Parameter würdest du nur die lokalen Zweige in deinem Projektverzeichnis sehen. Danach könntest du beispielsweise mit
git checkout NameDesBranches
zu dem gewünschten Zweig wechseln.
Um neue Schnappschüsse vom lokalen Projekt an den Server zu senden, gibt man ein:
git push
Der git push Befehl sendet normalerweise nur den aktuellen Zweig. Du kannst den Parameter --all verwenden, um alle Zweige zu senden.
Um neue Schnappschüsse vom Server ins lokale Projekt zu holen, gibt man ein:
git pull
Der git pull Befehl holt normalerweise nur den aktuellen Zweig. Du kannst den Parameter --all verwenden, um alle Zweige zu holen.
Eventuell tritt dabei ein Konflikt auf, nämlich wenn jemand anderes zwischenzeitlich die gleiche Datei geändert hat, wie du. In diesem Fall zeigt Git eine Hilfe an, wie du den Konflikt lösen kann. In der Regel hat man nun die Wahl zwischen dem zusätzlichen Parameter --rebase oder --merge:
Markierungen werden von Git außerhalb der Schnappschüsse verwaltet, deswegen muss man diese separat an den Server senden:
git push --tagsAnstelle von "--tags" kann man auch einzelne Markierungen senden:
git push "1.0.0"
Um alle Markierungen vom Server zu holen, gibt man den folgenden Befehl ein:
git fetch --all --tags
SSH ist die einfachste Methode, sicher auf einen Linux Server im lokalen Netz oder über das Internet zuzugreifen. Anstelle des lokalen Verzeichnisnamens "/repository/MeinProjekt.git" ist die Syntax dann wahlweise
git clone deinName@serverName:/repository/MeinProjekt.gitoder
git clone ssh://deinName@serverName/repository/MeinProjekt.git
Wenn du unsicher bist, in welchem Zustand sich Git gerade befindet oder welchen Befehl du als nächstes eingeben sollst, dann gebe ein:
git status
Versehentlich gelöschte Dateien/Verzeichnisse kannst du sofort wieder herstellen, indem du eingibst:
git checkout dateiname
Mit dem gleichen Befehl kannst du auch Änderungen an Dateien verwerfen. Die Datei wird dabei wieder in den Zustand des letzten Schnappschusses zurück versetzt.
Um den letzten noch nicht gepushten Schnappschuss (commit) zu löschen, gibst du ein:
git reset HEAD^
Deine Arbeistdateien bleiben dabei erhalten. Wenn du zusätzlich die Option "--hard" angibst, werden deine Änderungen mit verworfen: alle Dateien werden in den Zustand des vorletzten Schnappschusses zurück versetzt.
Um den letzten noch nicht gepushten Schnappschuss zu erweitern oder seinen Kommentar zu ändern:
git commit --amend
Man soll Schnappschüsse auf dem Server niemals verändern oder gar löschen, denn das kann üble Probleme auslösen. Versuche nicht, peinliche Fehlversuche vom Server zu entfernen! Erstelle stattdessen einen ganz normalen weiteren Schnappschuss, der den Fehler korrigiert.
Du kannst in deinem Projektverzeichnis eine Datei namens ".gitignore" anlegen, um Dateien/Verzeichnisse aufzulisten, die Git ignorieren soll. Das folgende Beispiel schließt alle "logs" Verzeichnisse und Backup-Dateien in beliebigen Verzeichnissen aus.
**/logs *.bak
Für weitere Informationen zu den Befehlen siehe die Seiten Git Book und Git Reference.
Als Softwareentwickler arbeitst du wahrscheinlich die meiste Zeit mit einer IDE. Jede mir bekannte IDE unterstützt GIT mehr oder weniger gut. Wenn immer deine IDE eine unklare Fehlermeldung ausgibt oder du nicht weisst, wie es weiter geht, erinnere dich an den Befehl "git status". Dessen Ausgabe ist sehr oft wesentlich hilfreicher. Die wechselweise Verwendung von IDE und Kommandozeile ist ausdrücklich erwünscht.
Ich hatte auch öfters mit einer falschen grafischen Darstellung der Historie zu kämpfen, bis ich heraus fand, dass "gitk --all" sie immer korrekt darstellt.
GitLab ergänzt Git um eine Web basierte Benutzeroberfläche mit Funktionen für Projektverwaltung und kontinuierliche Integration. GitLab wird normalerweise auf Firmen-eigene Server installiert, es gibt aber auch einen öffentlichen Dienst.
GitHub ist ein ähnlicher öffentlicher Dienst von Microsoft. Die meisten Open-Source Projekte sind hier zu finden.