How do you squash commits into one patch with git format-patch?

102,754

Solution 1

I'd recommend doing this on a throwaway branch as follows. If your commits are in the "newlines" branch and you have switched back to your "master" branch already, this should do the trick:

[adam@mbp2600 example (master)]$ git checkout -b tmpsquash
Switched to a new branch "tmpsquash"

[adam@mbp2600 example (tmpsquash)]$ git merge --squash newlines
Updating 4d2de39..b6768b2
Fast forward
Squash commit -- not updating HEAD
 test.txt |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git commit -a -m "My squashed commits"
[tmpsquash]: created 75b0a89: "My squashed commits"
 1 files changed, 2 insertions(+), 0 deletions(-)

[adam@mbp2600 example (tmpsquash)]$ git format-patch master
0001-My-squashed-commits.patch

Solution 2

Just to add one more solution to the pot: If you use this instead:

git format-patch master --stdout > my_new_patch.diff

Then it will still be 8 patches... but they'll all be in a single patchfile and will apply as one with:

git am < my_new_patch.diff

Solution 3

I always use git diff so in your example, something like

git diff master > patch.txt

Solution 4

As you already know, a git format-patch -8 HEAD will give you eight patches.

If you want your 8 commits appear as one, and do not mind rewriting the history of your branch (o-o-X-A-B-C-D-E-F-G-H), you could :

git rebase -i
// squash A, B, C, D, E ,F, G into H

or, and it would be a better solution, replay all your 8 commits from X (the commit before your 8 commits) on a new branch

git branch delivery X
git checkout delivery
git merge --squash master
git format-patch HEAD

That way, you only have one commit on the "delivery" branch, and it represent all your last 8 commits

Solution 5

This is an adaptation of Adam Alexander answer, in case your changes are in master branch. This do the following:

  • Creates a new throwaway branch "tmpsquash" from the point we want (look for the SHA key running "git --log" or with gitg. Select the commit you want to be tmpsquash head, the commits that are after that in master will be the squashed commits).
  • Merges the changes from master to tmpsquash.
  • Commits the squashed changes to tmpsquash.
  • Creates the patch with the squashed commits.
  • Goes back to master branch

laura@rune:~/example (master)$ git branch tmpsquash ba3c498878054e25afc5e22e207d62eb40ff1f38
laura@rune:~/example (master)$ git checkout tmpsquash
Switched to branch 'tmpsquash'
laura@rune:~/example (tmpsquash)$ git merge --squash master
Updating ba3c498..40386b8
Fast-forward
Squash commit -- not updating HEAD

[snip, changed files]

11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git commit -a -m "My squashed commits"
[test2 6127e5c] My squashed commits
11 files changed, 212 insertions(+), 59 deletions(-)
laura@rune:~/example  (tmpsquash)$ git format-patch master
0001-My-squashed-commits.patch
laura@rune:~/example  (tmpsquash)$ git checkout master
Switched to branch 'master'
laura@rune:~/example  (master)$
Share:
102,754

Related videos on Youtube

Yaser Har
Author by

Yaser Har

I am a Perl programmer using Java by day. I am jdavidb on use.perl.org and slashdot.

Updated on January 10, 2021

Comments

  • Yaser Har
    Yaser Har over 3 years

    I've got eight commits on a branch that I'd like to email to some people who aren't git enlightened, yet. So far, everything I do either gives me 8 patch files, or starts giving me patch files for every commit in the branch's history, since the beginning of time. I used git rebase --interactive to squash the commits, but now everything I try gives me zillions of patches from the beginning of time. What am I doing wrong?

    git format-patch master HEAD # yields zillions of patches, even though there's 
                                 # only one commit since master
    
    • VonC
      VonC over 15 years
      I am curious about what method you will end up using amongst the propositions below. Let us know ;)
    • Yaser Har
      Yaser Har over 15 years
      I will use git diff as suggested by Rob Di Marco. But I'm off work for two weeks, having just witnessed the birth of my second baby girl last night, so it'll be awhile before I use it! :)
    • schoetbi
      schoetbi over 13 years
      I would love to see git format-patch --squash master HEAD
    • Konrad Kleine
      Konrad Kleine almost 10 years
      Try master..HEAD to specifiy a rev-range.
  • sebnow
    sebnow over 15 years
    This is what I use when I want to keep the history locally (in case I need to edit the patch). Otherwise I just use rebase -i and squash the commits.
  • mcepl
    mcepl almost 13 years
    Except than you loose all commit messages and metadata. Beauty of git format-patch is that it is possible to reconstruct whole branch from a set of patches.
  • gumik
    gumik almost 12 years
    I like this solution. It is worth notice that it may create sometimes a lot bigger patch than method described by @Adam Alexander. This is because some files may be edited more than once through commits. This method treats each commit separately, even if some file was reverted. But most of the time this is not an issue.
  • Sebastian
    Sebastian over 10 years
    for me, it worked more reliable with git comit -m "My squashed commits" otherwise it would add other untracked files
  • woojoo666
    woojoo666 almost 9 years
    the create-branch-and-squash method has the benefit of combining all the commit messages into one, but this method is much faster if you want to write your own commit message
  • woojoo666
    woojoo666 almost 9 years
    actually, a combined message can be done using git log, see my answer for an example
  • Stunner
    Stunner over 8 years
    git merge master merely does a fast forward and doesn't squash commits into one. Change to git merge --squash master to get all commits squashed and visible in the staged area. Your flow will work with this change. (I'm using git version 2.1.0.)
  • Santiago Villafuerte
    Santiago Villafuerte over 8 years
    Nice option, but consider that 'git diff' cannot include binary differences (maybe there's an option to do it).
  • ivan_pozdeev
    ivan_pozdeev about 8 years
    Making changes in master is an anti-pattern if you won't be pushing them to remote yourself. And if you will, you probably don't need to generate patch files for them.
  • Jorge Orpinel Pérez
    Jorge Orpinel Pérez about 7 years
    This option is great if you're trying to avoid merging! (e.g. you want to skip some commits). You can still git rebase -i ... and squash them all down to one.
  • Berry M.
    Berry M. over 6 years
    Additonally, you can switch to a specific commit instead of the master and do this to create a patch from commit to commit: git checkout 775ec2a && git checkout -b patch && git merge --squash branchname