From a454cdca42fda0afaade73d7e90010289d1e7ba8 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Thu, 12 Feb 2026 23:28:23 +0100 Subject: [PATCH] doc: add caveat about round-tripping format-patch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-format-patch(1) and git-am(1) deal with formatting commits as patches and applying them, respectively. Naturally they use a few delimiters to mark where the commit message ends. This can lead to surprising behavior when these delimiters are used in the commit message itself. git-format-patch(1) will accept any commit message and not warn or error about these delimiters being used.[1] Especially problematic is the presence of unindented diffs in the commit message; the patch machinery will naturally (since the commit message has ended) try to apply that diff and everything after it.[2] It is unclear whether any commands in this chain will learn to warn about this. One concern could be that users have learned to rely on the three-dash line rule to conveniently add extra-commit message information in the commit message, knowing that git-am(1) will ignore it.[4] All of this is covered already, technically. However, we should spell out the implications. † 1: There is also git-commit(1) to consider. However, making that command warn or error out over such delimiters would be disruptive to all Git users who never use email in their workflow. † 2: Recently patch(1) caused this issue for a project, but it was noted that git-am(1) has the same behavior[3] † 3: https://github.com/i3/i3/pull/6564#issuecomment-3858381425 † 4: https://lore.kernel.org/git/xmqqldh4b5y2.fsf@gitster.g/ https://lore.kernel.org/git/V3_format-patch_caveats.354@msgid.xyz/ Reported-by: Matthias Beyer Reported-by: Christoph Anton Mitterer Reported-by: Matheus Tavares Reported-by: Chris Packham Helped-by: Jakob Haufe Helped-by: Phillip Wood Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/format-patch-caveats.adoc | 33 +++++++++++++++++++ .../format-patch-end-of-commit-message.adoc | 8 +++++ Documentation/git-am.adoc | 19 +++++++---- Documentation/git-format-patch.adoc | 4 +++ Documentation/git-send-email.adoc | 5 +++ 5 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 Documentation/format-patch-caveats.adoc create mode 100644 Documentation/format-patch-end-of-commit-message.adoc diff --git a/Documentation/format-patch-caveats.adoc b/Documentation/format-patch-caveats.adoc new file mode 100644 index 0000000000..807a65b885 --- /dev/null +++ b/Documentation/format-patch-caveats.adoc @@ -0,0 +1,33 @@ +The output from linkgit:git-format-patch[1] can lead to a different +commit message when applied with linkgit:git-am[1]. The patch that is +applied may also be different from the one that was generated, or patch +application may fail outright. +ifdef::git-am[] +See the <> section above for the syntactic rules. +endif::git-am[] + +ifndef::git-am[] +include::format-patch-end-of-commit-message.adoc[] +endif::git-am[] + +Note that this is especially problematic for unindented diffs that occur +in the commit message; the diff in the commit message might get applied +along with the patch section, or the patch application machinery might +trip up because the patch target doesn't apply. This could for example +be caused by a diff in a Markdown code block. + +The solution for this is to indent the diff or other text that could +cause problems. + +This loss of fidelity might be simple to notice if you are applying +patches directly from a mailbox. However, changes originating from Git +could be applied in bulk, in which case this would be much harder to +notice. This could for example be a Linux distribution which uses patch +files to apply changes on top of the commits from the upstream +repositories. This goes to show that this behavior does not only impact +email workflows. + +Given these limitations, one might be tempted to use a general-purpose +utility like patch(1) instead. However, patch(1) will not only look for +unindented diffs (like linkgit:git-am[1]) but will try to apply indented +diffs as well. diff --git a/Documentation/format-patch-end-of-commit-message.adoc b/Documentation/format-patch-end-of-commit-message.adoc new file mode 100644 index 0000000000..ec1ef79f5e --- /dev/null +++ b/Documentation/format-patch-end-of-commit-message.adoc @@ -0,0 +1,8 @@ +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. diff --git a/Documentation/git-am.adoc b/Documentation/git-am.adoc index 0c94776e29..972398d457 100644 --- a/Documentation/git-am.adoc +++ b/Documentation/git-am.adoc @@ -233,6 +233,7 @@ applying. create an empty commit with the contents of the e-mail message as its log message. +[[discussion]] DISCUSSION ---------- @@ -252,14 +253,11 @@ where the patch begins. Excess whitespace at the end of each line is automatically stripped. The patch is expected to be inline, directly following the -message. Any line that is of the form: +message. +include::format-patch-end-of-commit-message.adoc[] -* 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 <> section below). When initially invoking `git am`, you give it the names of the mailboxes to process. Upon seeing the first patch that does not apply, it @@ -283,6 +281,13 @@ commits, like running 'git am' 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). +[[caveats]] +CAVEATS +------- + +:git-am: 1 +include::format-patch-caveats.adoc[] + HOOKS ----- This command can run `applypatch-msg`, `pre-applypatch`, diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc index 9a7807ca71..bac9b818f3 100644 --- a/Documentation/git-format-patch.adoc +++ b/Documentation/git-format-patch.adoc @@ -798,6 +798,10 @@ if they are part of the requested range. A simple "patch" does not include enough information for the receiving end to reproduce the same merge commit. +=== PATCH APPLICATION + +include::format-patch-caveats.adoc[] + SEE ALSO -------- linkgit:git-am[1], linkgit:git-send-email[1] diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc index ebe8853e9f..0b118df649 100644 --- a/Documentation/git-send-email.adoc +++ b/Documentation/git-send-email.adoc @@ -692,6 +692,11 @@ Links of a few such community maintained helpers are: - https://github.com/AdityaGarg8/git-credential-email[git-msgraph] (cross platform client that can send emails using the Microsoft Graph API) +CAVEATS +------- + +include::format-patch-caveats.adoc[] + SEE ALSO -------- linkgit:git-format-patch[1], linkgit:git-imap-send[1], mbox(5)