Repository navigation
How Reverting a Change Works
This chapter explains the Revert button on each change of the Changes diff and the click on a change bar in the file editor. The user side is in Revert a Change. The diff itself is in How Diffs Work and How the inline diff works; the editor and its change bars are in How the Editor Works.
Staging one change was already one click, but throwing one away meant selecting its lines and running Discard Selected Lines, or editing by hand. A revert action on every change is common, and users expect it in both the diff and the editor.
The two places revert against different versions, because each shows a different comparison: the Changes diff compares the index with the working tree, and the editor's bars compare the editor's text with HEAD. So they take two paths.
flowchart TD
A[Revert button on a diff change] --> B[revertChange.ts: the change's old and new lines]
B --> C[DiffView: onLines discard, wholeChange]
C --> D[changesSelection.applyLines: confirm Revert Change]
D --> E[apply_selected_lines: version check, reverse patch on the work tree]
E --> F[Toast with Undo: restore_discarded_lines]
G[Click on an editor change bar] --> H[changeGutter onBarClick]
H --> I[FileGitInfo.revertChange: confirm]
I --> J[readHeadFile, diffLines against the text now]
J --> K[revertLines.ts: changeAtLine, revertEdit]
K --> L[One editor transaction, undoable]
Side by side, DiffFrame takes onrevert and revertTitle and passes them to MergeConnector, which draws a button with the discard icon on each band, on the far side of the Stage arrow (where the merge tool's Ignore button goes). DiffEditors.changeLines(index) turns the MergeView chunk into line ranges with chunkSelection. A chunk's to is one past its last line break and may point past the end of the text, so chunkLines clamps it.
Inline, inlineView.ts adds a second button after Stage in the control gutter. Each block already carries its backend hunk, so hunkSelection reads the lines straight from it.
Both end in onLines("discard", lines, true), the Discard Selected Lines path in changesSelection.applyLines. The backend checks the diff's version, so a file that changed since the diff was shown is refused, and the Undo in the toast applies the saved patch again. wholeChange only changes the confirm's words to Revert Change. Revert is offered only in unstaged mode: a staged diff has Unstage, which already moves a change back.
These diffs are read-only, so DiffView takes onRevert (and onApply for a commit or a branch compare) instead of line actions: the same buttons side by side, and inline Apply then Revert in the control gutter. One diff view explains how GitDiffView picks the revisions; changeWorkTree (diff/diffActions.ts) confirms a Revert and calls apply_revision_lines, which patches the work tree file only, after a local history snapshot, and returns the patch for Undo.
changeGutter takes an optional onBarClick. Its mousedown handler looks up the gutter's own markers on the clicked line, so a click beside an unchanged line or on a conflict's bar does nothing. FileGitInfo.revertChange then:
- Confirms with a danger dialog.
- Reads HEAD's file with
readHeadFile(LF text, the path HEAD has for a staged rename). - Diffs it with the editor's text as it is now (
diffLines), so edits made while the dialog was open count. - Picks the change with
changeAtLine: the hunk holding the line, or the deletion whose wedge sits on it (at the end of the text, the last line). - Dispatches the edit from
revertEditas one transaction withuserEvent: "input.revert".
| File | What it does |
|---|---|
ui/web/src/lib/components/MergeConnector.svelte, DiffFrame.svelte
|
The Revert button on each band (UI library) |
src/lib/diff/revertChange.ts |
A chunk's or a hunk's lines as a LineSelection
|
src/lib/diff/inlineView.ts |
The inline Revert button after Stage |
src/lib/diff/DiffView.svelte, diffEditors.svelte.ts
|
Wiring the buttons to onLines
|
src/lib/views/changes/selection.svelte.ts |
applyLines, the confirm and the Undo toast |
src/lib/diff/diffActions.ts, src-tauri/src/commands/revision_lines.rs
|
Revert and Apply between two revisions, or a revision and the work tree |
src/lib/editor/scrollMarkers.ts |
changeGutter and its bar click |
src/lib/editor/revertLines.ts |
changeAtLine and revertEdit
|
src/lib/views/files/fileGitInfo.ts |
revertChange for the editor |
Reuse Discard Selected Lines in the diff. It already checks the version, keeps the patch for Undo and serializes with staging. Copying a chunk in the editors (as Stage does) would need a write of the work tree file, which the diff never does.
Edit the buffer in the editor, not the file. The editor may hold unsaved text the disk does not have. An editor transaction keeps undo, auto save and the dirty state working as for typing.
Diff again on click. The bars come from the backend and may be up to 200 ms old. Diffing HEAD with the text of that moment means the revert always matches what is there. Past MAX_EDITS the diff is one big change, so the whole range reverts.
Always confirm. Reverting loses work, and a click on a 5 pixel bar is easy to make by mistake.
-
src/lib/diff/revertChange.test.ts: a chunk's and a hunk's lines, empty sides, a last line without a break. -
src/lib/editor/revertLines.test.ts: the change on a clicked line, and reverting changed, added and deleted lines at the start, middle and end. - The backend paths are covered by the
apply_selected_linestests incommands/lines.rsand theapply_revision_linestests incommands/revision_lines.rs: only the picked change goes back or comes in, Undo reverses it, and a staged version stays in the index.
The buttons, the hand pointer and the confirms need a check in the app. See Testing.
The Changes tab had no Revert button.
- The issue: the Changes tab (status bar > N changes) showed changes with no way to revert one, side by side or inline.
- Why it happened: Revert came from Discard Selected Lines, which works on the index against the work tree, and the tab compares with HEAD in a read-only diff.
-
The fix and why we chose it: a backend action reverts against HEAD, with the same checks, local history snapshot and Undo patch as Discard, and
DiffView'sonRevertshows the usual buttons in a read-only diff. It becameapply_revision_lineswhen commits got Revert and Apply.
Commit diffs had no Revert, Apply or three columns.
- The issue: the History panel and commit tabs showed a commit's diff with no buttons, and only merge commits could show three columns, while the Changes diff had both.
-
Why it happened: every place chose its own panes and buttons around
DiffViewandThreePaneDiff, so features added in one place never reached the others. -
The fix and why we chose it: one
GitDiffViewfor every place (see One diff view), with aDiffSourcethat decides the panes and buttons, so a new button reaches every diff at once.
- Update this page when the Revert buttons move, when
applyLinesorchangeGutterchange, or when the editor's bars compare with something other than HEAD.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode