93

I have looked at various SO answers on using git diff and git revisions (HEAD, ORIG_HEAD, FETCH_HEAD, etc.) and I still haven't found an easy way to list the changes have been made since the beginning of the local branch, or since last rebase.

By easy I mean without having to look up and paste commit SHA or having to count how many commits I want to look back.

git diff origin/master is close, but it refers to remote which may have diverged since I checked out new branch from it.

I would expect something like git diff BASE_HEAD to be available.

...unless there's already a way to do that. Does anyone have the answer?

user776686
  • 7,933
  • 14
  • 71
  • 124
  • 2
    you want to diff against your upstream's mergebase, use @{u} and triple dot syntax. Try `git diff @{u}...HEAD` – Andrew C Apr 22 '15 at 22:55
  • http://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git, lindes answer. you might be interested in other answers too. – guido Apr 22 '15 at 22:57

9 Answers9

82

You can find the branch point using git merge-base. Consider master the mainline and dev the branch whose history you are interested in. To find the point at which dev was branched from master, run:

git merge-base --fork-point master dev

We can now diff dev against this basis:

git diff $(git merge-base --fork-point master dev)..dev

If dev is the current branch this simplifies to:

git diff $(git merge-base --fork-point master)

For more information see the git-merge-base documentation.

frasertweedale
  • 5,424
  • 3
  • 26
  • 38
  • 2
    Note that `git merge-base` returns no output once the `dev` branch has been merged to `master`. For that, see: https://stackoverflow.com/questions/30560256/how-to-get-commit-where-merged-branch-forked-from – Daniel Stevens Sep 02 '18 at 07:16
  • 4
    If your base wasn't `master` this won't work. If you don't remember which branch was the base, then what? – Patrick Parker Sep 24 '19 at 22:59
  • 1
    @PatrickParker, git does not store "which branch came from which", so its not something it can infer on its own. – Guilherme de Lazari Sep 21 '21 at 14:39
62

Use git diff @{u}...HEAD, with three dots.

With two dots, or with HEAD omitted, it will show diffs from changes on both sides.

With three dots, it will only show diffs from changes on your side.

Edit: for people with slightly different needs, you might be interested in git merge-base (note that it has plenty more options than the other answer uses).

o11c
  • 15,265
  • 4
  • 50
  • 75
  • @o11c where to specify branch name with your solution? – jangorecki Aug 21 '15 at 12:08
  • @jangorecki `@{u}` and `HEAD` are two separate "commitish" objects (that can be passed to `git rev-parse`). `@{u}` is short for `HEAD@{u}`, which is usually `master@{u}`. – o11c Aug 24 '15 at 05:43
  • 16
    I think using the upstream could be confusing. Why not just `git diff master...HEAD`? – Kelvin Sep 26 '16 at 18:36
  • @Kelvin Because those are usually the same thing. – o11c Sep 27 '16 at 01:47
  • 3
    What does the `u` in `@{u}` mean? – Tor Klingberg Jul 25 '17 at 12:54
  • 7
    @TorKlingberg It's short for `@{upstream}`, this is all documented in `git rev-parse --help` – o11c Jul 27 '17 at 20:23
  • @Kelvin For me using master makes the diff output include changes made on master since the feature branch was started but that are not on the feature branch yet (i.e., the branch could be rebased). – Taylor D. Edmiston Jul 25 '18 at 16:11
  • 1
    @TaylorEdmiston I tried this but I'm not seeing the issue. The `git diff` man page also indicates you're not supposed to see changes from `master` that were made after the branch point because of the `merge-base`: _"git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"_. Are you sure you're using 3 dots? – Kelvin Jul 25 '18 at 17:57
  • Yep, this was with 3 dots. I don't think it makes a difference but my feature branch I was comparing to was remote, not local. When using `@{u}` as the first branch the diff stat output differs compared to using `master`. – Taylor D. Edmiston Jul 25 '18 at 18:46
  • when I tried this, I got "fatal: no upstream configured for branch" – Patrick Parker Sep 24 '19 at 23:01
  • @PatrickParker in that case, you need to configure an upstream using `git branch --set-upstream-to`. There are other ways to do this at clone or branch creation time. – o11c Sep 24 '19 at 23:43
  • I'm using git 2.17.1 and this produces an empty diff, while it shouldn't. – reinierpost Feb 04 '21 at 16:18
  • 3
    If you use a newer git version, you can simply use `git diff --merge-base ` – Kound Apr 05 '22 at 14:46
26

You can diff the current branch from the branch start point using:

git diff (start point)...

Where (start point) is a branch name, a commit-id, or a tag.

Eg if you're working on a feature branch branched from develop, you can use:

git diff develop...

for all changes on the current branch since the branch point.

This was already mentioned in a comment, but I think it deserves answer status. I don't know what it will do since last rebase.

crimbo
  • 10,308
  • 8
  • 51
  • 55
  • The reverse seems to be useful as well: `git diff ...develop`. It shows what has changed on 'develop' after the branch point. – Brent Bradburn Jul 13 '23 at 14:15
11

For diffs, you want the three-dot notation. If your branch is called dev and it branched from master:

% git diff master...dev

For log, you want the two-dot notation:

% git log master..dev

The revision syntax r1..r2 (with two dots) means "everything reachable from r2 (inclusive) but not reachable from r1 (inclusive)". The normal way to use this is to think of r1 and r2 as specifying a range in a sequence of commits (r1 exclusive, r2 inclusive), so if you have 10 revisions, 3..7 will show you changes 4, 5, 6, and 7. It's {1, 2, 3, 4, 5, 6, 7} minus {1, 2, 3}. But r1 doesn't necessarily have to be an ancestor of r2. Think of it more like a set operation where r1 represents the entire ancestry from r1 backwards, and r2 represents the entire ancestry from r2 backwards, and you're subtracting the first set from the second set.

So then:

git log master..dev

is the entire history of the branch minus the entire history of master. In other words, just the branch.

Lawrence Kesteloot
  • 4,149
  • 2
  • 31
  • 28
4

To diff against the remote master branch:

git diff $(git merge-base HEAD origin/master)..
Harald Nordgren
  • 11,693
  • 6
  • 41
  • 65
4

If you use a newer git version, you can simply use

git diff --merge-base <target_branch>

Which delivers (for me) identical results to currently highest voted answer of:

git diff $(git merge-base --fork-point origin/main)

The command was introduced in Git Version 2.30 as:

"git diff A...B" learned "git diff --merge-base A B", which is a longer short-hand to say the same thing.

So basically it another way of gettings the same result as the currently accepted answer.

Kound
  • 1,835
  • 1
  • 17
  • 30
3

The current solution mentions

Use git diff @{u}...HEAD, with three dots.

But... this is best done with Git 2.28 (Q3 2020).
Before, "git diff" used to take arguments in random and nonsense range notation, e.g. "git diff A..B C ", "git diff A..B C...D", etc., which has been cleaned up.

See commit b7e10b2, commit 8bfcb3a (12 Jun 2020), and commit bafa2d7 (09 Jun 2020) by Chris Torek (chris3torek).
(Merged by Junio C Hamano -- gitster -- in commit 1457886, 25 Jun 2020)

git diff: improve range handling

Signed-off-by: Chris Torek

When git diff is given a symmetric difference A...B, it chooses some merge base from the two specified commits (as documented).

This fails, however, if there is no merge base: instead, you see the differences between A and B, which is certainly not what is expected.

Moreover, if additional revisions are specified on the command line ("git diff A...B C"), the results get a bit weird:

  • If there is a symmetric difference merge base, this is used as the left side of the diff.
    The last final ref is used as the right side.

  • If there is no merge base, the symmetric status is completely lost.
    We will produce a combined diff instead.

Similar weirdness occurs if you use, e.g., "git diff C A...B D". Likewise, using multiple two-dot ranges, or tossing extra revision specifiers into the command line with two-dot ranges, or mixing two and three dot ranges, all produce nonsense.

To avoid all this, add a routine to catch the range cases and verify that that the arguments make sense.

As a side effect, produce a warning showing which merge base is being used when there are multiple choices; die if there is no merge base.

The documentation now includes:

'git diff' [<options>] <commit> [<commit>...] <commit> [--] [<path>...]:

This form is to view the results of a merge commit.

The first listed must be the merge itself; the remaining two or more commits should be its parents.
A convenient way to produce the desired set of revisions is to use the {caret}@ suffix.
For instance, if master names a merge commit, git diff master master^@ gives the same combined diff as git show master.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
1

I wrote an alias in my .gitconfig to solve this task:

[alias]
    # See changes since branching off of main branch
    changes = "!f() { \
        current=$(git rev-parse --abbrev-ref HEAD); \
        main=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'); \
        commit=$(git merge-base --fork-point \"$main\" \"$current\"); \
        git diff \"$commit\"...; \
    }; f"

Line-by-line, this alias:

  1. Defines a shell function, f, which
  2. computes the current branch name,
  3. computes the main branch name (which could be main, master, develop, etc.),
  4. computes the commit from which these two branches diverge, and
  5. runs git diff to see the changes since this commit
Adam Stewart
  • 2,001
  • 1
  • 16
  • 16
-5

In Visual Studio 2017 there is a comfortable way to show diffs:

  1. In Team Explorer -> Branches right click the branch and select View History

View History

  1. In the History - branch control select the commits you want the diff and select Compare Commits

Compare Commits

You get a nice diff overview and you can open the files in compare mode.

Felix Keil
  • 2,344
  • 1
  • 25
  • 27