GIT-AM(1)

๐ŸŒธ GIT-AM(1) โ€” the git am glow-up, bestie edition ๐ŸŒธ

okay so. you've wandered into the Git Manual page for git am and honestly? you're about to eat. this one's a whole vibe. ๐Ÿ’…


โœจ NAME โœจ

git-am โ€” apply a series of patches from a mailbox ๐ŸŽ€


๐Ÿฆ‹ SYNOPSIS ๐Ÿฆ‹

git am [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--[no-]verify]
         [--[no-]3way] [--interactive] [--committer-date-is-author-date]
         [--ignore-date] [--ignore-space-change | --ignore-whitespace]
         [--whitespace=<action>] [-C<n>] [-p<n>] [--directory=<dir>]
         [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
         [--[no-]scissors] [-S[<key-id>]] [--patch-format=<format>]
         [--quoted-cr=<action>]
         [--empty=(stop|drop|keep)]
         [(<mbox> | <Maildir>)...]
git am (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty)

๐Ÿ’– DESCRIPTION ๐Ÿ’–

so here's the tea: git am splits mail messages in a mailbox into three lil piles โ€” commit log messages, authorship information, and patches โ€” and then applies them to the current branch. it's giving โœจdispatchโœจ. the classic way to think about it is that it's literally a reverse operation of git-format-patch(1) run on a branch with a straight history without merges. iconic behavior tbh. ๐Ÿ”ฅ


๐ŸŒˆ OPTIONS ๐ŸŒˆ

  • (<mbox>|<Maildir>)... โ€” the list of mailbox files to read patches from. if you don't supply this argument, the command reads from the standard input ๐ŸŒธ. and if you supply directories, they'll be treated as Maildirs, periodt.
  • -s, --signoff โ€” adds a Signed-off-by trailer to the commit message (peep git-interpret-trailers(1)), using the committer identity of yourself ๐Ÿ‘‘. want the full lore? check the signoff option in git-commit(1).
  • -k, --keep โ€” passes the -k flag straight to git-mailinfo(1). handoff, slay.
  • --keep-non-patch โ€” passes the -b flag to git-mailinfo(1). yes bestie, a whole different flag.
  • --keep-cr, --no-keep-cr โ€” with --keep-cr, it calls git-mailsplit(1) with the same option, so it won't strip CR at the end of lines ๐Ÿซถ. the am.keepcr configuration variable can be used to specify the default behaviour, and --no-keep-cr is the move when you need to override am.keepcr.
  • -c, --scissors โ€” removes everything in the body before a scissors line (see git-mailinfo(1)). can be activated by default using the mailinfo.scissors configuration variable. โœ‚๏ธ๐Ÿ’…
  • --no-scissors โ€” ignores scissors lines (see git-mailinfo(1)). the scissors stay in the chat, unread.
  • --quoted-cr=<action> โ€” this flag gets passed down to git-mailinfo(1). that's the whole note, no cap.
  • --empty=(drop|keep|stop) โ€” how to handle an e-mail message lacking a patch. choose your fighter:
    • drop โ€” the e-mail message will be skipped. bye girl ๐Ÿ’€
    • keep โ€” an empty commit will be created, with the contents of the e-mail message as its log. main character energy for an empty commit, honestly.
    • stop โ€” the command will fail, stopping in the middle of the current am session. this is the default behavior. ๐Ÿ™ˆ
  • -m, --message-id โ€” passes the -m flag to git-mailinfo(1), so that the Message-ID header is added to the commit message. the am.messageid configuration variable can be used to specify the default behaviour.
  • --no-message-id โ€” do not add the Message-ID header to the commit message. --no-message-id is useful to override am.messageid.
  • -q, --quiet โ€” be quiet. only print error messages. ๐Ÿคซ lowkey the introvert flag.
  • -u, --utf8 โ€” passes the -u flag to git-mailinfo(1). the proposed commit log message taken from the e-mail is re-coded into UTF-8 encoding (the configuration variable i18n.commitEncoding can be used to specify the project's preferred encoding if it is not UTF-8). this was optional in prior versions of git, but now it is the default, bestie. you can use --no-utf8 to override this.
  • --no-utf8 โ€” passes the -n flag to git-mailinfo(1).
  • -3, --3way, --no-3way โ€” when the patch does not apply cleanly, fall back on a 3-way merge if the patch records the identity of blobs it is supposed to apply to and we have those blobs available locally. --no-3way can be used to override the am.threeWay configuration variable. for more info, see am.threeWay in git-config(1). ๐Ÿงš rescue mission mode.
  • --rerere-autoupdate, --no-rerere-autoupdate โ€” after the rerere mechanism reuses a recorded resolution on the current conflict to update the files in the working tree, this allows it to also update the index with the result of resolution. --no-rerere-autoupdate is a good way to double-check what git-rerere(1) did and catch potential mismerges, before committing the result to the index with a separate git-add(1). basically: peek before you commit, queen. ๐Ÿ‘‘
  • --ignore-space-change, --ignore-whitespace, --whitespace=<action>, -C<n>, -p<n>, --directory=<dir>, --exclude=<path>, --include=<path>, --reject โ€” these flags are passed to the git-apply(1) program that applies the patch. valid <action> for the --whitespace option are: nowarn, warn, fix, error, and error-all. โœจ that's the whole list, don't @ me.
  • --patch-format โ€” by default the command will try to detect the patch format automatically. this option lets the user bypass the automatic detection and specify the patch format that the patch(es) should be interpreted as. valid formats are mbox, mboxrd, stgit, stgit-series, and hg. ๐Ÿฆ‹
  • -i, --interactive โ€” run interactively. that's it. that's the bullet. ๐Ÿ’…
  • --verify, -n, --no-verify โ€” run the pre-applypatch and applypatch-msg hooks. this is the default. skip these hooks with -n or --no-verify. see also githooks(5). โš ๏ธ note that post-applypatch cannot be skipped. not me warning you twice.
  • --committer-date-is-author-date โ€” by default the command records the date from the e-mail message as the commit author date, and uses the time of commit creation as the committer date. this allows the user to lie about the committer date by using the same value as the author date. ๐Ÿ˜ญ lying is free, apparently.
Warning โš ๏ธ โ€” the history walking machinery assumes that commits have non-decreasing commit timestamps. you should consider if you really need to use this option. then you should only use this option to override the committer date when applying commits on top of a base which commit is older (in terms of the commit date) than the oldest patch you are applying. fr fr, be careful.
  • --ignore-date โ€” by default the command records the date from the e-mail message as the commit author date, and uses the time of commit creation as the committer date. this allows the user to lie about the author date by using the same value as the committer date. ๐Ÿ’€ two different lies, same energy.
  • --skip โ€” skip the current patch. this is only meaningful when restarting an aborted patch. ๐Ÿ™ˆ
  • -S[<key-id>], --gpg-sign[=<key-id>], --no-gpg-sign โ€” GPG-sign commits. the <key-id> is optional and defaults to the committer identity; if specified, it must be stuck to the option without a space ๐Ÿ’… โ€” yes, glued, no space, that's the rule. --no-gpg-sign is useful to countermand both the commit.gpgSign configuration variable, and earlier --gpg-sign.
  • --continue, -r, --resolved โ€” after a patch failure (e.g. attempting to apply a conflicting patch), the user has applied it by hand and the index file stores the result of the application. this makes a commit using the authorship and commit log extracted from the e-mail message and the current index file, and continues. you did the work, now let git take the credit for typing it out. ๐Ÿซถ
  • --resolvemsg=<msg> โ€” when a patch failure occurs, <msg> will be printed to the screen before exiting. this overrides the standard message informing you to use --continue or --skip to handle the failure. this is solely for internal use between git-rebase(1) and git-am(1). ๐Ÿ”ง don't touch unless you're on that internal business.
  • --abort โ€” restore the original branch and abort the patching operation. revert the contents of files involved in the am operation to their pre-am state. โœจ undo era โœจ
  • --quit โ€” abort the patching operation but keep HEAD and the index untouched. walking away with your hands in your pockets, no cap.
  • --retry โ€” try to apply the last conflicting patch again. this is generally only useful for passing extra options to the retry attempt (e.g. --3way), since otherwise you'll just see the same failure again. ๐Ÿ˜ญ the definition of insanity, but make it git.
  • --show-current-patch[=(diff|raw)] โ€” show the message at which git-am(1) has stopped due to conflicts. if raw is specified, show the raw contents of the e-mail message; if diff, show the diff portion only. defaults to raw. ๐Ÿ•ต๏ธโ™€๏ธ receipts time.
  • --allow-empty โ€” after a patch failure on an input e-mail message lacking a patch, create an empty commit with the contents of the e-mail message as its log message. โœจ the empty commit gets to be the main character โœจ

๐Ÿ’œ DISCUSSION ๐Ÿ’œ

okay so the commit author name is taken from the "From: " line of the message, and the commit author date is taken from the "Date: " line of the message. the "Subject: " line is used as the title of the commit, after stripping the common prefix "[PATCH <anything>]". and the "Subject: " line is supposed to concisely describe what the commit is about in one line of text. keep it snappy, bestie. ๐Ÿ’…

"From: ", "Date: ", and "Subject: " lines starting the body override the respective commit author name and title values taken from the headers. the body said "actually, no", and the body wins. ๐ŸŒธ

the commit message is formed by the title taken from the "Subject: ", a blank line, and the body of the message up to where the patch begins. excess whitespace at the end of each line is automatically stripped. ๐Ÿงš auto-clean, love that for us.

the patch is expected to be inline, directly following the message. any line that is of the form:

  • three-dashes and end-of-line, or
  • a line that begins with diff -, or
  • a line that begins with Index:

is taken as the beginning of a patch, and the commit log message is terminated before the first occurrence of such a line. ๐Ÿ‘‘

this means that the contents of the commit message can inadvertently interrupt the processing (see the CAVEATS section below). ๐Ÿ™ˆ awkward, but we move.

when initially invoking git-am(1), you give it the names of the mailboxes to process. upon seeing the first patch that does not apply, it aborts in the middle. you can recover from this in one of two ways:

  1. skip the current patch by re-running the command with the --skip option. โœ‚๏ธ
  2. hand resolve the conflict in the working directory, and update the index file to bring it into a state that the patch should have produced. then run the command with the --continue option. ๐Ÿซถ

the command refuses to process new mailboxes until the current operation is finished, so if you decide to start over from scratch, run git am --abort before running the command with mailbox names. no skipping ahead, babe. ๐Ÿ’…

before any patches are applied, ORIG_HEAD is set to the tip of the current branch. this is useful if you have problems with multiple commits, like running git-am(1) on the wrong branch or an error in the commits that is more easily fixed by changing the mailbox (e.g. errors in the From: lines). โœจ your little safety net โœจ


๐Ÿ’€ CAVEATS ๐Ÿ’€

Okay bestie, this is the part where we get real. The tea is: the output from git-format-patch(1) can end up giving you a totally different commit message when you apply it with git-am(1). Not a vibe. And the patch that actually gets applied might be different from the one that got generated, or โ€” worst case โ€” patch application just fails outright. Yikes. The syntactic rules live up in the DISCUSSION section, so go peek there.

Heads up, this is especially messy for unindented diffs that show up inside the commit message. Like, the diff in the commit message might get applied along with the patch section, or the patch machinery might trip up because the patch target doesn't apply. A classic way this happens? A diff inside a Markdown code block. ๐Ÿ˜ญ

The fix for all of this: indent the diff (or any other text that could cause problems). That's it. That's the whole hack. โœจ

This loss of fidelity might be easy to notice if you're applying patches directly from a mailbox. But when changes originating from Git get applied in bulk, it's way harder to catch. Think, like, a Linux distribution that uses patch files to apply changes on top of commits from the upstream repositories. So yeah โ€” this behaviour doesn't only impact email workflows, fr fr. ๐Ÿซถ

And given these limitations, you might be tempted to reach for a general-purpose utility like patch(1) instead. But plot twist: patch(1) will not only look for unindented diffs (like git-am(1) does) โ€” it'll try to apply indented diffs as well. ๐Ÿ‘‘ So it's not the clean escape you think it is.


๐Ÿช HOOKS ๐Ÿช

This command can run applypatch-msg, pre-applypatch, and post-applypatch hooks. See githooks(5) for the full lore.

Also see the --verify / -n / --no-verify options. ๐Ÿ‘€


โš™๏ธ CONFIGURATION โš™๏ธ

Everything below this line in this section is selectively included from the git-config(1) documentation. The content is the same as what's found there: (just keeping it faithful, bestie ๐Ÿ’…)

  • am.keepcr โ€” If true, git-am(1) will call git-mailsplit(1) for patches in mbox format with the parameter --keep-cr. In that case, git-mailsplit(1) will not remove \r from lines ending with \r\n. You can override this by giving --no-keep-cr from the command line. โœจ
  • am.threeWay โ€” By default, git-am(1) will fail if the patch does not apply cleanly. But when this is set to true, it tells git-am(1) to fall back on a 3-way merge if the patch records the identity of blobs it's supposed to apply to and we have those blobs available locally (equivalent to giving the --3way option from the command line). Defaults to false. ๐ŸŒธ
  • am.messageId โ€” Adds a Message-ID trailer based on the email header to the commit when using git-am(1) (see git-interpret-trailers(1)). Also peep the --message-id and --no-message-id options. ๐Ÿ’Œ

๐Ÿ‘€ SEE ALSO ๐Ÿ‘€


๐Ÿงš GIT ๐Ÿงš

Part of the git(1) suite. Obviously. ๐Ÿ’–


And that's the whole page, bestie โ€” you ate that. ๐ŸŽ€ This lil masterpiece is from Git 2.56.0, dated 2026-09-27, and it's serving GIT-AM(1) realness. Go forth and git am responsibly, mwah ๐Ÿ’‹

๐Ÿ“ฆ where this page comes from