Emacs Magit: The Git Interface That Will Change How You Work

Magit is not a thin wrapper around Git. It is a complete reimagining of the Git workflow inside a text editor, and it is almost universally cited as the single Emacs package that converts sceptics. After one week with Magit, most developers find the command-line Git UX intolerable by comparison.

This guide covers installation, the core status/staging workflow, branching, interactive rebasing, stashing, bisect, and a set of keybindings worth committing to muscle memory. It assumes Emacs 29+ and Git 2.40+.

Installation

;; With use-package + straight.el (recommended)
(use-package magit
  :straight t
  :bind (("C-x g"   . magit-status)
         ("C-x M-g" . magit-dispatch))
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
  (magit-save-repository-buffers 'dontask))

Or with the built-in package.el:

M-x package-install RET magit RET

After installation, open any file inside a Git repository and press C-x g to open the status buffer.

The Status Buffer: Your Command Centre

The Magit status buffer replaces git status, git diff, and most of your daily git add calls. The layout:

Head:     main Refactor user service
Merge:    origin/main origin/main
Push:     origin/main

Untracked files (1)
  src/NewFile.php

Unstaged changes (2)
  modified  src/UserService.php
  modified  src/UserRepository.php

Staged changes (1)
  modified  src/Config.php

Key bindings inside the status buffer:

KeyAction
TABExpand/collapse section or file diff inline
sStage file or hunk at point
uUnstage file or hunk at point
SStage all unstaged changes
UUnstage all staged changes
kDiscard change at point
gRefresh the status buffer
qQuit the buffer

Hunk-Level Staging: Magit's Killer Feature

Move point to an unstaged file and press TAB to expand the diff inline. Navigate into a hunk and press s to stage just that hunk. Press C-SPC to set a region within a hunk and s to stage only those lines — partial hunk staging that git add -p makes painful.

;; Useful additions for diff navigation
(use-package magit
  :bind (:map magit-hunk-section-map
              ("RET" . magit-diff-visit-file-worktree)))

Committing

Press c in the status buffer to open the commit popup (magit-commit). Common options:

Key sequenceAction
c cCreate a new commit (opens commit message buffer)
c aAmend the last commit
c eExtend the last commit (amend without editing message)
c fCreate a fixup commit targeting another commit
c sCreate a squash commit targeting another commit
c wReword the last commit message

Inside the commit message buffer, C-c C-c confirms, C-c C-k aborts. Magit automatically formats the buffer with a ruler at column 72, enforces a blank line after the subject, and shows the staged diff below for reference.

Branching and Checkout

Press b for the branch popup:

Key sequenceAction
b bCheckout a branch
b cCreate and checkout a new branch
b lList all branches
b dDelete a branch
b rRename a branch

Magit offers completion for branch names using your configured completing-read framework (Vertico, Ivy, etc.), so switching branches is a fuzzy-search away.

Fetching, Pulling, Pushing

Press f for fetch, F for pull, P for push. The popups show the active remote and branch, so a simple f u fetches upstream and P u pushes to upstream. Force-push is available as P -f u — the -f flag is a transient argument, visible in the popup UI, which makes force-pushes deliberate rather than accidental.

Interactive Rebase

Interactive rebase is where Magit genuinely surpasses the command line. Press r for the rebase popup:

Key sequenceAction
r iInteractive rebase (opens rebase todo buffer)
r uRebase current branch onto upstream
r eRebase and edit every commit message
r sRebase and autosquash fixup/squash commits

In the rebase todo buffer, place the cursor on a commit and press:

KeyAction
rReword this commit's message
eEdit (stop and drop to shell for this commit)
sSquash into previous commit
fFixup (squash, discard this commit's message)
dDrop this commit
M-p / M-nMove commit up/down in the list

Confirm with C-c C-c. Abort with C-c C-k. Magit automatically stashes uncommitted changes before the rebase and reapplies them after.

Log, Show, and Blame

Press l for the log popup. l l shows the log for the current branch. In the log buffer:

  • RET — show the full commit diff
  • a — cherry-pick the commit at point
  • A — cherry-pick and immediately commit
  • r i — interactive rebase starting from the commit at point

For blame, open any file and run M-x magit-blame (or bind it). Blame overlays each line with commit metadata. Press RET on a blame annotation to recurse into the parent commit's blame — a feature that has no equivalent in plain Git.

Stashing

Press z for the stash popup:

Key sequenceAction
z zStash all changes (with message prompt)
z iStash index only
z pPop most recent stash
z aApply a stash (keep it in the list)
z lList all stashes

Bisect

Git bisect is underused because the command-line interface is clunky. In Magit:

  1. Open the log (l l).
  2. Press B to open the bisect popup.
  3. B s — mark current commit as bad.
  4. Move point to a known good commit and press B g — mark as good.
  5. Magit checks out the midpoint. Test, then B b (bad) or B g (good). Repeat.
  6. B r — reset when done.

Recommended Configuration

(use-package magit
  :straight t
  :bind (("C-x g"   . magit-status)
         ("C-x M-g" . magit-dispatch)
         ("C-c g b" . magit-blame))
  :custom
  ;; Show status in same window, avoid split
  (magit-display-buffer-function
   #'magit-display-buffer-same-window-except-diff-v1)
  ;; Save modified buffers without asking
  (magit-save-repository-buffers 'dontask)
  ;; Spell-check commit messages
  (git-commit-summary-max-length 72)
  ;; Auto-revert Magit buffers
  (magit-auto-revert-mode t)
  ;; Show fine-grained word diffs
  (magit-diff-refine-hunk 'all)
  :hook
  (git-commit-setup . git-commit-turn-on-flyspell))

Magit Forge: GitHub and GitLab Inside Emacs

Install forge to manage pull requests, issues, and notifications without leaving Emacs:

(use-package forge
  :straight t
  :after magit)

After adding your token to ~/.authinfo.gpg, press N in the status buffer to access the forge popup. N p l lists open PRs; N i l lists issues. You can create, review, and merge PRs entirely from the Magit buffer.

Summary Checklist

  • Install Magit and bind magit-status to C-x g.
  • Use TAB to expand diffs inline; stage hunks with s, not whole files.
  • Learn c c, c a, c f for the full commit workflow.
  • Use r i for interactive rebase — it is dramatically better than the command line.
  • Enable magit-diff-refine-hunk for word-level diff highlighting.
  • Add forge if you use GitHub or GitLab; it eliminates browser context switches.
  • Use B (bisect) for regressions rather than manually checking out commits.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Please share this article on your favorite website or platform.