Staging changes

Choosing which of your changes the next commit will contain.

A commit does not have to contain everything you have done. Staging is how you choose: the staged changes are the next commit, and everything else waits.

That separation is worth using rather than working around. A morning’s work is rarely one change, and three commits that each do one thing are three commits you can read, revert or cherry-pick later — where one commit that does all three is a wall.

The mark at the end of the row

Every row with something to stage carries a mark at its right-hand end, saying how much of that file is in the next commit already: a hollow circle for Unstaged, a half-filled one for Partially staged, a filled tick for Staged. Point at the row and the same mark becomes the action it offers — a green plus to stage, an amber minus to unstage — and pressing it acts on that file and nothing else. It does not select the row, reload the diff, or open or close a folder.

The mark keeps its place whether it is reporting or offering, so the column stays still as you go down the list, and it belongs to the keyboard as much as to the pointer: give it the focus and it offers the same action. A file that is partly staged offers Stage remaining changes, since that is what is left to do to it; taking the whole file back out is ⌥⌘U, or Unstage in its context menu.

By file

Select a file and press ⌥⌘A. Select several — click, then shift-click or command-click — and the same command stages all of them.

Staging an untracked file makes it an addition: the mark on Scanner.swift changes from a question mark to an A, and the mark at the other end of the row becomes a tick.

There is no staged group to move into. What changes is the mark at the end of the row, and the count above the commit message that the Commit button waits on. An untracked file changes its other mark as well — Untracked becomes Added, and the file moves out of Unversioned Files into Changes with it — because Git has now recorded it.

Repository ▸ Stage All (⇧⌘A) takes the lot. Repository ▸ Unstage All (⇧⌘U) and ⌥⌘U are the exact opposites, and neither touches the file on disk — unstaging only changes what the next commit will contain.

By folder

With the list showing the folder hierarchy (View ▸ Working Copy Files ▸ Folder Hierarchy), a folder row stages, unstages or discards everything under it in one action, and shows how many files that is before you do.

Its mark aggregates what is below it: Staged only when everything under it is, Unstaged when none of it is, Partially staged for every mixture. The action follows — while anything below is unstaged the folder stages that part, and only a folder that is staged throughout offers to unstage it — so what the row is about to do is never ambiguous.

Exactly which files that is, the row shows rather than describes. Point at the folder’s own mark, or give it the keyboard focus, and every row the action would reach takes the same plus or minus, drawn faintly; a subfolder that is closed takes it too if there is a file inside it. Nothing else moves — no row is selected, no folder opens — and it clears when you look away.

Keyboard focus on the folder's mark: it shows its action — Unstage, since everything under the folder is staged by now — and marks faintly the two files that action would reach. README.md, outside the folder, keeps its own mark.

Finer than a file

You do not have to take a whole file. The diff gutter stages one hunk, or one line, or a block of lines dragged across the gutter — see staging hunks and single lines.

Everything is reachable without the mouse

Every staging action has a keyboard equivalent, a context menu entry, and a VoiceOver route to the same thing. The commands are listed in the Repository menu with their key equivalents, and in the Command Palette (⌘K) if you would rather search for them by name.