How can I generate a Git patch for a specific commit?
Asked Answered
S

11

1666

I want to create a patch for a specific commit hash, <rev>.

I tried using git format-patch <rev>, but that generated a patch for each commit since the <rev> commit. Is there a way to generate a patch only for <rev>?

Surefire answered 12/7, 2011 at 0:35 Comment(0)
G
2595

Try:

git format-patch -<n> <rev>

For example:

git format-patch -1 HEAD

The -1 flag indicates how many commits should be included in the patch:

-<n>

     Prepare patches from the topmost <n> commits.


Apply the patch with the command:

git am < file.patch

Alternatively you can also apply (should work on all OSes including Windows) with:

git apply --verbose file.patch

The -v or --verbose will show what failed, if any. Giving you a clue on how to fix.

Grip answered 12/7, 2011 at 0:43 Comment(11)
Applying the patch: git apply --stat file.patch # show stats. git apply --check file.patch # check for error before applying. git am < file.patch # apply the patch finally.Unmannerly
It does not seem to work if the last commit is a merge from another branch.Tray
It is the very correct answer! If u also want to specify the output file , u can try this "git format-patch -1 <sha> -o output" . Then u will git a patch on the directory, it's sth like this: ./output/xxxxxx.patchGambeson
To apply the patch on files using CRLF line endings: git am --keep-cr < mypatch.patchIntravasation
Omitting <sha>, by the way, will default to HEAD.Baikal
Use git am -3 < file.patch to apply using a three-way merge which will let you resolve conflicts using git mergetool afterward (or editing manually) found here.Herschel
patch -p1 < file.patch didn't create new files.Cad
This command also works for just a specific file(s) from the commit: git format-patch -1 <sha> path/to/file.js This will create a patch only containing the diffs for the file.jsExclosure
Git format-patch documentation states "If you want to format only <commit> itself, you can do this with git format-patch -1 <commit>."Alva
It would be very helpful if you explained the purpose of the -1Farmstead
In case it is needed to ensure the commit hash is preserved when applying the commit, use --committer-date-is-author-date.Afternoons
R
362

For generating the patches from the topmost <n> commits from a specific SHA-1 hash:

git format-patch -<n> <SHA-1> --stdout > <name_of_patch_file>.patch

The last 10 patches from head in a single patch files:

git format-patch -10 HEAD --stdout > 0001-last-10-commits.patch
Rotate answered 23/4, 2013 at 14:34 Comment(2)
git format-patch -1 HEAD will generate patch for the most recent commitRotate
pardon me for asking this, so when it is -2 it generate patches for most recent 2 commits is it, and one more thing to for clarification is the command got format-patch -2 HEAD is same as the line git format-patch HEAD~2Tongs
S
125

Say you have commit id 2 after commit 1 you would be able to run:

git diff 2 1 > mypatch.diff

where 2 and 1 are SHA-1 hashes.

Sadiron answered 12/7, 2011 at 0:42 Comment(6)
Thank you dookehster for the reply. That means I need the script to find the commits that preceded those I am interested in. I was hoping that I could avoid that.Surefire
@elle, no, you don't -- git diff hash^ hash . the "hash^" give the preceded commit. (but, of course, manojlds's answer is better)Extrajudicial
git show HEAD > mypatch.diff while you're on the commit should do the same.Emissive
@dookehester is it correct or is it the other way, git diff 1 2Tongs
I tend to use --no-prefix and apply with 'patch -p0 < patch file' ... patch files made this way also work interchangeably with subversion's diff outputTinatinamou
This will fail to include any binary files in the diff.Destinee
C
73

This command (as suggested already by @Naftuli Tzvi Kay),

git format-patch -1 HEAD

Replace HEAD with a specific hash or range.

will generate the patch file for the latest commit formatted to resemble the Unix mailbox format.

-<n> - Prepare patches from the topmost <n> commits.

Then you can reapply the patch file in a mailbox format by:

git am -3k 001*.patch

See: man git-format-patch.

Conium answered 12/7, 2011 at 0:36 Comment(4)
Thanks! I think it's worth noting that applying the patch will create a commit with a commit message prefixed by [PATCH]. That's easy to fix thoughRecalcitrant
Phenomenal. OP, you haven't accepted this, because...? @MikeS No, it doesn't, anymore than any other git-formatted patch does, at least if the user applies it in the correct way.Lye
@MikeS I didn't really investigate why, but leaving out the -k flag (git am -3) fixed this form me (no PATCH[0/10] commit messages). Git version 2.20.1.windows.1Beneficence
@Beneficence see man git-am and man git-mailbox for explanation, this is expected behavior of the -k optionAnciently
K
42
git format-patch commit_Id~1..commit_Id  
git apply patch-file-name

Fast and simple solution.

Kreegar answered 6/7, 2017 at 13:52 Comment(2)
Also do not forget to call git apply --check patch-file-name before applying a patch. This will help to avoid problems.Spindlelegs
also be aware that git apply will lose all of the commit information and you have to commit manually. git am calls git apply behind the scenes but preserves that info which in turn means it makes the commits automatically. see https://mcmap.net/q/22465/-what-is-the-difference-between-git-am-and-git-applyAnciently
W
24

If you want to be sure the (single commit) patch will be applied on top of a specific commit, you can use the new git 2.9 (June 2016) option git format-patch --base

git format-patch --base=COMMIT_VALUE~ -M -C COMMIT_VALUE~..COMMIT_VALUE

# or
git format-patch --base=auto -M -C COMMIT_VALUE~..COMMIT_VALUE

# or
git config format.useAutoBase true
git format-patch -M -C COMMIT_VALUE~..COMMIT_VALUE

See commit bb52995, commit 3de6651, commit fa2ab86, commit ded2c09 (26 Apr 2016) by Xiaolong Ye (``).
(Merged by Junio C Hamano -- gitster -- in commit 72ce3ff, 23 May 2016)

format-patch: add '--base' option to record base tree info

Maintainers or third party testers may want to know the exact base tree the patch series applies to. Teach git format-patch a '--base' option to record the base tree info and append it at the end of the first message (either the cover letter or the first patch in the series).

The base tree info consists of the "base commit", which is a well-known commit that is part of the stable part of the project history everybody else works off of, and zero or more "prerequisite patches", which are well-known patches in flight that is not yet part of the "base commit" that need to be applied on top of "base commit" in topological order before the patches can be applied.

The "base commit" is shown as "base-commit: " followed by the 40-hex of the commit object name.
A "prerequisite patch" is shown as "prerequisite-patch-id: " followed by the 40-hex "patch id", which can be obtained by passing the patch through the "git patch-id --stable" command.


Git 2.23 (Q3 2019) will improve that, because the "--base" option of "format-patch" computed the patch-ids for prerequisite patches in an unstable way, which has been updated to compute in a way that is compatible with "git patch-id --stable".

See commit a8f6855, commit 6f93d26 (26 Apr 2019) by Stephen Boyd (akshayka).
(Merged by Junio C Hamano -- gitster -- in commit 8202d12, 13 Jun 2019)

format-patch: make --base patch-id output stable

We weren't flushing the context each time we processed a hunk in the patch-id generation code in diff.c, but we were doing that when we generated "stable" patch-ids with the 'patch-id' tool.

Let's port that similar logic over from patch-id.c into diff.c so we can get the same hash when we're generating patch-ids for 'format-patch --base=' types of command invocations.


Before Git 2.24 (Q4 2019), "git format-patch -o <outdir>" did an equivalent of "mkdir <outdir>" not "mkdir -p <outdir>", which is being corrected.

See commit edefc31 (11 Oct 2019) by Bert Wesarg (bertwesarg).
(Merged by Junio C Hamano -- gitster -- in commit f1afbb0, 18 Oct 2019)

format-patch: create leading components of output directory

Signed-off-by: Bert Wesarg

'git format-patch -o ' did an equivalent of 'mkdir <outdir>' not 'mkdir -p <outdir>', which is being corrected.

Avoid the usage of 'adjust_shared_perm' on the leading directories which may have security implications. Achieved by temporarily disabling of 'config.sharedRepository' like 'git init' does.


With Git 2.25 (Q1 2020), "git rebase" did not work well when format.useAutoBase configuration variable is set, which has been corrected.

See commit cae0bc0, commit 945dc55, commit 700e006, commit a749d01, commit 0c47e06 (04 Dec 2019) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit 71a7de7, 16 Dec 2019)

rebase: fix format.useAutoBase breakage

Reported-by: Christian Biesinger
Signed-off-by: Denton Liu

With format.useAutoBase = true, running rebase resulted in an error:

fatal: failed to get upstream, if you want to record base commit automatically,
please use git branch --set-upstream-to to track a remote branch.
Or you could specify base commit by --base=<base-commit-id> manually
error:
git encountered an error while preparing the patches to replay
these revisions:

ede2467cdedc63784887b587a61c36b7850ebfac..d8f581194799ae29bf5fa72a98cbae98a1198b12

As a result, git cannot rebase them.

Fix this by always passing --no-base to format-patch from rebase so that the effect of format.useAutoBase is negated.


With Git 2.29 (Q4 2020), "git format-patch"(man) learns to take "whenAble" as a possible value for the format.useAutoBase configuration variable to become no-op when the automatically computed base does not make sense.

See commit 7efba5f (01 Oct 2020) by Jacob Keller (jacob-keller).
(Merged by Junio C Hamano -- gitster -- in commit 5f8c70a, 05 Oct 2020)

format-patch: teach format.useAutoBase "whenAble" option

Signed-off-by: Jacob Keller

The format.useAutoBase configuration option exists to allow users to enable '--base=auto' for format-patch by default.

This can sometimes lead to poor workflow, due to unexpected failures when attempting to format an ancient patch:

$ git format-patch -1 <an old commit>
fatal: base commit shouldn't be in revision list  

This can be very confusing, as it is not necessarily immediately obvious that the user requested a --base (since this was in the configuration, not on the command line).

We do want --base=auto to fail when it cannot provide a suitable base, as it would be equally confusing if a formatted patch did not include the base information when it was requested.

Teach format.useAutoBase a new mode, "whenAble".

This mode will cause format-patch to attempt to include a base commit when it can. However, if no valid base commit can be found, then format-patch will continue formatting the patch without a base commit.

In order to avoid making yet another branch name unusable with --base, do not teach --base=whenAble or --base=whenable.

Instead, refactor the base_commit option to use a callback, and rely on the global configuration variable auto_base.

This does mean that a user cannot request this optional base commit generation from the command line. However, this is likely not too valuable. If the user requests base information manually, they will be immediately informed of the failure to acquire a suitable base commit. This allows the user to make an informed choice about whether to continue the format.

Add tests to cover the new mode of operation for --base.

git config now includes in its man page:

format-patch by default.
Can also be set to "whenAble" to allow enabling --base=auto if a suitable base is available, but to skip adding base info otherwise without the format dying.


With Git 2.30 (Q1 2021), "git format-patch --output=there"(man) did not work as expected and instead crashed.

The option is now supported.

See commit dc1672d, commit 1e1693b, commit 4c6f781 (04 Nov 2020) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit 5edc8bd, 18 Nov 2020)

format-patch: support --output option

Reported-by: Johannes Postler
Signed-off-by: Jeff King

We've never intended to support diff's --output option in format-patch. And until baa4adc66a (parse-options: disable option abbreviation with PARSE_OPT_KEEP_UNKNOWN, 2019-01-27, Git v2.22.0-rc0), it was impossible to trigger. We first parse the format-patch options before handing the remainder off to setup_revisions().
Before that commit, we'd accept "--output=foo" as an abbreviation for "--output-directory=foo". But afterwards, we don't check abbreviations, and --output gets passed to the diff code.

This results in nonsense behavior and bugs. The diff code will have opened a filehandle at rev.diffopt.file, but we'll overwrite that with our own handles that we open for each individual patch file. So the --output file will always just be empty. But worse, the diff code also sets rev.diffopt.close_file, so log_tree_commit() will close the filehandle itself. And then the main loop in cmd_format_patch() will try to close it again, resulting in a double-free.

The simplest solution would be to just disallow --output with format-patch, as nobody ever intended it to work. However, we have accidentally documented it (because format-patch includes diff-options). And it does work with "git log"(man) , which writes the whole output to the specified file. It's easy enough to make that work for format-patch, too: it's really the same as --stdout, but pointed at a specific file.

We can detect the use of the --output option by the "close_file" flag (note that we can't use rev.diffopt.file, since the diff setup will otherwise set it to stdout). So we just need to unset that flag, but don't have to do anything else. Our situation is otherwise exactly like --stdout (note that we don't fclose() the file, but nor does the stdout case; exiting the program takes care of that for us).

Willey answered 24/5, 2016 at 7:26 Comment(0)
P
22

Create a git patch using commit-id

$ git format-patch -1 commit-id

This command create patch with following file name

0001-commit-message.patch

To apply the patch:

$ git am 0001-commit-message.patch
Pony answered 23/9, 2021 at 16:18 Comment(3)
Could you clarify the -1 argument? I was unable to find a reference to it in the docs or online.Ming
@Ming I found it in the manpage: -<n> Prepare patches from the topmost <n> commitsOvovitellin
If you change -1 to any >1 number you will still get patch per commit. How does this even answer the question?Patton
F
12

To generate a patch from a specific commit (not the last commit):

git format-patch -M -C COMMIT_VALUE~1..COMMIT_VALUE
Furbelow answered 4/5, 2016 at 16:52 Comment(0)
E
6

With my Mercurial background I was going to use:

git log --patch -1 $ID > $file

But I am considering using git format-patch -1 $ID now.

Elongation answered 31/1, 2020 at 18:49 Comment(0)
I
5

If you just want diff the specified file, you can use:

git diff master 766eceb -- connections/ > 000-mysql-connector.patch

Indult answered 1/6, 2018 at 6:29 Comment(0)
W
-1

What is the way to generate a patch only for the specific SHA-1 value?

It's quite simple:

Option 1. git show commitID > myFile.patch

Option 2. git commitID~1..commitID > myFile.patch

Note: Replace commitID with the actual commit id (SHA-1 commit code).

Wilde answered 17/1, 2017 at 9:40 Comment(2)
Option 2 is also an invalid command. You will get error like: git a5f4bcaeb7fa7de27ae79d9522332e872889bbf0~1..a5f4bcaeb7fa7de27ae79d9522332e872889bbf0 git: 'a5f4bcaeb7fa7de27ae79d9522332e872889bbf0~1..a5f4bcaeb7fa7de27ae79d9522332e872889bbf0' is not a git command. See 'git --help'. Pleas check before posting answersAftersensation
Option 1 is actually what I was looking for when I went searching how to do this. +1 from me!Filagree

© 2022 - 2024 — McMap. All rights reserved.