70

I would like to create a patch for the last 2 revisions.

git format-patch -2

gives me 2 patch files, one for each revision

git format-patch HEAD~2..HEAD

gives the same thing.

git format-patch -1 HEAD~2..HEAD

gives a single file, but only contains changes for the last revision.

Is there any way to do this in git?

Matthew
  • 28,056
  • 26
  • 104
  • 170
  • 2
    Can you tell us more about the context of what you want to do? Are you aware of ability to squash commits together with interactive rebase? If so, why would you want to squash a patch you send to others but not the corresponding commits in your history? – Greg Bacon Feb 07 '10 at 21:04
  • @gbacon: I actually learned about rebase shortly after posting this question. You're right that it is a better solution to my problem. Still, it can't hurt to know how to do this. – Matthew Feb 07 '10 at 22:15
  • 1
    @GregBacon: One thing I now do often is: Work in a feature branch, with many small commits. When it's time to push the branch to master, squash it first. But in the meantime, I use `git diff master mybranch` to send in a patch for review, while still preserving my small commit history (for my own use). – Matthew Aug 21 '12 at 00:36
  • possible duplicate of [How do you squash commits into one patch with git format-patch?](http://stackoverflow.com/questions/616556/how-do-you-squash-commits-into-one-patch-with-git-format-patch) – Damien Aug 20 '13 at 13:02

4 Answers4

71
git diff HEAD~2..HEAD > my-patch.diff

It won't have any of format-patch's per-commit metadata, though.

Tobu
  • 24,771
  • 4
  • 91
  • 98
70

Use the --stdout option and then cat it to a file.

Like so:

git format-patch HEAD~2..HEAD --stdout > changes.patch

This will keep the per-commit metadata.

JC Brand
  • 2,652
  • 18
  • 18
  • 3
    What you get is an mbox file (concatenated mail files), not a patch file. You can apply it with `git am`. You won't be able to use the standard tools for patch files. – Tobu Aug 30 '12 at 15:55
  • 1
    @Tobu: but often you want to apply the commits with `git am`, since that retains the commits as they are, instead of one big blob of code... – Smar Jun 01 '16 at 08:20
  • is there a way to reference the origin's HEAD as the beginning of the refspec?! That would be amazing something like `git format-patch origin/HEAD..HEAD --stdout > changes.patch`... OMG THAT WORKS – Ray Foss Jun 12 '20 at 18:43
  • This solution is better than the one above - if there are binary files (for example secret files) then they will not be included in the above solution. This solution will also produce the full list of commits into one big patch file which is awesome - if you need to squash, it's possible using `git rebase -i` later on. – John Basila Oct 19 '20 at 07:36
5

With Git 2.20 (Q4 2018) and more, you now have:

  • git format-patch --interdiff.
  • git format-patch --rangediff.

Both are helping to explain the difference between this version and the previous attempt in the cover letter (or after the tree-dashes as a comment).

format-patch: allow --interdiff / --rangediff to apply to a lone-patch

When submitting a revised version of a patch or series, it can be helpful (to reviewers) to include a summary of changes since the previous attempt in the form of an interdiff, typically in the cover letter.
However, it is occasionally useful, despite making for a noisy read, to insert an interdiff or a rangediff into the commentary section of the lone patch of a 1-patch series.

See commit ee6cbf7, commit 3fcc7a2, commit 3b02641, commit 5ac290f, commit 126facf, commit fa5b7ea (22 Jul 2018) by Eric Sunshine (sunshineco).
(Merged by Junio C Hamano -- gitster -- in commit 688cb1c, 17 Sep 2018)

Therefore, extend "git format-patch --interdiff=<prev>" to insert an interdiff into the commentary section of a lone patch rather than requiring a cover letter.
The interdiff is indented to avoid confusing git-am and human readers into considering it part of the patch proper.

See commit 40ce416, commit 8631bf1, commit 4ee9968, commit 2e6fd71, commit 31e2617, commit 73a834e, commit 2566865, commit 87f1b2d (22 Jul 2018) by Eric Sunshine (sunshineco).
(Merged by Junio C Hamano -- gitster -- in commit 881c019, 17 Sep 2018)

Therefore, extend "git format-patch --range-diff=<refspec>" to insert a range-diff into the commentary section of a lone patch rather than requiring a cover letter.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • So, `git format-patch --range-diff=` produces a patch with just the commits needed, and no PATCH letter with each file changed? – ZeroPhase May 08 '19 at 02:15
  • @ZeroPhase no patch letter, as far as I know. (https://git-scm.com/docs/git-format-patch#Documentation/git-format-patch.txt---range-diffltpreviousgt) – VonC May 08 '19 at 14:35
-1

You could do something like:

$ git checkout -b tmp
$ git reset HEAD~2
$ git commit -a

The commit to branch tmp will be the same as the 2 individual commits.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • or `git rebase -i HEAD~2`, and squash. – Tobu Feb 07 '10 at 17:54
  • 3
    Huh, a down vote on an answer that is well over 6 years old! That's some serious archeology. A comment would have been nice to explain the necrophilia. – William Pursell May 31 '16 at 17:39
  • I’m not the downvoter, but I’d suppose it’s because there is easier and safer ways to do it; `git reset` can eradicate something extra. The rebase given in a comment would be a bit safer since it would at least tell if the work tree is dirty. That said, I do think this answer has value. – Smar Jun 01 '16 at 08:22
  • This answer helped me since I needed to deal with well over 20 commits... – Dror Cohen May 24 '17 at 22:39
  • 1
    This is a dangerous way to do things if you have added new files / renamed them. – sdevikar Feb 09 '18 at 22:42