Kürzlich leitete ich eine einführende Git-Schulung, als mich einige Nutzer, die derzeit Mercurial verwenden, etwas Interessantes fragten. Frei formuliert:
Jan Krag
Jan has been with us since 2014 as a Continuous Improvement Agent. He is an accredited trainer for Docker and Github and is also a certified life coach. Jan has a truly diverse range of interests. He breeds oriental cats, builds and flies his own kites, collects Rubik’s cubes, and enjoys snowboarding. Wow!
Warum kann Git nicht …?
Warum kann ich nicht pullen, wenn mein Workspace ungespeicherte Änderungen enthält, obwohl Mercurial das standardmäßig kann?
Meine spontane Antwort war, dass Git den Benutzer damit lediglich vor potenziell schädlichen und vor allem irreversiblen Änderungen schützt. Standardmäßig verfolgt Git bei allen Operationen, die Dateien mit ungespeicherten Änderungen im Dateisystem verändern, einen sehr vorsichtigen Ansatz, wenn Git diese Änderungen nicht wieder rückgängig machen kann. Das wird normalerweise als Feature betrachtet.
Der bekannte „Workaround“ beziehungsweise mögliche Workflow besteht darin, Änderungen vor einem Pull zu staschen (mit git stash save) und sie danach wieder zurückzuholen (git stash pop).
Offensichtlich lässt sich das einfach mit einem Git-Alias automatisieren. Allerdings ist das nicht trivial, da git stash nicht sauber fehlschlägt, wenn keine lokalen Änderungen vorhanden sind.
Git autostash
Nach dem Training habe ich mich etwas mit aktuellen Änderungen in Git beschäftigt und dazu gelesen. Dabei stellte sich heraus, dass Git dies inzwischen tatsächlich unterstützt – Grund genug für einen kurzen Blogbeitrag.
Seit Git-Version 2.6 bietet git rebase eine Funktion beziehungsweise Option namens autostash.
Aus der Dokumentation zu git rebase:
--autostash --no-autostash Automatically create a temporary stash before the operation begins, and apply it after the operation ends. This means that you can run rebase on a dirty work-tree. However, use with care: the final stash application after a successful rebase might result in non-trivial conflicts.Der manuelle Weg
Als ersten Schritt können wir damit folgenden Prozess verwenden:
git fetch, gefolgt von: git rebase --autostash
Dadurch werden lokale Änderungen automatisch gestasht, Git erledigt „das Richtige“ (also lokale Commits auf die eingehenden Commits rebased) und holt anschließend eure Änderungen wieder zurück.
Leider gibt es keinen entsprechenden Schalter für git pull, auch nicht bei git pull --rebase. Aber keine Sorge.
Git config verwenden
Glücklicherweise und wenig überraschend bietet Git eine entsprechende Konfigurationsoption namens pull.rebase.
Da git pull --rebase intern git rebase verwendet, wird dieser Konfigurationsparameter berücksichtigt.
Das bedeutet, dass ihr Folgendes ausführen könnt:
git config rebase.autoStash trueDanach übernimmt git pull --rebase künftig automatisch das Autosquash-Verhalten.
Alles oder nichts
Wenn ihr euch vollständig auf das Rebase-Verhalten festlegen möchtet, könnt ihr es mit der Konfigurationsoption pull.rebase true kombinieren:
git config --global pull.rebase true git config --global rebase.autoStash trueDadurch verwendet jedes git pull immer den „rebase“-Prozess, kombiniert mit dem automatischen Stashen und Zurückholen lokaler Änderungen. Ziemlich praktisch …
Mögliche Konflikte
An dieser Stelle sei auf die offensichtliche und unvermeidbare Situation hingewiesen, dass die gestashten Änderungen mit eingehenden, gepullten Änderungen in Konflikt geraten können.
Die resultierende Ausgabe würde etwa so aussehen:
✗ git pull Created autostash: 094ad5c HEAD is now at d39c25c repo1 - readme First, rewinding head to replay your work on top of it... Fast-forwarded master to 6b6e1d4262fd5bc8d2b974f81222003a6c67fea6. Applying autostash resulted in conflicts. Your changes are safe in the stash. You can run "git stash pop" or "git stash drop" at any time.Im Ergebnis geht git auf Nummer sicher. Es versetzt euren Workspace in einen Konfliktzustand, den ihr wie gewohnt mit eurem bevorzugten Editor oder Merge-Tool auflösen könnt. Gleichzeitig bleibt der Stash sicher erhalten, falls ihr beispielsweise einen Hard Reset durchführen und es erneut versuchen möchtet:
➜ git stash list stash@{0}: autostashStattdessen einen Alias verwenden
Wenn ihr euch nicht auf diesen Workflow festlegen und die mehrstufigen Befehle git fetch und git rebase --autostash nicht ausführen möchtet, könnt ihr einen passenden Alias erstellen.
Ein Vorschlag wäre:
git config --global alias.up '!git fetch && git rebase --autostash FETCH_HEAD'Dann könnt ihr git up gezielt verwenden, wenn ihr mit dem Verfahren Rebase + Autostash aktualisieren möchtet.
- DevOps
- CI/CD
Subscribe to our newsletter
Related blogs