Die Befehle aus Versionsverwaltung mit Git zum Nachschlagen: Commits anlegen, die Geschichte ansehen, mit Branches arbeiten, Konflikte lösen, mit anderen teilen und Fehler rückgängig machen. Wie dein Workspace sich bei einem Git-Server anmeldet, steht unter Git-Server: Zugang und Veröffentlichen.
| Begriff | Was es ist |
|---|---|
| Repository | ein Ordner, dessen Geschichte Git verwaltet; die Geschichte selbst liegt im versteckten Ordner .git
|
| Commit | ein gespeicherter Stand aller Dateien, mit Nachricht, Autor, Zeit und einer ID wie a3ac34a
|
| Arbeitsverzeichnis | die Dateien, wie du sie gerade siehst und bearbeitest |
| Staging Area | was mit dem nächsten Commit gespeichert wird; git add legt Änderungen dorthin |
| Branch | ein Name, der auf einen Commit zeigt und mit jedem neuen Commit weiterrückt, zum Beispiel main
|
HEAD |
wo du gerade bist: meist ein Branch, nach git checkout HEAD~2 ein einzelner Commit |
| Remote | ein anderes Repository, mit dem du Commits austauschst, meist origin auf einem Git-Server |
HEAD~1 ist der Commit vor HEAD, HEAD~2 der davor. Statt einer ID genügen ihre ersten Zeichen, solange sie eindeutig sind.
Linus Torvalds (geboren 1969). Das Terminal im Workspace läuft unter Linux: Das hat er 1991 als Student in Helsinki angefangen, »nur ein Hobby«, schrieb er damals. Heute läuft Linux auf den meisten Servern der Welt und in jedem Android-Handy.
2005 brauchte er für die Arbeit an Linux eine neue Versionsverwaltung und schrieb in wenigen Tagen die erste Fassung von Git.
Foto: Raysonho, 2018, CC0 (Wikimedia Commons)
| Befehl | Was er tut |
|---|---|
git init |
macht den aktuellen Ordner zu einem Repository, ohne Commits |
git clone ADRESSE |
holt eine Kopie eines Repositorys mit seiner ganzen Geschichte in einen neuen Ordner |
git clone ADRESSE ordner |
dasselbe in einen Ordner mit anderem Namen |
Bevor du den ersten Commit machst, muss Git wissen, wer du bist: Git sagen, wer du bist. Ein Repository für eine Aktivität klonst du so, wie es unter Repository klonen steht.
| Befehl | Was er tut |
|---|---|
git status |
zeigt, welche Dateien geändert, bereitgelegt oder Git noch unbekannt sind (»Untracked files«) |
git add datei |
legt eine neue oder geänderte Datei für den nächsten Commit bereit; git add . alles im Ordner |
git commit -m "Nachricht" |
speichert alles Bereitgelegte als Commit |
git commit -a -m "Nachricht" |
legt vorher alle geänderten Dateien bereit, die Git schon kennt; neue Dateien brauchen trotzdem git add
|
git diff |
zeigt die Änderungen, die noch nicht bereitgelegt sind, Zeile für Zeile |
git diff --staged |
zeigt, was bereitgelegt ist und mit dem nächsten Commit gespeichert wird |
git mv alt neu |
benennt eine Datei um oder verschiebt sie |
git rm datei |
löscht eine Datei und legt das Löschen bereit |
Der Ablauf ist fast immer derselbe:
git status git add README.md git commit -m "Anleitung ergänzt"
Eine gute Nachricht sagt in einer Zeile, was der Commit ändert, so dass du ihn in git log später wiederfindest: »Punkte zählen, wenn ein Stern gefangen wird«, nicht »weiter«.
| Befehl | Was er zeigt |
|---|---|
git log |
alle Commits, der neueste oben, mit ID, Autor, Datum und Nachricht |
git log --oneline |
jeden Commit in einer Zeile |
git log --oneline --graph --all |
alle Branches als Graph, wo sie sich trennen und wieder zusammenkommen |
git log --author=Name |
nur die Commits einer Person; git log -- datei nur die, die eine Datei ändern |
git show a3ac34a |
einen Commit mit allen seinen Änderungen |
git blame datei |
zu jeder Zeile, in welchem Commit und von wem sie zuletzt geändert wurde |
Eine lange Ausgabe zeigt Git seitenweise wie less: Pfeiltasten und Leertaste blättern, Q beendet.
Was dein Programm erzeugt (übersetzte Programme, Bilder, die es rechnet, Ordner wie node_modules), gehört nicht ins Repository. Eine Datei .gitignore im Repository nennt sie, ein Muster pro Zeile:
hello *.o build/
hello ist eine Datei mit genau diesem Namen, *.o jede Datei, die auf .o endet, build/ ein ganzer Ordner. git status zeigt sie danach nicht mehr an, und git add . lässt sie aus. Die .gitignore selbst wird committet, damit sie für alle gilt. Eine Datei, die schon committet ist, ignoriert Git erst, wenn du sie mit git rm --cached datei aus dem Repository nimmst; im Ordner bleibt sie.
| Befehl | Was er tut |
|---|---|
git branch |
listet die Branches auf; vor dem, auf dem du bist, steht ein *
|
git branch feature |
legt einen Branch an, der auf den aktuellen Commit zeigt; du bleibst, wo du bist |
git checkout feature |
wechselt zu dem Branch: Die Dateien im Ordner sind jetzt die von dort |
git checkout -b feature |
beides auf einmal: anlegen und wechseln |
git merge feature |
holt die Commits von feature in den Branch, auf dem du bist |
git branch -d feature |
löscht den Branch, wenn seine Commits schon gemergt sind; -D auch sonst |
Vor dem Wechseln sollte git status nichts Geändertes zeigen: Committe erst, oder leg die Änderungen mit git stash beiseite (siehe unten). Neuere Fassungen von Git kennen für das Wechseln auch git switch feature und git switch -c feature; sie tun dasselbe wie die beiden checkout-Zeilen oben.
Gemergt wird immer in den Branch, auf dem du gerade bist. Um feature in main zu bringen:
git checkout main git merge feature
Haben zwei Commits dieselben Zeilen verschieden geändert, kann Git sie nicht von selbst zusammenführen. git merge oder git pull melden dann CONFLICT, und in der Datei stehen beide Fassungen:
<<<<<<< HEAD HOLAAA ======= HEYYYY >>>>>>> ef91739
Oben steht deine Fassung, unten die, die dazukommen soll. So löst du den Konflikt:
<<<<<<<, ======= und >>>>>>>.git add datei, für jede Datei mit Konflikt; git status zeigt, welche es noch gibt.git commit -m "Konflikt gelöst", danach wie gewohnt git push.Visual Studio Code zeigt über jedem Konflikt die Knöpfe »Accept Current Change«, »Accept Incoming Change« und »Accept Both Changes«; sie erledigen die Schritte 1 und 2. Willst du lieber wieder zum Stand vor dem Merge, bricht git merge --abort ihn ab.
| Befehl | Was er tut |
|---|---|
git remote add origin ADRESSE |
nennt ein anderes Repository origin, damit du mit ihm Commits austauschen kannst |
git remote -v |
zeigt, welche Remotes es gibt und wo sie liegen |
git push -u origin main |
schickt main zum ersten Mal und merkt sich origin als Ziel für diesen Branch |
git push |
schickt deine neuen Commits zum Remote |
git pull |
holt die neuen Commits vom Remote und führt sie mit deinen zusammen |
git config pull.rebase false |
sagt Git einmal, dass git pull zusammenführen soll, wenn beide Seiten neue Commits haben |
git push origin --tags |
schickt auch die Tags (siehe unten) |
Hol mit git pull, bevor du anfängst, und schick mit git push, wenn du fertig bist. Lehnt Git deinen Push ab, weil jemand vor dir gepusht hat, steht unter Wenn Git den Push ablehnt, was zu tun ist. Bricht git pull ab, weil du Dateien geändert hast, die auch in der neuen Version anders sind, hilft git stash wie unter Eine neue Version der Vorlage holen.
| Befehl | Was er tut |
|---|---|
git checkout HEAD~2 |
die Dateien, wie sie zwei Commits vorher waren |
git checkout a3ac34a |
die Dateien, wie sie in diesem Commit waren; git checkout v1.0 wie bei einem Tag |
git checkout main |
zurück zum neuesten Stand von main
|
git restore --source HEAD~2 datei |
nur diese eine Datei so, wie sie zwei Commits vorher war; danach wie jede Änderung committen |
Nach git checkout auf einen Commit oder Tag meldet Git detached HEAD: Du bist auf keinem Branch. Ansehen und ausprobieren geht, aber Commits von hier gehören zu keinem Branch. Willst du von hier aus weiterarbeiten, leg zuerst mit git checkout -b neuer-name einen Branch an.
Welcher Befehl passt, hängt davon ab, wie weit die Änderung schon gekommen ist:
| Die Änderung ist … | Befehl | Was passiert |
|---|---|---|
| nur im Arbeitsverzeichnis | git restore datei |
Die Datei ist wieder auf dem Stand des letzten Commits. Die Änderung ist weg. |
mit git add bereitgelegt |
git restore --staged datei |
Die Änderung kommt aus der Staging Area zurück ins Arbeitsverzeichnis; verloren geht nichts. |
| im letzten Commit, noch nicht gepusht | git commit --amend -m "Nachricht" |
Der letzte Commit wird ersetzt, mit dem, was jetzt bereitliegt, und der neuen Nachricht. |
| schon committet | git revert HEAD |
Ein neuer Commit hebt den letzten auf; statt HEAD geht jede Commit-ID. |
| noch nicht fertig, soll aber kurz weg | git stash |
legt alle Änderungen beiseite, der Ordner ist wieder auf dem Stand des letzten Commits; git stash pop holt sie zurück, git stash list zeigt, was beiseite liegt |
git pull geholt haben können, ersetzt du nicht mit --amend, sondern hebst ihn mit git revert auf: Sonst passt ihre Geschichte nicht mehr zu deiner, und der nächste Push wird abgelehnt.
Was einmal committet war, findet Git meist wieder: git reflog listet, wo HEAD in letzter Zeit überall stand, auch Commits, auf die kein Branch mehr zeigt. Was mit git restore verworfen wurde, war nie committet und ist wirklich weg.
Ein Tag ist ein fester Name für einen Commit, etwa für eine Version, die du abgibst. Anders als ein Branch rückt er nicht weiter.
| Befehl | Was er tut |
|---|---|
git tag -a v1.0 -m "Abgabe" |
gibt dem aktuellen Commit den Namen v1.0, mit einer Nachricht |
git tag |
listet die Tags auf |
git push origin v1.0 |
schickt einen Tag zum Remote; git push origin --tags alle |
git checkout v1.0 |
die Dateien, wie sie bei diesem Tag waren (detached HEAD, siehe oben) |
Zu jedem Befehl zeigt git help befehl alle Optionen, zum Beispiel git help commit.
Pro Git, Scott Chacon und Ben Straub, Apress, 2. Auflage 2014. Alles, was hier fehlt: Rebase, Git auf einem Server, die Arbeit mit GitHub und wie Git seine Commits intern speichert. Frei lesbar, auch auf Deutsch: auf git-scm.com.
Cover: Apress, CC BY-NC-SA 3.0 (progit2)