597

I have an old branch, which I would like to delete. However, before doing so, I want to check that all commits made to this branch were at some point merged into some other branch. Thus, I'd like to see all commits made to my current branch which have not been applied to any other branch [or, if this is not possible without some scripting, how does one see all commits in one branch which have not been applied to another given branch?].

Alexander Oh
  • 24,223
  • 14
  • 73
  • 76
sircolinton
  • 6,536
  • 3
  • 21
  • 19

10 Answers10

728

To see a list of which commits are on one branch but not another, use git log:

git log --no-merges oldbranch ^newbranch

...that is, show commit logs for all commits on oldbranch that are not on newbranch. You can list multiple branches to include and exclude, e.g.

git log  --no-merges oldbranch1 oldbranch2 ^newbranch1 ^newbranch2

Note: on Windows command prompt (not Powershell) ^ is an escape key, so it needs to be escaped with another ^:

git log --no-merges oldbranch ^^newbranch
Andrew Spencer
  • 15,164
  • 4
  • 29
  • 48
jimmyorr
  • 11,178
  • 7
  • 30
  • 21
  • 2
    I found it looking for git compare commits of two branches. – User May 06 '13 at 08:53
  • 41
    This is exactly what I was looking for. But, using `^` as a prefix here confused me. In this context it means exclude that branch. Using `^` as a suffix would be a relative reference to the parent commit of that branch. – Joe Flynn Jul 18 '13 at 16:38
  • 4
    very useful thanks. I'm curious, why is the --no-merges flag necessary? Surely one wants to see those commits also? – Max MacLeod Aug 01 '13 at 08:17
  • Perfect for when you have this error: "error: The branch 'xxxxx' is not fully merged." Thank you ! – qwertzguy Sep 17 '13 at 20:25
  • 2
    Would like to use gitk with this? Simply use `gitk oldbranch ^newbranch --no-merges` (Tested with git 1.8.1.1). Side note, for me `^` means inclusive HEAD commit of branch `newbranch`. – Matt Dec 24 '13 at 16:53
  • This is fantastic. It's really useful for writing changelogs when pushing a release. Thanks! :) – mkgrunder Mar 15 '14 at 16:41
  • 1
    Great option! Is there a way to exclude commits which are cherry-picked? – Nazarii Gudzovatyi Oct 24 '14 at 09:21
  • Does `git log oldbranch ^newbranch1 ^newbranch2` show commits that are in neither of the two new branches or not in at least one of them? – Miserable Variable Jan 09 '15 at 05:24
  • 1
    Git is versatile! Thanks a lot for this solution. I use this at all points that I need to squash commits and merge branches! – IcyFlame Apr 06 '15 at 08:50
  • 2
    @NazariiGudzovatyi - yes, there is: "-cherry-pick". There is a HUGE number of options for log on the [documentation page](http://git-scm.com/docs/git-log) – romeara May 22 '15 at 15:30
  • 1
    Is `oldbranch` the same as "one branch", or the same as "another branch?" Could you use the same phrase in your command line as in your text? Thanks! – jpaugh Mar 11 '16 at 15:07
  • 4
    Thanks @jimmyor, As a side note I didn't need ^^ in windows when using PoshGit in PowerShell. I only need ^ – TheLukeMcCarthy Aug 09 '16 at 04:24
  • When running `git log branch1 ^branch2 --no-merges` with git 2.12.2, I get `fatal: bad flag '--no-merges' used after filename`, and leaving out `--no-merges` showed all commit history for branch1. [Xuan's answer](http://stackoverflow.com/a/21934460/1824868) worked for me. – jayhendren Apr 25 '17 at 16:07
  • @jayhendren I don't get any error when running git log --no-merges with git 2.13.0 – jimmyorr Apr 26 '17 at 19:06
  • May be something in my git config, then. I ran `git log branch1 ^branch2 --no-merges` on a different system with the same version of git and didn't have any issues. – jayhendren Apr 26 '17 at 19:32
  • 1
    Turns out it was my shell treating the carat character specially. – jayhendren Apr 27 '17 at 21:48
  • 17
    This is a great answer, but `oldbranch` and `newbranch` are (to me) somewhat confusingly named. I'd suggest something like `branch_withcommits` and `branch_missingcommits`, even though it's a little verbose, because it's immediately clear what the command is looking for. I'd make the edit myself, but that feels like a pretty major alteration to make preemptively. Would you mind if I make this change (or could you make it yourself)? – Kyle Strand Jun 01 '17 at 16:51
  • 6
    Or, to clarify the meaning of `^`, we could replace `^newbranch` with `^excludebranch`. – Kyle Strand Jun 01 '17 at 17:58
  • 1
    A variant of this answer helped me solve the opposite problem: I needed to see all commits on any branch except master (i.e., anything not merged in yet). `git log --all ^master` solved it beautifully. – joanis Jan 22 '21 at 20:24
  • I needed to **count** the commits too, and couldn't figure it out for a while, so here's how to do that (my answer I just added, now that I figured it out): https://stackoverflow.com/a/66201217/4561887. – Gabriel Staples Feb 14 '21 at 23:39
  • thought it useful to mention that `^` doesn't need escaping on Windows _per se_ (e.g. Powershell doesn't need it), but only in `cmd` – Andrew Spencer Jul 20 '21 at 08:45
  • Maybe helpful to some: What I'm always looking for with this is "Show me all of the commits in my current branch that aren't in my base branch." Since `HEAD` is always your current branch, you can always just do `git log --no-merges HEAD ^your-base-branch`. (In my case, the base branch is almost always `origin/develop`.) – kael Jul 24 '23 at 16:25
360

You probably just want

git branch --contains branch-to-delete

This will list all branches which contain the commits from "branch-to-delete". If it reports more than just "branch-to-delete", the branch has been merged.

Your alternatives are really just rev-list syntax things. e.g. git log one-branch..another-branch shows everything that one-branch needs to have everything another-branch has.

You may also be interested in git show-branch as a way to see what's where.

sleske
  • 81,358
  • 34
  • 189
  • 227
Dustin
  • 89,080
  • 21
  • 111
  • 133
  • 2
    +1. See also http://stackoverflow.com/questions/850607/difference-in-git-log-origin-master-vs-git-log-origin-master – VonC Nov 10 '09 at 20:30
  • 1
    The line 'If it reports something, the branch has merged' can be misinterpreted: if `git branch --contains some-branch` only returns `some-branch`, then it does return something, but it has *not* been merged. – Confusion Mar 21 '12 at 16:26
  • 5
    Note that `git log foo..bar` will show the commits between bar's latest and foo's latest, but not other commits missing from further back in time. To see everything in bar but not in foo, you should use @jimmyorr's solution. – Paul A Jungwirth Jul 10 '14 at 16:34
125

To show the commits in oldbranch but not in newbranch:

git log newbranch..oldbranch

To show the diff by these commits (note there are three dots):

git diff newbranch...oldbranch

Here is the doc with a diagram illustration https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#Commit-Ranges

Xuan
  • 5,255
  • 1
  • 34
  • 30
  • 1
    See [Paul A Jungwirth's comment](http://stackoverflow.com/questions/1710894/using-git-show-all-commits-that-are-in-one-branch-but-not-the-others#comment38269236_1710951) above. It seems this will miss out on some old commits? – Miserable Variable Jan 09 '15 at 05:22
  • 2
    I'm not sure what old commits mean. The double dots basically asks Git to resolve a range of commits that are reachable from one commit but aren’t reachable from another. Here is the doc with a digram illustration http://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#Commit-Ranges – Xuan Jan 09 '15 at 09:22
  • 1
    and if we are on either `newbranch` or `oldbranch`, we can do `git log ..oldbranch` or `git log newbranch..` respectively – YakovL Feb 05 '19 at 19:17
  • 1
    jimmyorr's solution didn't work for me, but this one did thanks to the two dots `..` between the refs' names. I also used the `--cherry-pick` option to hide commits that are present on both branches but have a different hash because they were cherry-picked from one branch to the other. – Mickäel A. Jun 02 '20 at 13:16
  • The problem with this one is that it only shows (besides new branch and old branch) the commits that were made chronologically between the two branches. If some commits on the newbranch were made before oldbranch was created, they won't show up. – MrMas May 06 '21 at 18:08
  • @xuan : This command is working fine on `git 2.30.1` but failing on `git 2.17.1`. Any other way to get above result on the older git. For some reason, I can't update git version on the prod. – Pramod Sep 20 '21 at 05:24
  • @Pramod Are you sure it's a version issue? This answer has been around since 2014, but 2.17.1 was out in 2018 https://github.com/git/git/releases?after=v2.17.1 – Xuan Sep 21 '21 at 13:08
  • @xuan : actually this is the issue of jenkins, you are right, this is not because of version.. – Pramod Sep 22 '21 at 13:10
77

For those still looking for a simple answer, check out git cherry. It compares actual diffs instead of commit hashes. That means it accommodates commits that have been cherry picked or rebased.

First checkout the branch you want to delete:

git checkout [branch-to-delete]

then use git cherry to compare it to your main development branch:

git cherry -v master

Example output:

+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message
- 85867e38712de930864c5edb7856342e1358b2a0 Yet another message

Note: The -v flag is to include the commit message along with the SHA hash.

Lines with the '+' in front are in the branch-to-delete, but not the master branch. Those with a '-' in front have an equivalent commit in master.

For JUST the commits that aren't in master, combine cherry pick with grep:

git cherry -v master | grep "^\+"

Example output:

+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message
Tim S
  • 5,023
  • 1
  • 34
  • 34
  • I've tried this, but it still reports that there are many commits in the fb (feature branch) that aren't in the mb (main branch). However, if I'm in the fb and do a git diff mb, I see no differences. I did use rebase and squashed everything. I'm nearly certain this is why, but I just want to be be certain. If this is the case, then I'm going to avoid squashing if at all possible; I'm in the "no lost info camp." I wonder if it would be possible to add a log display mode that can display merges as if they were rebases to keep the history clean and yet lose no info. – Outis Von Nemo Jun 29 '16 at 14:57
  • 2
    Not sure of your exact scenario here, but if you've squashed multiple commits together into one and are comparing that to another branch where the commits are separate, this definitely won't work. In that case, you may just want to use the unix `diff` utility to compare the various files. Or, you could create a temporary branch and squash all the commits in that similar to what you did with the original branch, and then use this, which I think would work. – Tim S Jul 01 '16 at 00:04
52

While some of the answers posted here will help find what you seek, the following sub-command of git branch is a more suitable solution for your task.

--merged is used to find all branches which can be safely deleted, since those branches are fully contained by HEAD.

While in master one could run the command to enumerate the branches one could safely remove, like so:

git branch --merged
  develop
  fpg_download_links
* master
  master_merge_static

# Delete local and remote tracking branches you don't want
git branch -d fpg_download_links
git push origin :fpg_download_links
git branch -d master_merge_static
git push origin :master_merge_static

# There is also a flag to specify remote branches in the output
git branch --remotes --merged
Freddie
  • 1,019
  • 10
  • 11
21

jimmyorr's answer does not work on Windows. it helps to use --not instead of ^ like so:

git log oldbranch --not newbranch --no-merges
Community
  • 1
  • 1
sebeck
  • 270
  • 2
  • 5
  • 7
    That is correct, +1. Note though that `^` is supported on Windows, but needs to be escaped, which, in Windows, is (another) `^`: `git log oldbranch ^^newbranch --no-merges`. – VonC Jun 18 '15 at 09:42
  • 5
    To be specific, it does work in Windows in Powershell console, but require extra "^" in CMD. – Rod Sep 07 '15 at 05:39
8

If it is one (single) branch that you need to check, for example if you want that branch 'B' is fully merged into branch 'A', you can simply do the following:

$ git checkout A
$ git branch -d B

git branch -d <branchname> has the safety that "The branch must be fully merged in HEAD."

Caution: this actually deletes the branch B if it is merged into A.

YakovL
  • 7,557
  • 12
  • 62
  • 102
Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
4

I'd like to count the commits too, so here's how to do that:

Count how many commits are on the current branch (HEAD), but NOT on master:

git log --oneline ^master HEAD | wc -l

wc -l means "word count"--count the number of 'l'ines.

And of course to see the whole log messages, as other answers have given:

git log ^master HEAD

...or in a condensed --oneline form:

git log --oneline ^master HEAD

If you don't want to count merge commits either, you can exclude those with --no-merges:

git log --oneline --no-merges ^master HEAD | wc -l

etc.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
3

You can use this simple script to see commits that are not merged

#!/bin/bash
# Show commits that exists only on branch and not in current
# Usage:
#   git branch-notmerge <branchname>
#
# Setup git alias
#   git config alias.branch-notmerge [path/to/this/script]
grep -Fvf <(git log --pretty=format:'%H - %s') <(git log $1 --pretty=format:'%H - %s')

You can use also tool git-wtf that will display state of branches

manRo
  • 1,455
  • 1
  • 14
  • 19
3

Show commits and commit contents from other-branch that are not in your current branch:

git show @..other-branch

Additionally you can apply the commits from other-branch directly to your current branch:

git cherry-pick @..other-branch
Pete B
  • 1,709
  • 18
  • 11