git stash bewirkt, dass Änderungen an deiner Arbeitskopie zeitweise zurückgestellt (oder auch gestasht) werden, damit du dich anderen Aufgaben widmen und die Änderungen später aufspielen kannst. Stashen kann praktisch sein, wenn du mitten in einer Codeänderung steckst, zum Committen aber noch nicht bereit bist und schnell an etwas ganz Anderem weiterarbeiten musst.

Anlegen eines Stash deiner Arbeit

Der Befehl git stash speichert deine nicht committeten Änderungen (egal, ob sie sich in der Staging-Umgebung befinden oder nicht) zur späteren Verwendung und setzt dann deine Arbeitskopie zurück. Ein Beispiel:

$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
nothing to commit, working tree clean

Nun kannst du Änderungen vornehmen, neue Commits erstellen, Branches wechseln und alle anderen Git-Funktionen nutzen. Wenn du schließlich bereit bist, wendest du deinen Stash wieder an.

Beachte, dass das in deinem Git-Repository ein lokaler Stash ist und deine Stashes beim Pushen nicht an den Server übermittelt werden.

Wiederanwenden deiner im Stash aufbewahrten Änderungen

Zuvor aufbewahrte Änderungen kannst du mit git stash pop erneut anwenden:

$ git status
On branch master
nothing to commit, working tree clean
$ git stash pop
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Wenn du deinen Stash poppst, werden die Änderungen aus deinem Stash entfernt und erneut auf deine Arbeitskopie angewendet.

Du kannst aber auch die Änderungen erneut auf deine Arbeitskopie anwenden und sie weiterhin in deinem Stash aufbewahren. Hierfür gibst du git stash apply ein:

$ git stash apply
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html

Das ist nützlich, wenn du dieselben gestashten Änderungen auf mehrere Branches anwenden willst.

Nachdem du nun die Grundlagen zum Stashing kennst, solltest du dir noch über einen kleinen Nachteil von git stash bewusst werden: In den Standardeinstellungen bewahrt Git keine Änderungen an u nicht verfolgten oder ignorierten Dateien im Stash auf.

Aufnehmen von unverfolgten oder ignorierten Dateien in den Stash

In den Standardeinstellungen wird beim Ausführen von git stash Folgendes in den Stash verschoben:

  • Änderungen, die deinem Index hinzugefügt wurden (in der Staging-Umgebung)
  • Änderungen an Dateien, die aktuell von Git verfolgt werden (noch nicht in der Staging-Umgebung)

Nicht in den Stash verschoben wird Folgendes:

  • Neue Dateien in deiner Arbeitskopie, die sich noch nicht in der Staging-Umgebung befinden
  • Dateien, die ignoriert werden

Wenn wir also dem obigen Beispiel eine dritte Datei hinzufügen, diese aber nicht in die Staging-Umgebung verschieben (d. h. wir führen git add nicht aus), wird git stash die Datei nicht dem Stash hinzufügen.

$ script.js
$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
Untracked files:
script.js

Durch Hinzufügen der Option -u (oder --include-untracked) werden mit git stash auch deine nicht verfolgten Daten gestasht:

$ git status
On branch master
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash -u
Saved working directory and index state WIP on master: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch master
nothing to commit, working tree clean

Die Änderungen ignorierter Dateien können miteinbezogen werden, indem du die Option -a (oder --all) an den Befehl git stash anfügst.

Git Stash – Optionen

Verwalten mehrerer Stashes

Du musst dich nicht auf einen einzigen Stash beschränken. Du kannst git stash mehrmals ausführen, um mehrere Stashes zu erstellen und diese anschließend mit git stash list ansehen. Standardmäßig werden Stashes an der Spitze des Branch und Commits, von dem du den Stash erstellt hast, einfach als "WIP", also Work in Progress, identifiziert. Nach einer Weile kann es schwierig werden, sich daran zu erinnern, was in dem jeweiligen Stash enthalten ist:

$ git stash list
stash@{0}: WIP on master: 5002d47 our new homepage
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

Zur Bereitstellung von mehr Kontextinformationen ist es sinnvoll, deine Stashes mithilfe von git stash save "Nachricht"mit einer Beschreibung zu versehen:

$ git stash save "add style to our site"
Saved working directory and index state On master: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On master: add style to our site
stash@{1}: WIP on master: 5002d47 our new homepage
stash@{2}: WIP on master: 5002d47 our new homepage

Standardmäßig wird mit git stash pop der zuletzt erstellte Stash erneut angewendet: stash@{0}

Du kannst aber wählen, welcher Stash erneut angewendet werden soll, indem du dessen Kennung als letztes Argument anfügst, z. B.:

$ git stash pop stash@{2}

Ansehen von Stash-Diffs

Mit git stash show wird eine Zusammenfassung für einen Stash angezeigt:

$ git stash show
index.html | 1 +
style.css | 3 +++
2 files changed, 4 insertions(+)

Du kannst aber auch die Option -p (oder --patch) angeben, um den vollständigen Diff eines Stashes anzuzeigen:

$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>

Partielle Stashes

Du kannst auch nur eine einzige Datei, mehrere Dateien oder auch beliebige Änderungen aus Dateien stashen. Wenn du die Option -p (oder --patch) für git stash angibst, wird der Befehl für jeden geänderten "Hunk" in deiner Arbeitskopie wiederholt und du musst angeben, ob du ihn stashen willst:

$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n
Git Stash -p

Wenn du auf das ? klickst, erhältst du eine vollständige Liste der Hunk-Befehle. Diese hier sind besonders nützlich:

Befehl Description
/ Suche nach einem Hunk mit einem regulären Ausdruck
? Hilfe
n Diesen Hunk nicht in den Stash verschieben
q beenden (von Englisch "quit"): Alle bereits ausgewählten Hunks werden gestasht.
s Diesen Hunk in kleinere Hunks aufteilen
y Diesen Hunk in den Stash verschieben

Es gibt zwar keinen ausdrücklichen Befehl zum "Abbrechen", aber mit Strg-C (SIGINT) kannst du den Stash-Prozess abbrechen.

Erstellen eines Branch von deinem Stash

Wenn die Änderungen an deinem Branch von den Änderungen in deinem Stash abweichen, kann es zu Konflikten kommen, wenn du deinen Stash anwendest. Stattdessen kannst du mit git stash branch einen neuen Branch erstellen, auf den du die Änderungen aus deinem Stash anwendest:

$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)

Hiermit werden ein neuer Branch auf Basis des Commits, auf dem du deinen Stash erstellt hast, ausgecheckt und dann die aufbewahrten Änderungen eingefügt.

Bereinigen des Stash

Wenn du einen bestimmten Stash nicht mehr benötigst, kannst du ihn mit git stash drop löschen:

$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)

Oder du löschst alle deine Stashes mit:

$ git stash clear

Funktionsweise von git stash

If you just wanted to know how to use git stash, you can stop reading here. But if you're curious about how Git (and git stash) works under the hood, read on!

Stashes sind übrigens in deinem Repository als Commit kodiert. Die spezielle Referenz .git/refs/stash verweist auf deinen zuletzt erstellten Stash, früher erstellte Stashes werden über das Reflog der stash-Referenz referenziert. Deshalb referenzierst du Stashes über stash@{n}: Du referenzierst eigentlich den n-ten Reflog-Eintrag für den stash. Da ein Stash einfach ein Commit ist, kannst du ihn mit git log untersuchen:

$ git log --oneline --graph stash@{0}
*-. 953ddde WIP on master: 5002d47 our new homepage
|\ \
| | * 24b35a1 untracked files on master: 5002d47 our new homepage
| * 7023dd4 index on master: 5002d47 our new homepage
|/
* 5002d47 our new homepage

Je nachdem, was du stashst, werden in einem einzigen git stash-Vorgang entweder zwei oder drei neue Commits durchgeführt. Im Beispiel oben gibt es folgende Commits:

  • stash@{0}, ein neuer Commit zum Speichern der verfolgten Dateien, die sich beim Ausführen von git stash in deiner Arbeitskopie befanden
  • Der erste übergeordnete Commit von stash@{0}, d. h. der vorher bereits bestehende Commit, der sich am HEAD befand, als du git stash ausgeführt hast
  • Der zweite Parent von stash@{0}, ein neuer Commit, der den Index von dem Zeitpunkt repräsentiert, als du git stash ausgeführt hast
  • Der dritte Parent von stash@{0}, ein neuer Commit, der die unverfolgten Dateien repräsentiert, die sich in deiner Arbeitskopie befanden, als du git stash ausgeführt hast. Der dritte Parent wird nur unter folgenden Voraussetzungen erstellt:
    • Deine Arbeitskopie enthält unverfolgte Dateien und
    • du hast die Option --include-untracked oder --all an git stash angefügt.

So kodiert git stash deinen Arbeitsbaum und deinen Index in Commits um:

  • Vor dem Stashing kann dein Arbeitsbaum Änderungen an verfolgten, nicht verfolgten und ignorierten Dateien enthalten. Einige dieser Änderungen befinden sich ggf. auch im Index (in der Staging-Umgebung).

    Vor dem Erstellen eines Stash
  • Bei der Verwendung von git stash werden alle Änderungen an verfolgten Dateien als zwei neue Commits in deinem DAG (gerichteten azyklischen Graphen) kodiert: ein Commit für die Änderungen, die sich nicht in der Staging-Umgebung befinden und ein Commit, für die Änderungen, die sich in der Staging-Umgebung (Index) befinden. Die spezielle Referenz refs/stash wird aktualisiert, um auf diese Commits zu verweisen.

    git stash
  • Mit der Option --include-untracked kannst du auch alle Änderungen an nicht verfolgten Dateien in einen weiteren Commit umkodieren.

    Git stash --include-untracked
  • Die Option --all schließt Änderungen an ignorierten Dateien genauso wie Änderungen an unverfolgten Dateien im selben Commit ein.

    Git Stash --all

     

Wenn du git stash pop ausführst, werden die Änderungen aus den obigen Commits zur Aktualisierung deiner Arbeitskopie und deines Index verwendet und der hervorgeholte Commit wird aus dem Stash-Reflog entfernt. Beachte, dass die hervorgeholten Commits nicht sofort gelöscht werden, sondern zu Kandidaten für die nächste Bereinigung werden.

Du möchtest mit Git arbeiten?

Sieh dir dieses interaktive Tutorial an.

Jetzt loslegen