diff ... as compared to what?
There is no such thing as a "diff of a branch". There are only diffs of commits.1 Pick any two commits and you can compare them. But a branch ... well, see What exactly do we mean by "branch"? A branch is not two commits. A branch name can select one commit, or you can use a branch name in conjunction with something else to select many commits. But one commit is not enough, and many commits is too many. You must pick exactly two commits.
Note that git diff branch1 branch2
and git diff branch1..branch2
mean exactly the same thing: translate the name branch1
to one specific commit, and translate the name branch2
to one specific commit, and then diff those two specific commits. Again, see What exactly do we mean by "branch"?
1You can also diff a commit against your work-tree, or against your index; and you can diff your index against your work-tree. Besides these, there are specialized forms of diffs to look at just one file, even one outside a Git repository; and you can have Git compute several different diffs, then combine them into a single combined diff. The combined diff, however, is designed to be used only with merge commits, and diffs the final merged result against each parent. It's not useful for viewing many arbitrary commits, only for checking the final result of a merge.
After the edit
You may be able to get what you want—but there isn't really a "parent commit of the branch" either. Consider, for instance, this graph fragment:
...--o--A--o--o--o <-- br1
\
o--B--o <-- br2
\
o--o <-- feature
The newest commit of each branch is the right-most o
, and each commit connects back to an earlier parent commit. (These connections are stored internally as those big ugly SHA-1 hash IDs, with each commit saving its parent IDs. Parents don't know their children, because the children don't exist yet when the parents are made, and once made, no commit can ever be changed. So the children know their parents, but not vice versa.)
What is the "parent" commit of feature
? Is it commit A
or commit B
? (It's probably not any of the remaining commits, which is why I only gave specific one-letter names to those two.) Or:
...--A--o--o--B--o--C--o <-- devel
\ / /
o----o--o--D--E--F <-- feat
Here feat
has been repeatedly brought into devel
, at points B
and C
. It can be brought in again; if so, that will introduce the changes from E
and F
with respect to D
. But it seems obvious from this graph drawing that feat
originally "grew out of" commit A
, so is A
the parent you want, or is it more related to B
or C
? If it's not C
, you will have a problem, because Git doesn't record A
or B
independently anywhere (it doesn't record C
independently either but we have an easy way to find, well, not C
but D
; but D
is perhaps what you want). Moreover, while it seems obvious that A
is the starting point, that's merely because of the way I drew this graph fragment. A different view might make it equally clear that there is an earlier starting point—and in fact, there just isn't a real "starting point" unless you specifically record one (tags are ideal for this purpose).
Merge bases: how to find A
or B
in the first diagram and D
in the second
Git supports—because it must, because git merge
needs it—the concept of a merge base. The merge base of two commits is easy(ish) to see if you draw a graph of the commits like we did above. The commits are usually two different branch tip commits (and if not, we just pretend they are). You simply start at each tip, then follow its the connecting lines leftwards / backwards. Eventually, this needs to "meet up" at some common commit. That's the first commit that's on both of these branches, and that commit is the merge base.
Here's that first diagram again:
...--o--A--o--o--o <-- br1
\
o--B--o <-- br2
\
o--o <-- feature
Starting at the tip of feature
and the tip of br1
, check to see if you have a common commit yet. No—so look back a bit. Looking back on br1
there's a point where something comes in, at commit A
. Can we get to commit A
from feature
? Yes: we start at the tip of feature
and go back two steps to B
, then go back two more steps to A
. That's the first shared commit—the first commit that's on both br1
and feature
. So that's the merge base.
The merge base of br1
and br2
is likewise commit A
, and the merge base of br2
and feature
is commit B
. Hence, given two branch names—or even just two commit IDs—we can find their merge base.
The merge base for the second diagram is trickier. Commit C
is a merge commit. This means it has two parent arrows, one to a commit that is only on branch devel
, and one to commit D
on feat
. (Note, by the way, that this means we made commit D
before we made commit C
. The graph lettering here is a bit misleading! Sorry about that.) This makes commit D
reachable from the tip of devel
, so that commit D
is on both branches—and that, plus its "most close"-ness to the branch tips, makes commit D
the merge base of devel
and feat
.
git merge-base
The command git merge-base A B
will find the merge base of the two named branches. Ideally, this will be a single commit ID. (It could be no ID, if the two branches literally have nothing in common—they have unrelated histories; this is rare—or there could be more than one merge base, in which case git merge-base
just picks one, somewhat arbitrarily. It's hard to get multiple merge bases, though, so generally you don't have to worry about this.)
Hence, if the goal at this point is to find commit D
in the second diagram, and diff that against the tip of feat
, you can do:
git merge-base devel feat # and note the commit ID
git diff <hash> feat
Because this is a relatively common thing to want, git diff
has it built in. The syntax for this borrows the three-dot syntax that for every other Git command means something else:
git diff devel...feat
Note the three (not two) dots between the two names. For git diff
, and only for git diff
, this means "find the merge base between these two branch tip commits, and then diff it against the second commit."
With the first diagram, you can pick br1
or br2
to find either A
or B
and compare that to the tip of feature
:
git diff br1...feature
for instance.