Wer modal editiert, braucht zwei verlässliche Sicherheits-Mechanismen: einen, der aus jeder Situation in den Normal-Mode zurückführt, und einen, der jeden Edit-Schritt umkehrbar macht. Vim hat beides — und das Undo-System ist eine seiner unterschätzten Stärken. Statt einer linearen Undo-Kette führt Vim einen Baum von Edits, der jede Verzweigung mitschreibt: wer rückgängig macht, dann etwas Neues editiert und später beide Versionen vergleichen will, kann das ohne Versionskontrolle direkt im Editor tun. Mit set undofile werden diese Bäume sogar über Editor-Sessions hinweg persistent — ein Vim-Undo aus letzter Woche funktioniert nach dem Neustart. Dieser Artikel deckt die universellen Notbremsen Esc und Ctrl-c, alle Undo-/Redo-Varianten, das Zeilen-Undo U, persistent-undo und die Zeit-Reise-Befehle ab.
Esc und Ctrl-c als Notbremsen
In Vim gibt es zwei Tastenkombinationen, die aus praktisch jeder Situation sicher zurückführen:
- Esc — bringt aus Insert, Visual, Replace, Select, Operator-pending und allen anderen Modi zurück in den Normal-Mode. Funktioniert auch dann, wenn ein mehrteiliger Befehl halb eingegeben ist (
dohne Motion,gohne Folgezeichen). - Ctrl-c — wirkt ähnlich, mit einem Unterschied: er löst beim Verlassen des Insert-Mode keine
InsertLeave-Autocommands aus. Vor allem nützlich, um eine laufende Operation mitten im Vorgang abzubrechen, ohne dass Save-Hooks oder Plugin-Trigger aktiviert werden.
Eine universelle Notbremse, die in keiner Situation falsch ist: zweimal Esc drücken. Wer komplett die Orientierung verloren hat — egal in welchem Modus, mit oder ohne laufenden Befehl —, kommt damit zurück in den Normal-Mode mit leerem Eingabe-Puffer.
" Versehentlich im Replace-Mode statt Insert
<Esc> " zurück in Normal-Mode
" Halb eingegebenes d, dann unsicher was als Motion folgen sollte
<Esc> " bricht den ausstehenden Operator ab
" :s/foo/bar in der Command-Line, will doch nicht
<Esc> " bricht den Ex-Befehl ab, ohne ihn auszuführen
" Plugin hat ein Popup geöffnet, das man nicht erwartet
<Esc><Esc> " schließt Popups, kehrt in Normal-Mode zurückWer eine laufende externe Shell-Operation abbrechen möchte (z. B. :!sleep 30), drückt Ctrl-c — das sendet ein SIGINT an den Subprozess. Esc würde hier nichts ausrichten, weil Vim auf das Subprozess-Ende wartet.
u und Ctrl-r — Undo und Redo
Die zwei zentralen Befehle:
| Taste | Aktion |
|---|---|
| u | undo — letzten Edit-Schritt rückgängig machen |
| Ctrl-r | redo — den durch u rückgängig gemachten Schritt wiederherstellen |
u ist im Normal-Mode der Standard-Undo, beliebig oft anwendbar. Mit einem Count gehen mehrere Schritte zurück: 5u macht fünf Schritte rückgängig. Analog für Redo: 3<C-r> stellt drei Schritte wieder her.
Eine Vim-Eigenheit: Was Vim als „einen Edit-Schritt" zählt, ist nicht ein einzelner Tastendruck. Vim gruppiert Tastendrücke zu Undo-Blöcken:
- Ein Normal-Mode-Befehl mit allen Auswirkungen = ein Block (
3dwist ein Undo-Schritt). - Eine Insert-Mode-Phase zwischen
i/a/ound<Esc>= ein Block (egal wie viel Text dazwischen). - Ein Ex-Befehl wie
:s/foo/bar/gmit allen Ersetzungen = ein Block.
Konsequenz: Wer im Insert-Mode 500 Buchstaben tippt, ohne zwischendurch Esc zu drücken, macht alle 500 Buchstaben mit einem einzigen u rückgängig. Das ist meistens gewollt — kann aber überraschen, wenn man nur „die letzten paar Zeichen" wegnehmen will. Wer feinere Undo-Granularität haben will, drückt regelmäßig zwischendrin Esc und steigt mit einem neuen i wieder in Insert ein. Eine zweite Variante:
" Im Insert-Mode bei jedem Punkt, Komma, Semikolon oder Leerzeichen
" einen neuen Undo-Punkt setzen — feinere Granularität, ohne Esc-Reflex.
inoremap . .<C-g>u
inoremap , ,<C-g>u
inoremap ; ;<C-g>u
inoremap <Space> <Space><C-g>u<C-g>u ist das Vim-Idiom für „starte einen neuen Undo-Block hier". Diese Mappings führen die normale Taste aus und setzen anschließend einen Trennpunkt.
U — die Zeilen-Undo-Eigenheit
Vim hat einen zweiten Undo-Befehl, der in dieser Form kein anderer Editor kennt: U (Großbuchstabe). Er macht alle Änderungen in der aktuellen Zeile rückgängig — vorausgesetzt, du hast die Zeile seit dem letzten Verlassen nicht verlassen.
" Zeile: "Hallo Welt"
" Cursor steht auf "H"
rWelt<Esc> " "Hallo" wird zu "Wello"
" (zwei Zeichen ersetzt, Zeile sieht jetzt aus: "Welto Welt")
cwGuten<Esc> " "Welto" zu "Guten" geändert
" (Zeile: "Guten Welt")
U " ALLE Änderungen seit dem Betreten der Zeile rückgängig
" (Zeile wieder: "Hallo Welt")U ist nicht „undo des undo" und auch nicht das Inverse von u. Es ist eine eigenständige Operation, die sich nur auf die aktuelle Zeile bezieht — und nur funktioniert, solange du die Zeile nicht zwischendurch verlassen hast.
In der Praxis ist U ein Nischen-Werkzeug. Die meisten Anwender nutzen stattdessen mehrere u-Anwendungen oder springen direkt mit g- (siehe unten) zu einem früheren Stand. Sinnvoll ist U bei einer Reihe schneller Korrekturen an einer Zeile, die man komplett verwerfen will, ohne zu zählen, wie viele Schritte das waren.
Vims Undo-Baum
Andere Editoren führen Undo als lineare Kette: jeder Edit hängt am vorigen, Redo geht in die Gegenrichtung. Sobald man nach einem undo etwas Neues macht, ist der vorherige Redo-Pfad verloren — das nennt man „Redo zerstört".
Vim macht das anders. Vim führt einen Baum: jeder neue Edit nach einem undo startet einen neuen Branch, der vorige Pfad bleibt im Hintergrund erhalten. Damit hat man im Prinzip alle jemals editierten Versionen einer Datei verfügbar — beliebig viele Verzweigungen, beliebig tief.
Zur Demonstration: vier Edits, dann ein Branch:
Stand der Datei: leer
↓ tippe "Hallo"
Version A: "Hallo"
↓ tippe " Welt"
Version B: "Hallo Welt"
↓ u (undo)
zurück auf Version A: "Hallo"
↓ tippe " Du" ← neuer Branch, B bleibt erhalten!
Version C: "Hallo Du"
Baum-Struktur:
leer → A → B
↘ C (aktuell)Klassischer Undo-Editor: nach „Hallo Du" wäre Version B („Hallo Welt") verloren. In Vim ist sie weiterhin abrufbar — über zwei Befehle:
| Taste | Bedeutung |
|---|---|
| g- | gehe zum nächst-älteren Edit (in der Zeit zurück) |
| g+ | gehe zum nächst-neueren Edit (in der Zeit vorwärts) |
g- und g+ ignorieren die Baum-Struktur und folgen der chronologischen Reihenfolge aller Edits. In unserem Beispiel führt g- von Version C zur ältesten Version, dann zu B, dann zu A.
Wer den Baum lieber visuell sehen möchte, installiert das Plugin undotree — es zeigt den vollständigen Branch-Graphen mit Zeitstempeln und ermöglicht die Auswahl per Cursor. Dieses Werkzeug ist Thema im Kapitel Erweiterte Features.
Zeit-basiertes Undo: :earlier und :later
Vim erlaubt Zeit-Reisen durch die Edit-Historie über zwei Ex-Befehle, die g-/g+ mit Zeitangaben erweitern:
| Befehl | Bedeutung |
|---|---|
:earlier 5m | gehe zu dem Stand, den die Datei vor 5 Minuten hatte |
:earlier 30s | … vor 30 Sekunden |
:earlier 2h | … vor 2 Stunden |
:earlier 1d | … vor 1 Tag (mit persistent-undo) |
:earlier 10 | … 10 Edit-Schritte zurück |
:earlier 10f | … 10 File-Writes zurück |
:later 5m | das Gegenstück: gehe 5 Minuten in die Zukunft |
:earlier 5m ist im Alltag erstaunlich nützlich: „mach das, was ich in den letzten fünf Minuten getan habe, rückgängig" — ein hochpräziser Reset ohne Zählen. Mit persistent-undo (siehe nächster Abschnitt) funktioniert das sogar über Sessions hinweg, also „mach das rückgängig, was ich gestern getan habe".
:earlier 10m " 10 Minuten zurück
:earlier 1d " einen Tag zurück (mit undofile)
:later 5m " wieder 5 Minuten vor
:earlier 50 " 50 Edit-Schritte zurückPersistent-Undo: undofile
Standardmäßig vergisst Vim den Undo-Baum, sobald man die Datei schließt. Mit der Option undofile wird er als versteckte Datei (<original>.un~ bzw. in einem konfigurierten Verzeichnis) persistent gespeichert und beim nächsten Öffnen wiederhergestellt:
" Persistent-Undo aktivieren
set undofile
" Empfohlen: undo-Dateien zentral im ~/.vim/undo/-Verzeichnis ablegen,
" statt überall als <name>.un~ neben den Originalen. Sauberer.
set undodir=~/.vim/undo//
" Das Verzeichnis muss existieren — Vim legt es NICHT automatisch an.
" Einmalig: mkdir -p ~/.vim/undoDas doppelte Slash am Ende von undodir ist Absicht: damit kodiert Vim den vollen Dateipfad in den Namen der Undo-Datei. Ohne den Doppel-Slash würden zwei Dateien mit dem gleichen Basisnamen (z. B. index.html in zwei verschiedenen Projekten) sich gegenseitig die Undo-Historie überschreiben.
Mit aktiviertem undofile gilt:
- Vim merkt sich pro Datei den vollen Undo-Baum dauerhaft.
:earlier 1dspringt zum Stand vor einem Tag — auch nach Neustart.g-undg+funktionieren über Sessions hinweg.- Branches bleiben erhalten — gestern verworfene Versionen sind heute weiter abrufbar.
Der Speicher-Overhead ist gering: typische .un~-Dateien sind wenige Kilobyte groß. Sicherheits-Hinweis: Undo-Dateien enthalten Klartext-Versionen alter Datei-Stände. Wer in einem Repo mit sensiblen Daten arbeitet, sollte sicherstellen, dass ~/.vim/undo/ nicht versehentlich in ein Backup oder einen Cloud-Sync rutscht.
Was Vim NICHT undoen kann
Es gibt drei Klassen von Operationen, die außerhalb des Undo-Systems liegen:
- Schreib-Operationen mit
:w— Vim speichert die Datei, aber das Schreiben selbst ist kein Undo-Schritt. Wer eine versehentliche Speicherung rückgängig machen will, holt sich den älteren Inhalt peruzurück und speichert erneut. - Externe Datei-Änderungen — wenn ein anderes Programm die Datei modifiziert (Git-Pull, externer Editor, Build-Tool), kennt Vim diese Änderungen nicht. Mit
:e!lädt Vim die Datei neu — auch das ist kein Undo, sondern ein Reset. - Quittieren mit
:q!— die ungespeicherten Änderungen sind danach weg. Vim wirft den Buffer raus, der Undo-Baum geht verloren (außer er ist persistent gespeichert via undofile und die Datei wurde zwischendurch mindestens einmal gespeichert).
Eine Praxis-Empfehlung: nach komplexen Refactorings öfter :w drücken. Jeder Save ist ein Sicherheitsnetz — und mit undofile ist jeder Save zusätzlich ein dauerhafter Wiederherstellungspunkt.
Praxis-Konfiguration
Ein vollständiges, robustes Undo-Setup für die ~/.vimrc:
" --- Undo-System ---
" Mehr Undo-Levels (Default ist 1000, was meist reicht).
" Mehr kostet ein wenig RAM, ist aber bei großen Refactorings nützlich.
set undolevels=10000
" Persistent-Undo: Baum bleibt über Sessions hinweg erhalten.
set undofile
" Zentrales Verzeichnis statt .un~-Dateien neben den Originalen.
" Doppel-Slash verhindert Kollisionen gleichnamiger Dateien.
set undodir=~/.vim/undo//
" Feinere Undo-Granularität im Insert-Mode an Satz-Trenner-Zeichen.
inoremap . .<C-g>u
inoremap , ,<C-g>u
inoremap ; ;<C-g>u
inoremap ! !<C-g>u
inoremap ? ?<C-g>u
inoremap <CR> <CR><C-g>uDazu einmalig in der Shell:
mkdir -p ~/.vim/undoMit dieser Konfiguration hast du Vim-Undo auf einem Niveau, das jeder andere Editor erst durch Versionskontrolle erreicht — und das in jeder Vim-Installation seit Version 7.3 (2010).
Besonderheiten
`Ctrl-c` ist nicht immer dasselbe wie `Esc`
Aus dem Insert-Mode bringen beide in den Normal-Mode zurück. Der Unterschied: Esc löst Autocommands für das InsertLeave-Event aus, Ctrl-c nicht. Plugins, die auf InsertLeave reagieren (Save-on-leave, Linter-Trigger, Diagnose-Refresh), werden bei Ctrl-c umgangen — meistens irrelevant, manchmal genau das, was man will.
`5u` und fünf Mal `u` sind identisch
Vims Count-Präfix gilt auch für u. 5u macht fünf Edit-Schritte rückgängig — exakt wie fünfmal u hintereinander. Bei größeren Reset-Operationen ist der Count die effizientere Schreibweise.
Insert-Mode zählt als EIN Undo-Schritt — ohne Aufteilung
Wer von i bis <Esc> 500 Zeichen tippt, hat im Default-Setup einen einzigen Undo-Schritt. u macht alle 500 auf einmal rückgängig. Die <C-g>u-Mappings aus der Konfiguration oben unterteilen diesen Block an Satzzeichen und Leerzeichen — granularer, ohne den Tippfluss zu unterbrechen.
`U` braucht eine unverlassene Zeile
Die Zeilen-Undo-Eigenheit U funktioniert nur, solange der Cursor seit dem letzten Edit-Anfang in derselben Zeile geblieben ist. Sobald man die Zeile verlässt (mit j/k, Suche, Sprung), ist U für diesen Edit-Block deaktiviert.
`:earlier 1d` braucht persistent-undo
Ohne set undofile hat Vim keinen Edit-Verlauf, der älter ist als die aktuelle Session. :earlier 1d geht dann nur soweit, wie die heutige Session reicht. Mit aktiviertem undofile sind Zeit-Sprünge über Tage und Wochen möglich.
undotree-Plugin als visueller Browser
mbbill/undotree zeigt den Vim-Undo-Baum als grafischen Buffer mit Verzweigungen, Zeitstempeln und Differenz-Vorschau. Wer den Baum-Aspekt von Vims Undo wirklich nutzen will, kommt um das Plugin schwer herum — ohne es bleibt der Baum unsichtbar, mit ihm ist es eine echte Zeit-Reise-Konsole.
Weiterführende Ressourcen
Externe Quellen
- Vim Help: undo.txt — vollständige Undo-Referenz mit Baum-Konzept.
- Vim Help: undofile — Persistent-Undo-Option.
- Vim Help: :earlier — Zeit-basierte Sprünge.
- Vim Help: i_CTRL-G_u — Undo-Block-Trenner im Insert-Mode.
- mbbill/undotree — visueller Browser für Vims Undo-Baum.