0

In certain scenarios git format-patch will not include merge commit or will generate patches in such a way that they cannnot be cleanly applied. In these scenarios I’d like to use git diff to generate a squashed patch in email/mbox format and also have it squash the commit messages into one so at least some history is preserved. Is there a convenient way to do this?

tesserakt
  • 3,231
  • 4
  • 27
  • 40

1 Answers1

2

You say certain scenarios, but in fact, git format-patch will never format a merge commit, because it doesn't know how to do so. It also won't format an empty patch (which may explain Git's relatively strong insistence on not making "empty", i.e., no-change, commits). But, yes, if your commit range includes a merge (one or more, really), you are setting yourself up for trouble.

In these scenarios I’d like to use git diff to generate a squashed patch in email/mbox format and also have it squash the commit messages into one so at least some history is preserved. Is there a convenient way to do this?

The short answer is no, because it's never obvious—at least in a mechanical sense—what to do here.

The best—at least, best built-in—way to preserve such commits and transmit them across a network gap that doesn't allow git fetch or git push is to turn them into a Git bundle. A bundle is, in effect, half of a git fetch or git push operation. You can send the bundle to another computer through any transmission mechanism you like, then, on the other computer, use git fetch to bring its commits into your repository at the other end. See also Why can't I git bundle all parents?

Failing that, you could attempt to use git cherry-pick, or the command that runs it for you, git rebase (probably in interactive mode), to turn your string of commits-including-merges into a more linear string of commits. Because it's never obvious what to do around the merge points, you'll have to handle that yourself, some other way. The resulting series of linear commits can then be fed to git format-patch.

If you're willing to turn everything into one single massive commit, you can just run git diff on the two endpoints (a starting commit and an ending one) and also run git log to gather up the log messages. Formatting those into a mailbox-style message is pretty trivial. Or, if you want, you can use git commit-tree to write a commit that uses the final tree but sets its parent to the starting point you like, then use git format-patch to format that single commit. Since git commit-tree reads stdin for its commit message, you can use git log, perhaps with --pretty=format:%B, to gather up all the commit messages from the commits you're combining.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Yeah `git diff` is the way I'll need to go. Thanks for the tip at the end on how to bring three tools together to achieve what I want. I'll look into it. – tesserakt Feb 24 '19 at 18:29