Configuration

File location

Magritte’s global configuration file lives at:

$XDG_CONFIG_HOME/magritte/config.toml

Or when XDG_CONFIG_HOME is not set:

~/.config/magritte/config.toml

Magritte automatically reloads config values when the file changes. Omitted values automatically fall back to their default, so an empty file is still a valid configuration.

See config.example.toml for a full example that you can copy and edit as you see fit.

Settings screen

Press , or choose Magritte > Settings to access the settings screen. Here you can change common options such as themes, fonts, editors, and the keymap preset.

Per-repo configuration

All configuration values can be overridden by a repo-local configuration file located at .git/magritte/config.toml. E.g.:

# .git/magritte/config.toml
dark_theme = "Nord Dark"

[fetch]
auto = true
interval_minutes = 10

If you create the .git/magritte directory outside Magritte while the app is running, restart Magritte once so it can begin watching the directory.

Top level settings

All scalar settings are top-level TOML keys. Every setting is optional.

KeyValuesDefaultMeaning
appearance"auto" / "light" / "dark"autoFollow the system or force light/dark mode.
light_themetheme nameSelenized LightTheme used in light mode.
dark_themetheme nameSelenized BlackTheme used in dark mode.
fontfont familyplatform monospaceFont for code, diffs, and aligned rows.
ui_fontfont family / "system-ui"value of fontFont for menus, headings, and labels. Use "system-ui" for the platform UI font. Unset falls back to monospace font value.
font_sizepixelssystem defaultBase UI size, clamped to 9–24.
app_iconson-of-man / pipe / golconda / magicson-of-manDock and app-switcher icon on macOS. This does not change the icon in Finder.
editorcommand or app nameOS defaultEditor used by Open File (Return). See External file editor.
commit_in_editortrue / falsefalseWrite commit messages in commit_editor instead of the in-app editor.
commit_editorcommandnoneBlocking command used as GIT_EDITOR, such as zed --wait, code --wait, or nvim. Only used when commit_in_editor is true.
commit_title_rulertrue / falsetrueHighlight summary text after column 50.
commit_body_wraptrue / falsetrueWrap commit bodies at column 72.
commit_vim_modetrue / falsefalseEnable vim emulation in the in-app commit editor. See Vim mode keys.
auto_refreshtrue / falsetrueWatch the repository and refresh settled external changes automatically.
refresh_on_focustrue / falsetrueRefresh the repository when the window regains focus.
show_tags_in_title_bartrue / falsefalseShow the nearest reachable tag in the title bar.
check_for_updatestrue / falsetrueCheck for new releases and show a quiet notification.
keymap_preset"evil" / "vanilla"evilBase keymap applied before [keymap]. The legacy value "evil-collection" is also accepted.
which_key_delay_msmilliseconds1000Time before possible continuations appear for a key prefix or Vim sequence.
published_brancheslist of refs["origin/main", "origin/master"]Branches considered shared. Magritte warns before rewriting a commit reachable from one of them. Missing refs are ignored. Use [] to disable the warning.

Theme names match the entries under Light theme and Dark theme in Settings. Magritte includes GitHub, Solarized, Selenized, Gruvbox, Catppuccin, Nord, Dracula, and tao variants.

External file editor

Set editor to a command such as code -w, zed, or subl -w. On macOS, you can also use an application name such as "Zed" or "Visual Studio Code". Leave it empty to use the system default application.

Magritte opens supported editors at the line under the cursor. Terminal editors are not supported for Open File because Magritte cannot attach them to your existing terminal session.

Status sections

Use [status] to choose which sections appear and their order:

[status]
sections = [
  "untracked", "unstaged", "staged", "stashes",
  "unpulled", "unpulled-pushremote", "unpushed", "unpushed-pushremote",
  "recent",
]
recent_count = 10

sections is an ordered list. The list order becomes the display order, and an omitted section is hidden. Omit [status] or use an empty list to restore the default order shown above. Unknown section ids produce a warning.

Section idContents
untrackedUntracked files
unstagedChanges not yet staged
stagedStaged changes
stashesSaved stashes
unpulledCommits available from the upstream
unpushedLocal commits not on the upstream
unpulled-pushremoteCommits available from the push target
unpushed-pushremoteLocal commits not on the push target
recentThe last recent_count commits
ignoredIgnored files. Hidden by default

Push-target sections are hidden when the push target and upstream are the same. All empty sections are skipped. Commit rows show labels for branches, tags, and remotes.

Actions follow the item at the cursor. Return opens a commit or stash, while Cmd+C copies its hash or reference. On a stash, a applies it, A pops it, and x in the Evil preset or k in the Vanilla preset drops it after confirmation. On a section heading, s or u acts on the whole section. Discarded untracked files are moved to the system Trash.

Set show_tags_in_title_bar = true to show the nearest reachable tag. For example, v1.0 (5) means the current commit is five commits after v1.0.

Auto-fetch

Use [fetch] to keep incoming and outgoing commit counts current. Background fetching is off by default.

[fetch]
auto = true            # default false
interval_minutes = 30  # default 30; minimum 1

Magritte runs git fetch for the current branch’s configured remote, then refreshes the status view. It skips a fetch while another operation is running. If a fetch fails, for example while you are offline, Magritte waits until the next interval and tries again.

This setting can be configured per-repo like all others, as described in per-repo configuration.

As a git mergetool

You can set git to use Magritte as your mergetool, even when you’re working outside of Magritte. Just put the following in your .gitconfig:

# .gitconfig
[merge]
    tool = magritte
[mergetool "magritte"]
    cmd = magritte --mergetool "$MERGED"
    trustExitCode = true

Run git mergetool to open each conflicted file in Magritte. Resolve the conflicts and confirm the finish prompt. Magritte returns success only when the file has no unresolved conflict markers, which lets Git stage it. Closing the window before then reports failure for that file.

Key mappings

Every key resolves to a command, and three tables cover the three places keys live: [keymap] binds keys in the views, [transient.<id>] edits the keys and options inside one command menu, and [vim.keymap] adds sequences to the commit editor’s Vim mode. The same command IDs work in the first two, and "unbound" removes an entry wherever it appears.

Global keys

Magritte offers two base keybinding presets: evil and vanilla. The evil preset follows evil-collection’s magit bindings, while vanilla follows standard Emacs and Magit bindings.

Regardless of the preset chosen, key mappings can be added, changed, or removed via the [keymap] table. Each entry maps a key to a command ID.

keymap_preset = "evil"

[keymap]
"K" = "branch-delete"   # K now deletes a branch
"x" = "unbound"         # remove the default discard binding
"E" = "commit-extend"   # E now extends the current commit

Keys are case-sensitive. For example, s and S are different bindings. Sequences are written with spaces between their keys, such as g r or ctrl-x ctrl-c, and modifiers are written as ctrl-, alt-, or cmd-. Prefixes do not need separate bindings. If you bind ". c" = "commit", . automatically becomes a prefix.

Some keys are fixed and cannot be remapped:

  • Esc and Ctrl-g cancel a job, selection, pending sequence, or popup.
  • ? opens help.

Transient menus, pickers, and the commit editor handle their own keys while they are active.

Transients menu keys

Transient menus are the command menus opened by keys such as c, b, and p. Use [transient.<id>] to add an action or Git option, move an existing entry, or remove one. The customizable menu ids:

commitbranchtag
remotestashreset
rebasemergeignore
logdiffpush
pullfetchcherry-pick
revertbisectpatch
runstatus-jump

Key mappings take the form of "key" = "command-id". An extended form with options is also available:

[transient.<id>]
# Basic form
"<key>" = "<command-id>"

# Extended form
"<key>" = {
    command = "<command-id>",   # Specify one of
    flag = "<--flag>",          # command or flag
    description = "<description>",
    before = "<other-key>",     # Specify at most
    after = "<other-key>",      # one of before,
    group = "<group name>"      # after, or group
}

Some concrete examples:

[transient.branch]
"X" = "branch-delete"        # b X deletes a branch

[transient.fetch]
"-d" = "--depth=1"           # add a Git option

[transient.commit]
"A" = "commit-amend"         # add an action to the Custom group
"-v" = { flag = "--verbose", description = "Show diff in message", after = "-s" }
"W" = { command = "user.wip", group = "Create" }
"f" = { after = "c" }        # move Fixup after Commit
"F" = { group = "Edit" }     # move Instant fixup into Edit
  • A switch contains a Git option such as "--depth=1". Switch keys begin with a dash, so -d appears under the menu’s - prefix.
  • Use before or after to place an entry beside another key. Use group to append it to a named group. Magritte creates a missing group at the end.
  • Built-in entries can be moved by specifying only before, after, or group
  • Set an entry to "unbound" to remove it. For example, "-n" = "unbound" removes commit’s --no-verify option.

Config-derived switches

Some switches start with the value from your Git configuration:

Menu optionGit configuration
commit --gpg-signcommit.gpgSign
pull --rebasepull.rebase or branch.<name>.rebase
fetch --prunefetch.prune
rebase --autosquashrebase.autoSquash

Turning one of these switches off passes its negated form, such as --no-gpg-sign. Magritte highlights the switch to show that it overrides your Git configuration.

Saved argument defaults

Press Ctrl-s in a transient menu to save its current options as the defaults for the next time you open it. Magritte asks where to save them.

Globally saved arguments are stored in transient-arguments.toml beside your global configuration file. Locally saved arguments are stored in .git/magritte/transient-arguments.toml.

The file stores Git arguments rather than menu keys, so key remapping does not affect saved defaults:

# transient-arguments.toml
commit = ["--all", "--signoff"]
log = ["-n50", "--grep=fix"]

A config-derived switch is saved only when you change it from the Git-config value. Leaving it untouched continues to follow Git configuration.

Vim mode keys

Set commit_vim_mode = true to enable Normal, Insert, and Visual modes in the in-app commit editor. It supports most standard vim movements and operations.

For full Vim behavior, you can use an external commit editor:

commit_in_editor = true
commit_editor = "nvim"

A [vim.keymap] table adds your own key sequences for the editor-level commands: commit, cancel, discard (cancel without the confirmation), reflow (the whole message), and help.

[vim.keymap]
"Q" = "cancel"
"; w" = "commit"
"cmd-g z" = "help"
"ctrl-x ctrl-c" = "commit"

Write sequences with a space between keystrokes, such as Q x, Q enter, or ctrl-x ctrl-c. A modifier chord is one keystroke: use cmd-, ctrl-, alt-, or shift-, as in cmd-enter. Mappings are case sensitive, e.g. Q means Shift-Q. Named keys include enter, tab, and escape.

For literal character-only sequences, the compact form is also accepted: Qx is equivalent to Q x. Spaces are recommended because they also work when a sequence contains named keys or modifier chords.

The first key of a custom sequence shadows its normal Vim action. For example, mapping "d x" makes d wait for x, so it no longer starts the delete operator. Choose prefixes you do not otherwise need.

Custom commands

Use [[command]] to make a git or shell command available in the : palette and the keymap.

[[command]]
id = "user.sync"
title = "Sync"
run = "git pull --rebase && git push"

[[command]]
id = "user.wip"
title = "WIP commit"
run = "git commit -m WIP"
refresh = false           # skip the status refresh afterward
confirm = false           # never ask (unset = ask when it looks destructive)

run executes through sh -c in the repository root. Shell operators, pipes, and redirection work, and the command can run any program. For example, run = "make test" is valid.

Placeholder templates

The following placeholders can be used in run and title values:

PlaceholderValue
{file}File at cursor
{commit}Commit at cursor in status, log; or a commit view
{branch}Current branch
{upstream}Current branch’s upstream, such as origin/main
{push-remote}Resolved push remote, such as origin
{default-branch}Branch selected by the remote’s HEAD, such as main
{default-remote}Remote that owns the default branch, or the push remote as a fallback

If a required value is unavailable, the command does not run. For example, a command containing {file} reports an error when no file is selected.

A title such as "Rebase onto {default-remote}/{default-branch}" displays as “Rebase onto origin/main”, for example. If a title placeholder cannot be resolved, it remains visible as written.

Bind a custom command by id, for example "X" = "user.wip", or run it by title from the command palette. Bound commands also appear in the ? menu’s Commands group.

Command output appears in a notification. Failures remain until dismissed, and long output points to the $ command log for the full text. Commands containing clean, --hard, --force, or --force-with-lease ask for confirmation. Set confirm = false on a command you trust to skip that prompt, or confirm = true to always ask — for a destructive command those words can’t reveal, such as a script.

Command ID reference

Bind any id below from [keymap], or reference it from a [transient.<id>] action. none in the default-key column means the command has no direct binding, but you can still find it in a transient menu or the : command palette.

IDdefault keycommand
commitcCommit (transient)
branchbBranch (transient)
tagtTag (transient)
remoteMRemote (transient)
stashZStash (transient)
resetOReset (transient)
rebaserRebase (transient)
mergemMerge (transient)
ignoreiIgnore (transient)
loglLog (transient)
diffdDiff (transient)
worktreeZ (vanilla) / %Browse worktrees (visit / add / branch / move / remove)
pushpPush (transient)
pullFPull (transient)
fetchfFetch (transient)
patchWPatch (transient: create patches, apply a diff, git am a mailbox)
bisectBBisect (transient; marks good/bad/skip/reset while a bisect runs)
blamenoneBlame the file at point
run!Run a Git or shell command in the repository root or selected file’s directory
git-command| (evil) / :, Q (vanilla)Run a command directly (git by default)
stagesStage the selection
unstageuUnstage the selection
stage-allSStage all tracked changes (confirms if a file is partially staged)
unstage-allUUnstage all (confirms if a file is partially staged)
discardxDiscard the selection
untrackK (vanilla) / X (evil)Untrack the file at point (git rm --cached)
open-fileReturnOpen file at point in editor
open-commit / stash-showReturnShow the commit / stash at point
commit-applyaApply the changes of the commit at point
commit-cherry-pickACherry-pick transient for the commit at point
revert-here_ (evil) / V (vanilla)Revert transient for the commit at point
revert-changes- (evil) / v (vanilla)Revert the commit at point’s changes without committing
reset-hereo (evil) / x (vanilla)Reset HEAD (mixed) to the commit at point (confirmed)
stash-row-apply / stash-row-popa / AApply / pop the stash at point
stash-row-dropx (evil) / k (vanilla)Drop the stash at point (confirmed)
commit-details=Toggle the details panel in a commit view
foldTabFold / unfold
cycle-foldsshift-tabCycle every fold through sections, everything, and folded
fold-show / fold-hide / fold-show-children / fold-hide-childrenevil z o / z c / z O / z CExplicit fold verbs (vim’s zo/zc/zO/zC)
resolve-conflictseResolve the conflicted file at point in the smerge-style view
diff-more-context+More diff context lines
diff-less-context-Fewer diff context lines
diff-default-context0Default diff context (3 lines)
refreshg r (evil) / g (vanilla)Refresh status
visualvToggle visual selection
yanky y (evil) / Ctrl-w, Cmd+CCopy the value at point
copy-buffer-revisiony b (evil)Copy the current view’s revision
show-refsy (vanilla) / y r (evil)Browse branches, remotes, tags (Return visits the tip commit; b checkout, x/k delete, R rename)
settings,Open Settings
command-log$Open the command log
closeq (and Esc)Close the current secondary screen
commit-restore-messagenoneRestore a saved message in the commit editor
fsmonitor-enablenoneEnable Git’s filesystem monitor for the repository
check-updatesnoneCheck for updates
aboutnoneShow the About panel and version
move-downjMove cursor down
move-upkMove cursor up
goto-topg gJump to top
goto-bottomGJump to bottom
next-sectionctrl-jNext file, commit, or hunk section in the status view
prev-sectionctrl-kPrevious section start (status view)
next-sibling-sectiong jNext section at the same depth
prev-sibling-sectiong kPrevious section at the same depth
section-up^Jump to the parent section
show-level-1 through show-level-41 through 4Fold to sections, files, hunks, or everything
status-jumpvanilla jJump-to-section menu (magit-status-jump)
jump-to-untracked / jump-to-unstaged / jump-to-staged / jump-to-stashes / jump-to-ignorednoneJump to a file or stash section
jump-to-unpulled-upstream / jump-to-unpulled-pushremote / jump-to-unpushed-upstream / jump-to-unpushed-pushremotenoneJump to an incoming or outgoing commit section
half-page-downctrl-dScroll down half a page
half-page-upctrl-uScroll up half a page
page-downctrl-fScroll down a page
page-upctrl-bScroll up a page
helpvanilla hOpen the ? help menu
quitctrl-x ctrl-cQuit Magritte
commit-createnoneCreate commit
commit-amendnoneAmend commit
commit-rewordnoneReword commit
commit-extendnoneExtend commit and keep its message
branch-checkoutnoneCheck out a branch or revision
branch-createnoneCreate branch
branch-create-checkoutnoneCreate and check out a branch
branch-renamenoneRename branch
branch-deletenoneDelete branch
push-pushremote / push-upstream / push-elsewhere / push-other / push-tag / push-tagsnonePush variants
pull-pushremote / pull-upstream / pull-elsewherenonePull variants
fetch-pushremote / fetch-upstream / fetch-all / fetch-elsewherenoneFetch variants
stash-push / stash-index / stash-keep-index / stash-apply / stash-pop / stash-drop / stash-branchnoneStash variants
stash-snapshot / stash-snapshot-index / stash-snapshot-worktreenoneRecord the state on the stash list without resetting anything
merge-editmsg / merge-previewnoneEdit a merge message or preview a merge
reset-branch / file-checkoutnoneReset a branch or check out a file from a revision
tag-create / tag-deletenoneTag variants
remote-add / remote-rename / remote-removenoneRemote variants
log-current / log-all / log-other / log-file / log-reflognoneLog variants
diff-dwim / diff-range / diff-unstaged / diff-staged / diff-worktree / diff-commitnoneDiff variants
cherry-pick / cherry-pick-range / cherry-applynoneCherry-pick or apply commits
revert / revert-range / revert-no-commitnoneRevert commits with or without committing

Secondary views add scoped ids that can be remapped in the same way. These include refs-*, worktree-*, flat-*, rebase-todo-*, resolve-*, log-open, and git-log-toggle-queries. Open the : palette in a view to see every command available there.