Git-Cheat-Sheet [PDF]
(wizardzines.com)- Ein PDF, das häufige Stolperstellen in Git nach Commit-Erstellung, Branch-Wechsel, Vergleich von Änderungen, Remote-Synchronisierung und Befehlen zum Verwerfen von Änderungen schnell auffindbar zusammenfasst
- Der lokale Workflow dreht sich um
git status,git add,git commitundgit diff, um den Zustand vor und nach dem Staging zu prüfen und Commits zu erstellen - Branch-Arbeiten werden mit
git switch,git checkout,git branch,git merge,git rebaseundgit cherry-pickfür Erstellen, Wechseln, Mergen und Rebasing erledigt - Für das Durchsuchen der Historie und die Wiederherstellung sind
git log,git blame,git show,git reflog,git resetundgit restoreenthalten; auch Branches, Tags,HEADund Remote-Branches können als Commit-Referenzen verwendet werden - Remote-Repository-Arbeiten behandeln mit
git remote add,git fetch,git pull,git push,git push --force-with-leaseundgit push --tagsdie Abläufe zum Holen und Senden von Änderungen
Repository starten und aktuellen Status prüfen
- Neues Repository starten:
git init
- Bestehendes Repository klonen:
git clone $URL
- Aktuelle Position und Status prüfen:
git status
Commit vorbereiten und erstellen
- Nicht getrackte Datei hinzufügen:
git add $FILE
- Alle nicht getrackten Dateien und nicht gestagten Änderungen hinzufügen:
git add .
- Nur ausgewählte Teiländerungen einer Datei stagen:
git add -p
- Datei löschen oder verschieben:
git rm $FILEgit mv $OLD $NEW
- Datei aus dem Git-Tracking entfernen, ohne sie zu löschen:
git rm --cached $FILE
- Alles unstagen:
git reset HEAD
- Commit erstellen:
git commit- Öffnet einen Texteditor zum Schreiben der Nachricht
- Commit mit direkt angegebener Nachricht:
git commit -m 'message'
- Commit inklusive nicht gestagter Änderungen mit Nachricht:
git commit -am 'message'
Branch wechseln und verwalten
- Branch wechseln:
git checkout $NAMEgit switch $NAME
- Branch erstellen:
git checkout -b $NAMEgit switch -c $NAME
- Branch-Liste anzeigen:
git branch
- Branches nach den neuesten Commits sortieren:
git branch --sort=-committerdate
- Branch löschen:
git branch -d $NAME
- Branch zwangsweise löschen:
git branch -D $NAME
Historie durchsuchen und Code nachverfolgen
- Branch-Historie anzeigen:
git log main
- Beziehung zweier Branches als Graph anzeigen:
git log --graph a b
- Einzeiliges Log anzeigen:
git log --oneline
- Prüfen, wer jede Zeile einer Datei zuletzt geändert hat:
git blame $FILENAME
- Alle Commits anzeigen, die eine Datei geändert haben:
git log $FILENAME
- Commits finden, die einen bestimmten Text hinzugefügt oder entfernt haben:
git log -S banana
Änderungen vergleichen
- Unterschiede zwischen Commit und Parent-Commit anzeigen:
git show $COMMIT_ID
- Unterschiede zwischen einem Merge-Commit und den gemergten Parents anzeigen:
git show --remerge-diff $COMMIT_ID
- Diff-Zusammenfassung anzeigen:
git diff $COMMIT_ID --statgit show $COMMIT_ID --stat
- Zwei Commits vergleichen:
git diff $COMMIT_ID $COMMIT_ID
- Nur eine bestimmte Datei mit einem Commit vergleichen:
git diff $COMMIT_ID $FILENAME
- Alle gestagten und nicht gestagten Änderungen vergleichen:
git diff HEAD
- Nur gestagte Änderungen vergleichen:
git diff --staged
- Nur nicht gestagte Änderungen vergleichen:
git diff
Konfigurationsdateien und Optionen
- Lokale Git-Konfigurationsdatei:
.git/config
- Globale Git-Konfigurationsdatei:
~/.gitconfig
- Liste zu ignorierender Dateien:
.gitignore
- Konfigurationsoption setzen:
git config user.name 'Julia'
- Globale Option setzen:
git config --global ...
- Alias hinzufügen:
git config alias.st status
- Mögliche Konfigurationsoptionen prüfen:
man git-config
Historie ändern und Dateien wiederherstellen
- Den neuesten Commit zurücksetzen, Arbeitsverzeichnis unverändert lassen:
git reset HEAD^
- Fehlgeschlagenes Rebase zurücksetzen:
git reflog BRANCHNAMEgit reset --hard $COMMIT_ID
- Die letzten 5 Commits zu einem zusammenfassen:
git rebase -i HEAD^^^^^^- Bei den zusammenzufassenden Commits
pickinfixupändern
- Dateiversion aus einem anderen Branch oder Commit holen:
git checkout $COMMIT_ID $FILEgit restore $FILE --source $COMMIT_ID
- Commit-Nachricht ändern oder vergessene Datei hinzufügen:
git commit --amend
Branches zusammenführen
- Fast-Forward-Merge, der den aktuellen Branch mit einem anderen Branch aktualisiert:
git switch maingit merge banana
- Einen Commit in einen anderen Branch kopieren:
git cherry-pick $COMMIT_ID
- Auseinanderlaufende Branches per Rebase zusammenführen:
git switch bananagit rebase main
- Auseinanderlaufende Branches per Merge zusammenführen:
git switch maingit merge bananagit commit
- Auseinanderlaufende Branches per Squash-Merge zusammenführen:
git switch maingit merge --squash bananagit commit
Remote-Repository und Synchronisierung
- Remote-Repository hinzufügen:
git remote add $NAME $URL
- Branch
mainzum Remoteoriginpushen:git push origin main
- Einen Branch beim ersten Push zu
originhochladen und Tracking-Branch setzen:git push -u origin $NAME
- Aktuellen Branch zum Remote-Tracking-Branch pushen:
git push
- Force-Push:
git push --force-with-lease
- Tags pushen:
git push --tags
- Änderungen holen, ohne lokale Branches zu ändern:
git fetch origin main
- Alle Branches fetchen:
git fetch --all
- Nach dem Fetch auf den aktuellen Branch rebasen:
git pull --rebase
- Nach dem Fetch in den aktuellen Branch mergen:
git pull origin maingit pull
Wie man auf Commits verweist
- An der Stelle von
$COMMIT_IDkönnen verschiedene Referenzen verwendet werden:- Branch:
main - Tag:
v0.1 - Commit-ID:
3e887ab - Remote-Branch:
origin/main - Aktueller Commit:
HEAD - Commit vor 3 Commits:
HEAD^^^ - Commit vor 3 Commits:
HEAD~3
- Branch:
Änderungen verwerfen
- Sowohl gestagte als auch nicht gestagte Änderungen an einer Datei löschen:
git checkout HEAD $FILE
- Nicht gestagte Änderungen an einer Datei löschen:
git checkout $FILE
- Alle gestagten und nicht gestagten Änderungen löschen:
git reset --hard
- Gestagte und nicht gestagte Änderungen stashen:
git stash
- Nicht getrackte Dateien löschen:
git clean
1 Kommentare
Hacker-News-Kommentare
Es gibt ein paar versteckte Perlen unter den Befehlen:
git diff --stagedzeigt den Unterschied zwischen dem letzten Commit und dem aktuell gestagten Inhalt. Das ist praktisch, um beim feingranularen Stagen von Dateien oder Hunks zu prüfen, ob wirklich nur das Gewollte enthalten ist.git log <file>zeigt nur die Commits an, in denen die betreffende Datei geändert wurde. So muss man sich nicht durch das komplettegit logwühlen, was besonders bei Dateien nützlich ist, die sich nicht oft ändern.Wenn man bei
git add --patchnoch feiner auswählen möchte als die von Git aufgeteilten Hunks, sollte man die Optioneausprobieren. Dabei wird erklärt, wie man einzelne Zeilen ein- oder ausschließt, sodass man es sich nicht merken muss.git diff --stagedein Alias fürgit diff --cachedist. Ich verwendecachedschon seit Jahren, aberstagedist definitiv intuitiver. Ich weiß nur nicht, ob ich dieses Muskelgedächtnis wieder loswerde.Wer Interesse hat, kann hier schauen oder Aliasse vorschlagen: https://gitlab.com/Falimonda/gitrc
git config --global commit.verbose truesetzt, fügt Git im Kommentarbereich des Commit-Message-Editors automatisch den gestagten Diff ein.Einer meiner Lieblingsbefehle, der nicht auf der Liste steht, ist
git log -LstartLine,endLine:fileName.Das ist wie ein erweitertes
git blame: Es zeigt, wie sich die angegebenen Zeilen im Lauf der Zeit verändert haben und wer sie geändert hat. Dabei wird die Verfolgung auch fortgesetzt, wenn sich Zeilennummern ändern oder die Datei verschoben wird.Es beantwortet Fragen wie „Wer hat das wann und warum so gemacht?“ oder „Seit wann ist das so?“.
Das erinnert mich an das Zitat von Phil Karlton: „In der Informatik gibt es nur zwei harte Probleme: Cache-Invalidierung und Benennung.“
Aus dieser Perspektive fand ich den Git-Befehlsnamen
blameimmer ziemlich seltsam, und offenbar ging das nicht nur mir so.What does 'git blame' do? https://stackoverflow.com/questions/31203001/what-does-git-blame-do
Blame someone else for your bad code https://news.ycombinator.com/item?id=27963868
Git blame should be called git credit https://dev.to/damcosset/git-blame-should-be-called-git-credit-27h5
Does Git Blame sound too negative? https://www.reddit.com/r/ProgrammerHumor/comments/r5lzyo/does_git_blame_sound_too_negative_just_look_up/
gitbedenkt, wirktblamewie ein markengerechter Name.blameinwhoumbenannt. Da ich allerdings ein eingefleischter Vim-Nutzer bin, verwende ich eigentlich einfachw.Mir gefiel die Art, wie ich Git gelernt habe. Ich habe zunächst mit dem Third-Party-Git-GUI-Tool Sourcetree angefangen, das sehr leicht zu benutzen und zu verstehen war.
Danach bin ich zu
git guigewechselt, aber diesen Schritt kann man auch überspringen. Später wurde es mir lästig, jedes Mal eine UI zu öffnen, also habe ich Terminal-Befehle gelernt.Ich würde das Git-Anfängern empfehlen, aber das ist natürlich nur meine n=1-Erfahrung.
clone,pull,commitundpush, und bisher hat das völlig gereicht. Git kann tatsächlich so einfach sein. Natürlich kann man bei Bedarf auch komplexere Nutzungsweisen lernen.In dem Moment, in dem ich Magit zu verwenden begann, fing ich an, Git zu verstehen.
Über Sublime Merge kann ich nur Gutes sagen.
Ich frage mich, ob Git aus historischen Gründen unnötig komplex ist.
Wenn ich dieses Cheat Sheet sehe, wird mir diese Komplexität noch bewusster.
Dass es so weit verbreitet wurde, ist vielleicht ein „glücklicher Zufall“ oder auch ein Unglück. GitHub hat großen Anteil daran, Git durch „kostenloses Git-Hosting“ zu popularisieren, aber ich halte Git nicht für das ideale Versionsverwaltungssystem für viele Projekte.
Weil es für Linus und Linux gebaut wurde, wirken Terminologie und Workflow manchmal umgekehrt zu gewöhnlichen Versionsverwaltungssystemen. Der Name
Pull Requestkommt ebenfalls aus der Linux-Entwicklung, weil Linus oder die Maintainer Änderungen in den Kernel-Tree hineinziehen. In anderen Systemen nennt man das meistMerge Request, und das ist viel logischer, weil Änderungen unabhängig von ihrer Herkunft in den Tree zusammengeführt werden.Git war fast das einzige Open-Source-verteilte Versionsverwaltungssystem, das mit riesigen Codebasen schnell umgehen konnte, und dadurch wurde es auch in Großunternehmen durch Trägheit zum Standard.
Für persönliche Projekte bevorzuge ich Mercurial deutlich und nutze es auch tatsächlich, aber wenn man Hg auf einer großen Codebasis wie Android AOSP verwendet, ruckelt es extrem. Mercurial hat die bessere Benutzeroberfläche und Befehlsstruktur und kann auch spontan einen Webserver starten, um den Änderungsbaum anzuzeigen, aber da es in Python geschrieben ist, sind Performance und Skalierbarkeit nicht ideal.
git checkoutimmer weiter mit Funktionen überladen, was die User Experience noch verwirrender machte.In aktuellem Git sind die Kosten für neue Unterbefehle gesunken, und man hat begonnen, spezifischere Befehle wie
git switchhinzuzufügen.log,add,commit,pullundpushzu kennen. Es gibt ja auch GUI-Tools.Ehrlich gesagt finde ich Git für normale Arbeit gar nicht so komplex. Es hat nur viele mächtige Funktionen, die man bei Bedarf nutzen kann.
Kernel-Entwickler mussten dezentral miteinander kommunizieren und auf der Arbeit anderer weiterarbeiten. Wie arbeitet man in einem Projekt, an dem 15.000 Menschen Code schreiben? Genau dafür wurde Git gebaut.
Es ist so komplex, wie es sein muss, um den Workflow zu unterstützen, für den es entworfen wurde. Ein einfacheres Werkzeug zu bauen ist leicht, aber dann könnte es komplexe Workflows wie die Entwicklung des Linux-Kernels nicht unterstützen. Es ist also nicht unnötig komplex, aber für einfache Anwendungsfälle definitiv komplexer als nötig.
Wenn man ein weniger komplexes Frontend braucht, gibt es viele Tools, die den Umgang mit Git erleichtern. Wenn man kein hauptberuflicher Softwareentwickler ist, würde ich nicht empfehlen, Git direkt zu benutzen. Wenn man aber Vollzeitentwickler ist, lohnt es sich, Zeit in das Verständnis der internen Konzepte zu investieren, und sobald man sie verstanden hat, ist Git im Verhältnis zu dem, was es leistet, ziemlich elegant.
Ich würde niemandem den Status als Softwareentwickler absprechen, nur weil er Git nicht kennt, aber wenn es einem keinen Dopaminschub gibt, selbst herauszufinden, wie solche grundlegenden Systeme funktionieren, dann ist dieses Feld vielleicht einfach nicht das Richtige. Das ist aber auch okay; nicht alles passt zu jedem.
Um Git-Navigation zu lernen, empfehle ich https://learngitbranching.js.org. Natürlich gilt auch https://xkcd.com/1597/.
Ich kannte
git add -pnicht, aber es ist wirklich nützlich.-p,--patchermöglicht es, interaktiv Patch-Hunks zwischen Index und Working Tree auszuwählen und dem Index hinzuzufügen. So bekommt man die Gelegenheit, Unterschiede zu prüfen, bevor man Änderungen in den Index aufnimmt.Was ich hier noch ergänzen möchte, ist die Kombination aus
git commit --fixup $COMMIT_IDundgit rebase -i upstream/master --autosquash.Das ist in meinem aktuellen Workflow unverzichtbar geworden. Im Julia-Beispiel wird
HEAD^^^^^verwendet, um die letzten fünf Commits zu rebaseden, aber ich habe bis vor KurzemHEAD~5benutzt. Jetzt habe ich gelernt, dass man einfach alle Commits bis zum upstream-HEADrebaseden kann.git commit --fixup $COMMIT_IDmuss ich sofort übernehmen. Ich habe immer kleine Korrektur-Commits wie „oops GET users/me“ erstellt und sie beim nächsten interaktiven Rebase manuell verschoben und als Fixup markiert, aber diese Methode ist viel besser.„Die letzten fünf Commits zu einem zusammenfassen:
git rebase -i HEAD^^^^^^“ — ich glaube,git rebase -i HEAD~5ist korrekt.Vorausgesetzt natürlich, dass man nur eine lineare Historie rebasen will.
https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git
Die größte Erkenntnis war der Moment, in dem ich verstanden habe, dass alle Commits immer noch intern vorhanden sind. Tags und Branches zeigen nur auf Commits, und auch die Commits, auf die ein Branch früher gezeigt hat, sind nicht verschwunden.
Viele Befehle — wahrscheinlich fast alle — sind nicht-destruktiv, sodass man frühere Zustände eines Branches leicht referenzieren kann.
git refloghatte ich schon gesehen, aber ich habe es meist nur benutzt, um mich zu erinnern: „Wie hieß noch mal dieser Branch, an dem ich früher gearbeitet habe?“Ich hatte eine halbwegs gesunde Angst vor Aktionen, mit denen man mitten in eine unerwünschte Konfliktauflösung geraten kann. Meist lag das daran, dass ich versehentlich einen falschen Commit oder Branch referenziert hatte und dadurch Konflikte entstanden.
Diese Angst ist nicht völlig verschwunden, aber zumindest beim Wiederherstellen früherer Arbeit zwischen Vorgängen wie Rebase bin ich inzwischen deutlich entspannter.
Wenn ich nicht weiß, ob nach einer Aktion Konflikte auftreten, probiere ich es einfach aus und sehe nach. Wenn es Konflikte gibt, löse ich sie, mache die Aktion rückgängig, die den Konflikt erzeugt hat, oder erstelle anderswo einen neuen Commit und lasse die Konflikte erst einmal für später liegen.
Wenn ich weiß, dass es Konflikte geben wird, dupliziere ich den betreffenden Branch und gleiche es vorab ab oder führe die konfliktverursachende Aktion aus und gehe den Lösungsprozess durch. Wenn die Auflösung unübersichtlich wird, mache ich einen Teil der Lösung wieder rückgängig und versuche weiter, schiebe es vorübergehend auf und arbeite an etwas anderem oder verwerfe den gesamten Tree.
Ganz offen gesagt: Man sollte Git beiseitelegen und sich JJ ansehen.
https://martinvonz.github.io/jj/v0.17.1/
Ich könnte mir vorstellen, dass sogar Linus die Git-UI für miserabel hält. JJ hat einen hervorragenden Workflow.
Allerdings habe ich es außer ein wenig Herumprobieren noch nicht wirklich intensiv in echter Arbeit genutzt, daher will ich mich nicht zu endgültig festlegen.