User guide / Git

Changed files, staging, and committing

Development reference · View source

Space g g opens the changed-file list: files grouped by whether a commit would take them, one per line. A selection over several rows is a selection of files, and one key acts on all of them.

# main ↑1 · 2 staged · 1 not staged · 1 untracked · +105 -28

Staged
  M  +82  -12  src/app.rs
  A  +20   -0  src/git/stats.rs

Not staged
  M   +3  -16  README.md

Untracked
  ?    ·    ·  logo.png
KeyAction in the list
Tab s / Tab uStage / unstage every file the selection covers
Tab SStage every unstaged and untracked file in the list
EnterShow this row’s diff
Tab dCompare this row’s complete versions in a temporary split
Tab oOpen the file on this line
Tab DDiscard the selected files’ changes
Tab cWrite a message and commit what is staged
Tab iReview everything staged for the next commit
Tab p / Tab PPull / push the branch this working tree is on
Space g rRe-read everything from Git

Reading the changed-file list

The first row names the branch, its drift from upstream, and how many files are in each section. It counts sections rather than per-file states, so it never calls a file “modified” above a heading that calls it staged. The status line’s compact ~1 answers a different question: what changed, rather than where it sits.

Line counts show what each change costs, added then removed, in one aligned column; the first row totals them.

  • They use the theme’s change_added and change_removed, the same colours as the gutter and diffs. Built-in themes use green and red; custom themes can change either.
  • They are Git’s own --numstat counts of the same two trees the row comes from. A file staged and then edited again is counted once on each of its rows, and the total is the sum of what is shown.
  • An untracked file counts every line as added.
  • A change that cannot be counted — a binary file, an untracked symlink, a file over a megabyte, or a whole untracked directory Git collapsed into one row — shows · in both columns and is left out of the total. A list with no countable rows omits the columns.
  • Counts are read only while the list is open.

A file in two sections (staged, then edited again) is not a duplicate: those are two changes, staged separately. Enter on a staged row shows what a commit would take; on an unstaged row, what it would not. A selection covering both acts on the file once.

After staging, the caret follows the file into its new section, so Tab u undoes what you just did.

Staging

  • Tab s records each file as written on disk. When a buffer has unsaved changes, an INFO notification says so.
  • Staging moves the gutter’s base, so marks for staged lines disappear at once.
  • For a rename, the displayed destination is what you open or diff, while staging and unstaging act on both paths, so a move is never split across the index.
  • The changed-file list reads files on disk, not buffers — the one place the gutter and the diff views can disagree. The diff header says so when a buffer has unsaved changes.

Hunks. In a per-file diff, Tab s stages the exact hunk under the cursor and Tab u unstages the exact staged hunk. The request carries the hunk bytes plus repository, HEAD, index, file, and live-buffer preconditions; Git checks the patch, and any stale precondition changes nothing.

Lines. :git-stage-lines stages a deliberately narrow slice from a saved, clean source buffer: one contiguous selection containing every added or modified new line in one hunk.

  • Refused: dirty buffers, deletion-only choices, multiple or partial hunks, binary files, conflicts, renames, and untracked files.
  • A refused partial action never becomes whole-file staging.
  • Use Lazygit for finer patch surgery or advanced history work. Native merge review and conflict resolution are described below.

Committing

Tab c opens a commit message buffer with the template Git would give an external editor: an empty first line, then commented instructions and the files to be recorded.

ToDo
CommitWrite the buffer: :w or :wq (:wq does not exit Runyte here)
Cancel an unchanged message:c
Cancel an edited message:c!
  • The index is refreshed first, so staging done outside the editor is included.
  • A commit takes the index — exactly what the Staged section shows.
  • Comment lines are not part of the message, so a message line cannot start with #.
  • Cancelling commits nothing and leaves the index as it was.
  • A refused commit (an unset identity, a rejecting hook) keeps the message in the buffer to fix and retry.
  • Afterwards the pane returns to where you started.
  • Hooks run in the background commit, so a slow pre-commit leaves the editor responsive. A signing key that wants a terminal prompt fails rather than asking.

Discarding

Tab D restores the selected files to HEAD, throwing away both staged and unstaged changes.

  • It is the only Git action here that cannot be undone: the content was never a commit, so no reflog brings it back. It asks first and names what it will take.
  • A file with unwritten buffer edits is refused, so Git never overwrites text that exists only in the editor. Clean buffers reload afterwards.
  • Discarding a staged addition removes its clean open buffer with the file. Discarding a rename restores the original path and removes the destination.
  • Untracked files are refused. Discarding one could only mean deleting it, which Git keeps behind clean and Runyte keeps in the explorer, where deletion is a confirmed plan that goes to the trash.