git: generate a single patch across multiple commits

29,571

Solution 1

The following command creates a single .patch file that contains multiple commits.

git format-patch cc1dde0dd^..6de6d4b06 --stdout > foo.patch

You can then apply it like so:

git am foo.patch

Note: Be sure to use ^.. instead of .. if you want the first commit SHA to be included.

Solution 2

Create a new branch named squashed that has a single squashed commit. This branch will have the exact same contents as your normal branch but none of the history.

Look it over and if you're satisfied, use format-patch to create a patch file.

$ git checkout -b squashed $(git commit-tree HEAD^{tree} -m 'Squashed history')
$ git format-patch --root HEAD

This is a non-destructive operation and you can switch right back to your normal development branch afterwards. You can tag the squashed branch to save a reference to what you e-mailed them, or use branch -D to delete it if you no longer need it.

$ git branch -D squashed

Solution 3

You can use git diff:

git diff 0f3063094850 > ./test.patch

Share:
29,571
SimpleCoder
Author by

SimpleCoder

Updated on March 17, 2021

Comments

  • SimpleCoder
    SimpleCoder over 3 years

    This is the situation:

    1. We created a "private" repo (say our-repo) based off an existing open-source git repo (say source-repo).

    2. We have been developing code and have around 20 merges into our repo. So, the repo moved from "State_Initial" to "State_Current".

    Now, for business reasons, we want to hand-over all our development to a third party. Based on some legal issues, the only option is we give them a "single" patch file with all our changes. That is a squashed patch between "State_Initial" and "State_Current".

    I looked around, and found

    git format-patch -X
    

    But, it generates "n" .patch files.

    Is there a way to create a single patch file, so that if we create a repo based off "source-repo" and apply the patch, it takes us to "State_Current"?

  • aleclarson
    aleclarson over 5 years
    That generates one .patch file per commit. The asker wants a single .patch file that contains all commits in the given range.
  • John Kugelman
    John Kugelman over 4 years
    Warning: This produces one file containing multiple separate patches. It doesn't squash the history down as requested in the question. If there are sensitive commits in the middle they'll be exposed.
  • GuyPaddock
    GuyPaddock over 4 years
    How do you specify the start of the commit range, though? It looks like this captures all of the files of the branch in a single commit, going back to the initial commit.
  • Priyanshu
    Priyanshu about 3 years
    If you want to squash multiple commits into a patch then you can squash them by rebasing and then can make the squashed commit as a patch.
  • ThermoX
    ThermoX about 3 years
    Just to clarify (maybe for Windows users only?). This command resulted in an error for me when doing the "git am foo.patch" part. I got a "Patch: format detection failed" error. What worked was to create the patch using the command: git format-patch cc1dde0dd^..6de6d4b06 --output=foo.patch
  • Jordan Bradford
    Jordan Bradford almost 3 years
    @ThermoX Were you using PowerShell? From my testing it seems that If you run the --stdout version of the command from PowerShell you'll get a UTF-16 LE BOM-encoded file with Windows line endings instead of a UTF-8–encoded file with UNIX line endings, and that's probably why the patch doesn't apply cleanly. So use Git Bash or cmd.exe for best results.
  • ThermoX
    ThermoX almost 3 years
    @Jordan Bradford Yes, I was using PowerShell with the posh-git extension. I probably should have mentioned that in my original comment. Looking at the encoding, I am getting UTF-8 for the --output version, while as I am getting UCS-2 LE BOM for the --stdout. When running this under a cmd shell, you are correct. They both come out at UTF-8. However, I then need to use ^^ instead of ^. So I just keep using PowerShell and the --output version, which works fine. But glad to know the reason --stdout wasn't working there.
  • Addison Klinke
    Addison Klinke over 2 years
    For the curious, this is the official git docs for selecting ranges of commits based on .. and ^ syntax
  • Addison Klinke
    Addison Klinke over 2 years
    As explained in this answer, git format-patch may be preferred over git diff since it includes metadata for the changes (i.e. committer identity, timestamps, commit messages, etc)