Git (Magit)
Macros includes a Magit-style git porcelain: an interactive status buffer where you stage hunks, write commits, branch, push, pull, stash, and read diffs. The porcelain — the sectioned view, the transient popups, the keymaps — is written entirely in Scheme on the editor's special-buffer and transient primitives. Underneath, git data comes from two sources: pure-Rust gitoxide (gix) primitives for metadata reads (the HEAD commit, recent log, branches, tags, remotes, repo state, and blame) with no subprocess at all, falling back to shelling out (call-process to the git binary) for the working-tree scan, diffs, and mutating actions like stage / commit / push. The status buffer is a read-only faced buffer that's rebuilt on every refresh.
Opening the status buffer
Run magit-status with C-x g (or M-x magit-status). You get the familiar sectioned view: untracked, unstaged, staged, and recent commits, with colored diffs and per-file status labels.
Status buffer keys
Navigation & folding
| Key | Action |
|---|---|
| n / p | move line by line |
| M-n / M-p | next / previous section |
| Tab | fold / unfold the section at point |
| S-Tab | cycle all sections |
| Enter | visit the file at point |
| g | refresh |
| q | close |
Staging
| Key | Action |
|---|---|
| s / S | stage the item / stage all |
| u / U | unstage the item / unstage all |
| k | discard the change at point |
The "item" follows point: a hunk, a file, a selected region of files/lines — or, on a section header (s on Untracked files / Unstaged changes, u on Staged changes), the whole section.
Transient popups
Each of these opens a transient menu (a popup of further keys), mirroring Magit:
| Key | Popup |
|---|---|
| c | commit |
| b | branch |
| P / F | push / pull |
| f | fetch |
| l | log |
| z | stash |
| m | merge |
| r | rebase |
| t | tag |
| X | reset |
| M | remote |
| B | blame |
| ? | dispatch (all commands) |
Other handy keys: i add to .gitignore, y copy a ref, $ show the git process output, H toggle history.
Committing
Press c to open the commit popup, then start a commit. The message buffer is in git-commit-mode:
| Key | Action |
|---|---|
| C-c C-c | confirm and create the commit |
| C-c C-k | cancel |
Log
The log popup (l) opens a magit-log-mode buffer. From there: Enter shows a commit, A cherry-picks, v reverts, q closes.
Inline blame
Annotate the commit that last touched each line as faded virtual text at the end of the line (GitLens-style). This works in any file buffer — you don't need the status buffer open:
| Key | Action |
|---|---|
| C-x v b | toggle blame on every line |
| C-x v B | toggle blame on the current line only (follows the cursor) |
| C-x v Enter | show the commit that last touched this line |
| C-x v y | copy that commit's hash |
Each annotation shows the short hash, author, a humanized date ("3 weeks ago"), and the commit summary. Full-file mode (C-x v b) collapses runs of lines from the same commit to a single annotation and tints by age — recent edits pop, ancient code recedes. Current-line mode (C-x v B) shows one quiet grey annotation that re-places itself as point moves. All four commands are also available via M-x.
The status buffer's B is a separate view: it opens a full git blame of the file at point in a read-only buffer.
Customizing
magit-status is on C-x g by default. Rebind it, or any key inside the status buffer (the "magit-status" map), from your init.scm:
;; Rebind the global entry point:
(define-key "fundamental" "ctrl-x g" 'magit-status)
;; Rebind keys inside the status buffer — e.g. make `C` open the commit popup:
(define-key "magit-status" "shift-c" 'magit-commit-popup)
How it's built
Because Magit here is plain Scheme over a few primitives — gix-* (read metadata, log, and blame straight from gitoxide, no subprocess), call-process (run the git binary for the working-tree scan, diffs, and mutating actions), render-buffer (draw a faced read-only buffer), buffer-line / goto-line (find and restore the section at point), and transient (the popups) — you can read it, extend it, add your own popups, or change any binding. Folding works by regeneration: a refresh simply rebuilds the buffer text. See Scripting with Steel.