TL;DR: if you're looking for something like an interdiff, consider git range-diff.
Long
If I understand correctly, it seems git format-patch only emits real commits (could be stashed) but it will not try to calculate interdiff.
This is correct, but may be coming from some wrong assumptions.
In particular, git format-patch
is a method of turning a commit—or a whole chain of commits—into something that will survive email. Whoever gets the patch can use git am
to create an equivalent commit, preserving most of the metadata and the git patch-id
.1
Since this is aimed at preserving a chain of commits, format-patch looks specifically at a single chain of commits. The x1..x2
syntax you used is allowed, but when giving it a single revision, that's treated as a since specifier—that is, git format-patch X
means git format-patch X..HEAD
.
Note that in this kind of revision range—A..B
for any valid specifiers A
and B
; see the gitrevisions documentation for more detail—commit B
acts as a positive reference and is normally included in the selected commits, but A
is a negative reference, as in ^A
, and is always excluded. Hence if A
and B
name the same commit, B
winds up being excluded too. However, you can exclude a commit that normally wouldn't appear anyway. In particular, you have created this situation:
I <-- x1
/
...--H <-- master
\
J <-- x2
such that the commits selected by x1..x2
are always just commit J
, and the commits selected by x2..x1
are always just commit I
—the same set you'd get with master..x2
and master..x1
respectively.
(Note: the -number
option to git format-patch
forces a change in behavior when given a single commit specifier, instead of a range. It doesn't seem to have any effect when using a range specifier.)
The git diff
command, however, does not obey these rules. Normally, a range A..B
means all commits reachable from B
, excluding all commits reachable from A
, which is what we saw above with the master
/x1
/x2
fork. But git diff A..B
just means git diff A B
. Git simply extracts commit A
to use as the left side, and extracts commit B
to use as the right side, and compares them. There is no interdiff here either, nor any attempt to reach back to the common commit on master
.
The git diff
command has a special interpretation for the three-dot range syntax too: git diff A...B
means find a merge base between A
and B
, then compare that to commit B
. This is also not any kind of interdiff—git diff
just doesn't do that at all.
1The committer and committer-date are, by default, new when using git am
. However, you can also add --committer-date-is-author-date
. If you do this and you set things up so that your committer name matches the original committer name, and apply it to the right starting commit, you'll even get a commit that has the same hash ID, provided the original commit has the same author and committer dates. That is, with a little effort, sometimes an emailed patch can result in a bit-for-bit identical commit, as if you had used git bundle
or similar.