Suchen

Tutorial · Programmierung & Entwicklung

Git-Befehle: Die wichtigsten Kommandos erklärt, mit echten Beispielen

Du lernst zuerst, wie Git Dateien verwaltet, und gehst dann die wichtigsten Befehle Schritt für Schritt durch – vom ersten Commit bis zum Merge-Konflikt.

Grüne Terminal-Ausgabe auf einem dunklen Bildschirm

Das Wichtigste in Kürze

  • Git speichert Snapshots deines Projekts; Änderungen laufen vom Arbeitsverzeichnis über die Staging Area in einen Commit.
  • Branches sind günstig: Arbeite in einem eigenen Branch und führe ihn per merge oder rebase zurück.
  • git reset unterscheidet sich je nach Modus darin, ob nur HEAD, auch der Index oder zusätzlich das Arbeitsverzeichnis zurückgesetzt wird.
  • Rebase schreibt Commits neu: Wende es nicht auf Historie an, die schon andere von dir geholt haben.

Die Konzepte hinter den Befehlen

Git ist ein verteiltes Versionsverwaltungssystem. Nach der Darstellung in Pro Git speichert Git seine Daten nicht als Liste von Änderungen an Dateien, sondern als Folge von Snapshots: Bei jedem Commit hält Git fest, wie alle Dateien in diesem Moment aussehen. Unveränderte Dateien werden nicht erneut gespeichert, Git verweist auf die bereits vorhandene Version.

Eine Datei kann dabei drei Zustände haben: modified (geändert, noch nicht vorgemerkt), staged (für den nächsten Commit vorgemerkt) und committed (sicher in der lokalen Datenbank gespeichert). Daraus ergeben sich die drei Bereiche eines Projekts:

BereichBedeutung
Working Tree (Arbeitsverzeichnis)Die Dateien, die du auf der Platte siehst und bearbeitest
Staging Area (Index)Merkliste dessen, was in den nächsten Commit kommt
Git-Verzeichnis (.git)Datenbank mit der gesamten Historie

Dazu kommen drei weitere Begriffe. Ein Branch ist eine bewegliche Markierung auf einem Commit, über die du parallel an verschiedenen Strängen arbeitest. HEAD zeigt auf den Commit, den du gerade ausgecheckt hast. Ein Remote ist ein Repository auf einem anderen Rechner oder Server, mit dem du Commits austauschst.

Befehlsübersicht nach Aufgaben

AufgabeBefehl
Repository anlegengit init, git clone <url>
Stand ansehengit status, git diff, git log --oneline
Änderungen vormerkengit add <datei>
Commit anlegengit commit -m "Nachricht"
Branch anlegen/wechselngit switch -c <name>, git switch <name>
Branches auflisten/löschengit branch, git branch -d <name>
Branch einbindengit merge <name>, git rebase <ziel>
Arbeit zwischenlagerngit stash, git stash pop
Änderungen verwerfengit restore <datei>, git restore --staged <datei>
Historie zurücksetzengit reset --soft/--mixed/--hard <commit>
Mit Remote arbeitengit remote add, git fetch, git pull, git push

Repository anlegen, vormerken, committen

Die folgenden Beispiele laufen in einem frischen Verzeichnis. git init -b main legt ein Repository mit dem Branch main an. Danach hast du eine neue Datei, die Git noch nicht kennt (??):

Shell
git init -b main projekt
cd projekt
echo "# Projekt" > README.md
git status --short
Text
?? README.md

git add merkt die Datei vor, git commit speichert den Snapshot:

Shell
git add README.md
git status --short
git commit -m "Erster Commit: README"
Text
A  README.md
[main (root-commit) 374df69] Erster Commit: README
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

Das A in der linken Spalte bedeutet „staged, neu hinzugefügt“. Ändere die Datei jetzt, zeigt git diff den Unterschied zwischen Arbeitsverzeichnis und Staging Area:

Shell
echo "Zeile 2" >> README.md
git diff
Text
diff --git a/README.md b/README.md
index 5585de1..5ae98b0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
 # Projekt
+Zeile 2

Mit git commit -am stagest und committest du bereits getrackte Dateien in einem Schritt, git log --oneline zeigt die Historie kompakt:

Shell
git commit -am "README erweitert"
git log --oneline
Text
0dd594e README erweitert
374df69 Erster Commit: README

Praxis-Tipp: Schreibe Commit-Nachrichten so, dass man die Änderung ohne Diff versteht („README erweitert“), und committe zusammengehörige Änderungen gemeinsam. Das macht git log später nützlich.

Branches: Arbeiten ohne Risiko für main

Mit git switch -c legst du einen Branch an und wechselst gleich hinein. Ältere Anleitungen verwenden dafür git checkout -b; switch ist die speziellere Variante für diesen Zweck.

Shell
git switch -c feature/hallo
echo "print('hallo')" > hallo.py
git add hallo.py
git commit -m "hallo.py hinzugefuegt"
git switch main
git merge feature/hallo
Text
Switched to a new branch 'feature/hallo'
[feature/hallo 6b7f447] hallo.py hinzugefuegt
 1 file changed, 1 insertion(+)
 create mode 100644 hallo.py
Switched to branch 'main'
Updating 0dd594e..6b7f447
Fast-forward
 hallo.py | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 hallo.py

Weil auf main seit dem Abzweigen nichts passiert ist, genügt ein Fast-Forward: Git setzt main einfach auf den neueren Commit. Danach kannst du den fertigen Branch aufräumen:

Shell
git branch
git branch -d feature/hallo
Text
  feature/hallo
* main
Deleted branch feature/hallo (was 6b7f447).

Der Stern markiert den aktuellen Branch. -d löscht nur, wenn der Branch bereits eingebunden ist; das schützt vor Verlust.

Merge-Konflikt entstehen sehen und lösen

Ein Konflikt entsteht, wenn zwei Branches dieselbe Stelle unterschiedlich ändern. Wir erzeugen ihn absichtlich: Branch a und Branch b legen beide eine Datei titel.txt mit unterschiedlichem Inhalt an.

Shell
git switch -c a
echo "Titel: A" > titel.txt && git add . && git commit -m "Titel A"
git switch main
git switch -c b
echo "Titel: B" > titel.txt && git add . && git commit -m "Titel B"
git switch a
git merge b
Text
Auto-merging titel.txt
CONFLICT (add/add): Merge conflict in titel.txt
Automatic merge failed; fix conflicts and then commit the result.

git status --short zeigt AA titel.txt (beide Seiten haben die Datei hinzugefügt). In der Datei steht jetzt:

Text
<<<<<<< HEAD
Titel: A
=======
Titel: B
>>>>>>> b

Zwischen <<<<<<< und ======= steht deine Version (HEAD), darunter die des einzubindenden Branches. Du bearbeitest die Datei so, dass genau der gewünschte Inhalt übrig bleibt, und entfernst alle Markierungen. Hier entscheiden wir uns für Titel: AB. Danach schließt du den Merge ab:

Shell
echo "Titel: AB" > titel.txt
git add titel.txt
git commit -m "Merge b, Konflikt geloest"
git log --oneline --graph --all
Text
*   ac559bf Merge b, Konflikt geloest
|\
| * a3e2b2a Titel B
* | a23405d Titel A
|/
* 6b7f447 hallo.py hinzugefuegt
* 0dd594e README erweitert
* 374df69 Erster Commit: README

Der Graph zeigt den Merge-Commit mit zwei Eltern. Möchtest du den Merge lieber abbrechen, geht das vor dem Commit mit git merge --abort.

Merge oder Rebase?

Beide Befehle bringen die Arbeit eines Branches in einen anderen, aber auf unterschiedliche Weise. Merge verbindet beide Historien mit einem Merge-Commit und lässt alle bestehenden Commits unverändert. Rebase nimmt die Commits deines Branches und spielt sie neu auf der Spitze des Zielbranches ab. Das Ergebnis ist eine lineare Historie, aber die Commits sind neu (andere Hashes).

Ein Beispiel: main hat seit dem Abzweigen von r1 einen weiteren Commit bekommen.

Shell
git switch r1
git rebase main
git log --oneline --graph -5
Text
Rebasing (1/1)
Successfully rebased and updated refs/heads/r1.
* d1fd453 r1
* 62609e6 m weiter
* 89048f3 x a
* 6b7f447 hallo.py hinzugefuegt
* 0dd594e README erweitert

Der Commit r1 liegt jetzt direkt hinter m weiter, ohne Merge-Commit.

MergeRebase
Historiebleibt erhalten, mit Merge-Commitlinear, Commits neu geschrieben
Bestehende Commitsunverändertbekommen neue Hashes
Sicher auf geteilten Branchesjanein

Wichtig: Rebase schreibt Commits neu. Wende es nicht auf Commits an, die du bereits an andere weitergegeben hast (gepusht und von Kolleginnen oder Kollegen geholt). Sonst divergieren die Historien, und alle Beteiligten müssen aufräumen. Auf lokalen, noch nicht geteilten Branches ist Rebase unproblematisch.

Stash: Arbeit zwischenlagern

Du hast Änderungen, die noch nicht commit-reif sind, musst aber kurz den Branch wechseln? git stash legt den Stand beiseite und stellt das Arbeitsverzeichnis wieder her:

Shell
echo "unfertig" >> README.md
git stash
git stash list
git stash pop
Text
Saved working directory and index state WIP on main: 6b7f447 hallo.py hinzugefuegt
stash@{0}: WIP on main: 6b7f447 hallo.py hinzugefuegt
On branch main
Changes not staged for commit:
	modified:   README.md
Dropped refs/stash@{0} (4c458ba3f15c5d6cbdfd5d46ca6969a06632e67e)

stash pop holt die Änderungen zurück und entfernt den Eintrag aus der Stash-Liste.

Änderungen verwerfen und Commits zurücksetzen

Zwei Befehle mit unterschiedlichen Wirkungen, die oft verwechselt werden:

git restore arbeitet auf Dateiebene. Mit --staged nimmst du eine Datei aus der Staging Area, ohne die Änderung zu verlieren. Ohne --staged wirft es die Änderung im Arbeitsverzeichnis weg, und zwar endgültig, weil sie nie committet wurde.

Shell
echo "a" > x.txt && git add x.txt && git commit -m "x a"
echo "b" > x.txt && git add x.txt
git restore --staged x.txt
git status --short
git restore x.txt
Text
 M x.txt

Nach dem ersten restore steht die Änderung als unstaged ( M) im Arbeitsverzeichnis; nach dem zweiten ist sie weg.

git reset bewegt dagegen den aktuellen Branch auf einen anderen Commit. Die Git-Dokumentation unterscheidet drei Modi, die jeweils HEAD verschieben und sich darin unterscheiden, was sonst passiert:

ModusHEADIndex (Staging Area)Arbeitsverzeichnis
--softverschobenunverändertunverändert
--mixed (Standard)verschobenauf den Zielcommit zurückgesetztunverändert
--hardverschobenzurückgesetztauf den Zielcommit zurückgesetzt

Das lässt sich nachvollziehen. Ausgangspunkt ist ein Commit „x b“, der x.txt von a auf b ändert:

Shell
git reset --soft HEAD~1
git status --short
Text
M  x.txt

Der Commit ist weg, die Änderung steht aber noch fertig vorgemerkt in der Staging Area (M links). Nach einem neuen Commit und git reset --mixed HEAD~1:

Text
Unstaged changes after reset:
M	x.txt

Jetzt ist die Änderung nicht mehr vorgemerkt ( M), aber noch im Arbeitsverzeichnis. Mit git reset --hard HEAD~1 verschwindet sie ganz:

Shell
git reset --hard HEAD~1
cat x.txt
Text
HEAD is now at 89048f3 x a
a

--hard verwirft laut Dokumentation auch uncommittete Änderungen an getrackten Dateien. Verlierst du dabei einen Commit, hilft git reflog, der die letzten Positionen von HEAD auflistet und dir die Hashes verschwundener Commits zeigt, solange Git sie noch nicht aufgeräumt hat:

Text
89048f3 HEAD@{0}: reset: moving to HEAD~1
9f380bb HEAD@{1}: commit: x b dritter

Die Dokumentation warnt zudem davor, Commits zurückzusetzen, die du schon an andere weitergegeben hast.

Mit einem Remote arbeiten

Ein Remote ist ein Repository, mit dem du Commits austauschst. Zum Üben reicht ein lokales Bare-Repository; bei GitHub oder GitLab stünde an dieser Stelle die Adresse des Projekts.

Shell
git init -q --bare -b main remote.git
cd projekt
git remote add origin ../remote.git
git push -u origin main
Text
To ../remote.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

-u verknüpft deinen lokalen main mit origin/main, sodass späteres git push und git pull ohne weitere Angaben funktionieren. Hat jemand anderes (hier: ein zweiter Klon) etwas gepusht, unterscheidest du zwei Wege:

  • git fetch lädt neue Commits aus dem Remote, ändert aber deinen Branch nicht.
  • git pull holt und integriert in einem Schritt.
Shell
git fetch
git status -sb
git pull
Text
From ../remote
   62609e6..8ce1d6f  main       -> origin/main
## main...origin/main [behind 1]
Updating 62609e6..8ce1d6f
Fast-forward
 y.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 y.txt

Der Status [behind 1] sagt, dass dein Branch einen Commit hinter dem Remote liegt. Wer vor dem Integrieren sehen will, was kommt, nutzt erst fetch und danach git log oder git diff gegen origin/main.

Wie geht es weiter?

Dein konkreter nächster Schritt: Lege ein Wegwerf-Repository an und spiele den Konfliktfall aus diesem Artikel selbst durch, mit eigenen Dateinamen. Wenn du einmal einen Konflikt bewusst gelöst hast, verliert er viel von seinem Schrecken. Danach lohnt sich der Blick in das Buch Pro Git auf git-scm.com, das Branching, Remotes und Fehlerbehebung ausführlich behandelt.

Passende Übungsprojekte findest du im Python-Einstieg, dessen Skripte du von Anfang an in ein Repository legen kannst. Falls du noch überlegst, welche Sprache du als Nächstes angehst, hilft die Entscheidungshilfe zur ersten Programmiersprache. Weitere Themen im Ressort findest du unter Programmierung.

Häufige Fragen

Was ist der Unterschied zwischen Git und GitHub?

Git ist die Versionsverwaltung auf deinem Rechner. Plattformen wie GitHub oder GitLab hosten Remote-Repositorys und bieten zusätzliche Funktionen wie Pull Requests.

Wie mache ich einen Commit rückgängig, den ich schon gepusht habe?

Verwende git revert, das einen neuen Commit erzeugt, der die Änderung aufhebt. Historie auf einem geteilten Branch umzuschreiben (reset, rebase) betrifft alle, die ihn schon geholt haben.

Quellen

  1. Pro Git: What is Git? git-scm.com (Scott Chacon, Ben Straub) · abgerufen am 28. Oktober 2026
  2. git-reset Dokumentation git-scm.com · abgerufen am 28. Oktober 2026