Skip to content

Instantly share code, notes, and snippets.

@hlissner
Last active September 2, 2026 04:42
Show Gist options
  • Select an option

  • Save hlissner/c2aeae09772242360af48404893793e5 to your computer and use it in GitHub Desktop.

Select an option

Save hlissner/c2aeae09772242360af48404893793e5 to your computer and use it in GitHub Desktop.
Doom Emacs: git conventions

< back to index

Important

This gist is temporary until the new documentation (docs.doomemacs.org) and community wiki (wiki.doomemacs.org) have been published.

Git Conventions

Doom has adopted conventional commits (with a few minor tweaks). I summarize it here, temporarily, until our new documentation is up.

[SUBJECT]

[BODY]

[FILE-LOG]

[FOOTER]

Where [SUBJECT] is:

TYPE[!][(SCOPE)]: SUMMARY

As of afdd5f5, use doom run commit-linter HEAD in a git repository to lint your last commit locally.

Subject

Types

The commit type indicates, at a glance, what kind of change was made. Here are the types our projects recognize:

  • All projects:

    • dev: for work on project infrastructure: build scripts, CI/CD config files (e.g. .github/*), ignore files, etc.

    • docs: changes to user-facing documentation such as module docs, manuals, function docstrings, and output from CLI commands like doom help or doom doctor. Also for file templates like init.example.el or yasnippets in the file-templates module.

    • feat: code introducing a brand new feature or behavior.

    • fix: Resolves a bug or misbehavior. I.e. "This should've been working from the start" Also applicable when fixing stale code that was missed during a recent bump.

    • nit: cosmetic changes to comments, formatting, or spelling/grammar with no effect on any behavior whatsoever.

    • perf: A refactor or tweak intent on incrementally improving startup/runtime performance, specifically. Use fix instead if the performance issue being addressed is so severe that it renders Doom difficult/impossible to use.

    • refactor: code changes with little effect on user-facing behavior (unless paired with !--to indicate a breaking change--in which case it indicates the wholesale removal of code/features).

    • revert: Undoes a previous change. Must be followed by one of:

      • Doom groups/modules, listed in the same format as the doom! macro (when reverting module bumps)
      • Space-delimited package names (when reverting bumps)
      • The full subject of the reverted commit (and add Revert HASH to FOOTER).

      If you are reverting another commit in a same PR, please rebase the earlier commit out instead.

    • test: Added/removed/modifications to the contents of tests (but not changing testing infrastructure; use dev for that)

    • tweak: Changes that tune the default settings to better accommodate existing functionality, in general. The less specific your motivation for the change, the more appropriate tweak is over the other tyes. For example:

      • Use fix if the tweak is done to solve specific and known issues/bugs. Use tweak if it's meant to solve a poorly defined set of potential issues.
      • Use feat if the tweak's intention is to introduce brand new behavior. Use tweak if new behavior/features are the side-effect or consequence, rather than the goal.
      • Use perf if the tweak solves a specific and known performance problem, rather than a general (and possibly untested) one.

      Example: if I increase read-process-output-max to make lsp-mode clients run faster, use perf. If I change it to make IPC faster for all processes, use tweak. If I do it because the old value caused memory errors, use fix

    • merge: used for merge commits. E.g. merge: pull request #1234 from username/branchname

    • release: used to announce new tagged releases of the project. E.g. release: 3.0.0 (only a maintainer should use this type)

  • doomemacs/modules{,-contrib}:

    • module: Changes to our module list: adding, removing, moving, or deprecating modules.
      • Not for changes /within/ modules.

      • Place scope after colon.

        module: add :lang zig
        
        module: move :feature evil to :editor evil
        
        module: remove :ui fill-column
        
        With Emacs 26.x support dropped and display-fill-column-indicator-mode
        introduced in Emacs 27.1, this module is reduced to a single line, and so has
        become too trivial to warrant its own module.
        
      • bump: Package updates or code/doc changes intended solely to reflect changes upstream. Use revert: when downgrading packages. Must include bump commit diffs:

        bump: [:CATEGORY [MODULE...]|PACKAGE [PACKAGE...]|*]
        
        user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x
        user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x
        user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x
        
        [BODY]
        
        [FILE-LOG]
        
        [FOOTER]
        
  • doomemacs/themes:

    • theme: changes to the list of themes: adding, removing, moving, or deprecating themes.
  • doomemacs/snippets:

    • snippet: changes to the list of snippets: adding, removing, moving, or deprecating snippets.

Scopes

Scopes may be one or more of the following:

  • All projects:
    • For dev commits only:
      • ci -- affects continuous integration/delivery infrastucture.
  • For doomemacs/doomemacs:
    • A module's name without the category: nit(python):, test(doom-dashboard):, dev(popup):, docs(everywhere):
    • A category without the module, implying it affects all or many modules inside: fix(:lang):, feat(:editor):, ..
    • One of these special scopes:
      • cli: for anything concerning Doom's CLI: lisp/doom-cli.el, lisp/cli/*.el, or bin/*.
  • For doomemacs/themes:
    • base -- affects the base theme (or all themes)
    • The name of any of its themes, minus the doom- prefix and -theme suffix. E.g. feat(one): ...) for doom-one, or fix(gruvbox-light): ... for doom-gruvbox-light.
    • The name of any of any doom-themes-ext-X.el extension, minus doom-themes- and .el. E.g. feat(ext-org): ...
  • For doomemacs/snippets:
    • Any major mode, minus the -mode suffix. E.g. fix(org): ... for a bugfix in an org-mode snippet.

The scope may be omitted if:

  • The change affects many parts.
  • The change affects "core" code.
  • Using a scopeless type, like bump, revert, release, or merge (as well as theme for doomemacs/themes and module for doomemacs/doomemacs). For these, the scope belongs in their SUBJECT.

Warning

Does your change touch multiple Doom modules? Only mention the target scope(s). For example, a fix or update for :tools lsp that affects LSP implementations in various :lang modules only needs to specify lsp as its scope.

Warning

No issue/PR references in SUBJECT. See Footer below.

Summary

  • Should be present tense and imperative mood.

    • feat: add X instead of feat: added Y
    • fix: replace A with B instead of fix: replaced A with B
    • When TYPE is a verb, it may be used as part of the SUBJECT:
      • Bad: fix: fix TAB breaking when focus is lost
      • Good: fix: TAB breaking when focus is lost
  • The first word in SUBJECT should not be capitalized – unless it’s a code reference or a proper noun, e.g.

    • Good: fix: TAB breaks when focus is lost
    • Good: fix: remove buggy code
    • Good: fix: John Jacob jingled Heimer's Schmidt
    • Bad: feat: Add new shenanigans
  • Do not quote symbol references and inline code: tweak: gc-cons-threshold = (* 128 1024 1024)

  • Only quote key sequences if they are ambiguous in their context:

    • Good: feat: add C-; keybind
    • Good: refactor!: remove C-c C-; keybind
    • Bad: fix: make SPC s m a reality
    • Good: fix: make 'SPC s m' a reality
    • Bad: fix: bind 'SPC '' to ivy-resume
    • Good: fix: bind "SPC '" to ivy-resume

    A single quote is preferred. Switch to double quote if ' is present in sequence, otherwise backquote. If all three characters are present, know that the ancient ones don’t take kindly to your summoning methods

Body

BODY is optional and should explain the commit's changes in greater detail. It has no restrictions on tense, but should follow these conventions:

  • Line width must not exceed 72 characters, except for:

    • Machine generated lines, like bump diffs: user/repo@HASH -> user/repo@HASH
    • Long URLs
    • Long symbol references (e.g. a long function name)
  • Code blocks should be indented by 2 spaces from the previous paragraph, and separated from them with a blank line (before and after).

    fix(foo): bar
    
    Before:
    
      (+ 1 2)
    
    After:
    
      (+ 2 1)
    
    Ref: #1234
    
  • Inline code should be surrounded by backquotes, ala sub-shell syntax:

    fix(foo): bar
    
    `foo` calls the juxtapose of `(+ 1 2)`, i.e. `(+ 2 1)`.
    

File Log

For more complex commits whose changes span many files or multiple areas of the project, consider including a per-file changelog at the end of BODY (unless the changes are all pretty much identical and entirely summarized by BODY already). For example:

refactor!: rename foo to bar

BREAKING CHANGE: This changes the semantics of the `foo` function to do
X and Y, instead of Z. Any uses of this function must be updated to
reflect this.

* some/file.el (func-that-used-bar): remove `bar` use as it's no longer
  needed.
* another/file.el (bar-hook, other-bar-hook): update call
* foo.el (maybe-calls-bar): update call
* a/big/file.el:
  - (maybe-calls-bar): update in case of Z instead of X
  - (variablename): change default to accommodate Z instead of Y

Format

The precise format of a file log entry is either:

* FILENAME[ (SUBSCOPE[, SUBSCOPE]...)]: SUMMARY

Or, for multiple changes in one file:

* FILENAME:
  - (SUBSCOPE[, SUBSCOPE]): SUMMARY
  - (SUBSCOPE[, SUBSCOPE]): SUMMARY
  - ...

Strive to document all non-trivial changes this way, so that readers (and parsers) can detect where a symbol was changed.

  • A file log entry isn't necessary for:
    • The core change itself (e.g. where foo was changed to bar).
    • Changes that are trivial and have no impact on program correctness or behavior (e.g. reformatting, grammar/spelling, etc) unless it's directly relevant to the core change of the commit.
  • SUBSCOPE can be any arbitrary identifier, but 99% of the time should refer to the local symbol(s) affected.
  • If a change is too broad, the SUBSCOPEs may be omitted, but this is discouraged. A long list of SUBSCOPEs is preferred over few/no scopes, for posterity.
  • If a change affects a file's top-level, and doesn't affect any particular symbol, then the scope may be omitted.
  • Please sort the file list lexicographically (i.e. make it match the order they're displayed in, in git status or the magit diff).
  • No blank link in between log entries.

Footer

FOOTER is where commit trailers go. Each line should be comprised of:

  • A keyword followed by a colon:
    • Fix: REF|HASH|URL -- This commit resolves a Github issue. Use Ref if it isn't certain that this commit will fix the issue.
    • Ref: REF|HASH|URL -- Consult this resource for more information about this commit.
    • Close: REF -- This commit supersedes a Github PR or closes a Github issue (but does not resolve it; e.g. if a commit makes the issue obsolete or indicates a decision not to address the issue).
    • Revert: REF|HASH -- For commits that completely revert an earlier commit or un-bumps packages (repins them to earlier commits). For half-reverts use Amend.
    • Amend: REF|HASH -- This commit addresses an issue introduced within the same release (or PR). This merges or hides the commit from the changelog generator (E.g. to avoid announcing a breaking change to behavior that was introduced before it was released).
    • One of Github's supported trailers, e.g. Co-authored-by: or Signed-off-by:
  • A single reference:
    • An issue or PR REFerence: #123, user/repo#123, https://git.forge.fake/repo#123
    • A 12-character commit HASH: 3bedae38dd9f, user/repo@3bedae38dd9f, https://git.forge.fake/repo@3bedae38dd9f
    • An URL to an external website: e.g. a mailing list, reddit discussion, etc.

Examples:

Amend: #666
Amend: 3bedae38dd9f
Close: #55
Close: user/repo#952
Fix: #1
Fix: #25
Fix: https://git.forge.fake/repo#123
Fix: user/repo#84
Ref: #4
Ref: #5
Ref: 3bedae38dd9f
Ref: https://en.wikipedia.org/wiki/Git
Ref: https://git.forge.fake/repo#123
Ref: user/repo#25
Ref: user/repo@3bedae38dd9f
Revert: 3bedae38dd9f
Co-authored-by: John Doe <john@doe.com>
Signed-off-by: Jane Doe <jane.com>

Warning

Order of trailers don't matter, but please group like-keywords together.

Breaking changes

  • Append a ! to the TYPE to indicate a breaking change.
  • Prepend BREAKING CHANGE: to BODY, followed by an explanation of what is broken (and ideally, how to get around it).

Examples:

  • refactor!: remove X functionality
    
    BREAKING CHANGE: Without X, A and B will not work. Enable Y to get 
    similar behavior.
    
  • fix!(zig): remove lsp support
    
    BREAKING CHANGE: removing LSP support reduces how much Microsoft you
    must ingest to write Zig, but it means no more LSP. Only workaround 
    is to meme on the internet, especially in obscure git convention guides
    that only a handful of people will ever read.
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment