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

GitPatchSquashGit Squash

Git Problem Overview


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

Git Solutions


Solution 1 - Git

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 - Git

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 - Git

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

git diff master > patch.txt

Solution 4 - Git

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 - Git

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)$

Solution 6 - Git

Easiest way is to use git diff, and add in git log if you want the combined commit message that the squash method would output. For example, to create the patch between commit abcd and 1234:

git diff abcd..1234 > patch.diff
git log abcd..1234 > patchmsg.txt

Then when applying the patch:

git apply patch.diff
git add -A
git reset patch.diff patchmsg.txt
git commit -F patchmsg.txt

Don't forget the --binary argument to git diff when dealing with non-text files, e.g. images or videos.

Solution 7 - Git

Format-patch between two tags:

git checkout <source-tag>
git checkout -b <tmpsquash>
git merge --squash <target-tag>
git commit -a -m "<message>"
git format-patch <source-tag>

Solution 8 - Git

Based on Adam Alexander's answer:

git checkout newlines
## must be rebased to master
git checkout -b temporary
# squash the commits
git rebase -i master
git format-patch master

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionskiphoppyView Question on Stackoverflow
Solution 1 - GitAdam AlexanderView Answer on Stackoverflow
Solution 2 - GitTaryn EastView Answer on Stackoverflow
Solution 3 - GitRob Di MarcoView Answer on Stackoverflow
Solution 4 - GitVonCView Answer on Stackoverflow
Solution 5 - GitrecView Answer on Stackoverflow
Solution 6 - Gitwoojoo666View Answer on Stackoverflow
Solution 7 - GitkashesandrView Answer on Stackoverflow
Solution 8 - GitJulien WView Answer on Stackoverflow