74

How can I find the number of commits between two commitishes in git?

Additionally, is there some way that I could do the same with any project on GitHub (using the UI, not the API)?

2
  • If you have two commits you have their revision number no? Subtract the two? I may be oversimplifying or not understanding the question. Commented Aug 13, 2015 at 20:40
  • 1
    @CarlosBribiescas in git, a commitish isn't necessarily a commit ID. Also, even if you have the commit IDs, in git, commit IDs are hashes (ff3823ac, 554fbae3, etc.). Commented Aug 13, 2015 at 20:42

4 Answers 4

79

Before I give you an answer, consider this commit graph:

        o -----------
       /             \
... - A - o - o - o - B
       \         /
        o ----- o

Each o represents a commit, as do A and B (they're just letters to let us talk about specific commits). How many commits are there between commits A and B?

That said, in more linear cases, just use git rev-list --count A..B and then decide what you mean by "between" (does it include B and exclude A? that's how git rev-list --count will behave). In branchy cases like this, you'll get all the commits down all the branches; add --first-parent, for instance, to follow just the "main line".

(You also mentioned "commitish", suggesting that we might have annotated tags. That won't affect the output from git rev-list, which only counts specific commits.)


Edit: Since git rev-list --count A..B includes commit B (while omitting commit A), and you want to exclude both end-points, you need to subtract one. In modern shells you can do this with shell arithmetic:

count=$(($(git rev-list --count A..B) - 1))

For instance:

$ x=$(($(git rev-list --count HEAD~3..HEAD) - 1))
$ echo $x
2

(this particular repo has a very linear graph structure, so there are no branches here and there are two commits "between" the tip and three-behind-the-tip). Note, however, that this will produce -1 if A and B identify the same commit:

$ x=$(($(git rev-list --count HEAD..HEAD) - 1))
$ echo $x
-1

so you might want to check that first:

count=$(git rev-list --count $start..$end)
if [ $count -eq 0 ]; then
    ... possible error: start and end are the same commit ...
else
    count=$((count - 1))
fi
Sign up to request clarification or add additional context in comments.

5 Comments

What do you do if you want to get the total across all of the branches added up? Also, by between, I was thinking of "exclusive" (excludes A & B).
The git rev-list command (try it without --count) walks the graph, printing the SHA-1 of every commit you select. The A..B notation means "select every commit reachable starting from B and working back through all parent commits, but then exclude every commit reachable by starting from A and working back", so if you want all of them, you're in great shape, because that's what you get. Meanwhile, since rev-list includes A itself, subtract one.
could you put the comment in your answer along with a one liner that also subtracts one (perhaps pipe the result into | xargs expr -1 +) and then I'll mark it as correct
Done. Also I fixed the remark about which commit is included in the revisions walked (it's B, not A, that gets counted).
Does this guarantee that A is a parent of B? What if A is in another branch, not merged yet... or a descendant of B?
55
$ git log 375a1..58b20 --pretty=oneline | wc -l

Specify your start commit followed by your end commit, and then count the lines. That should be the count of commits between those two commit ranges. Use the --pretty=oneline formatting so that each commit takes up a single line.

Note that using two dots (375a1..58b20) is different than using three dots (375a1...58b20); see What are the differences between double-dot “..” and triple-dot “…” in Git commit ranges? for more information about this and to figure out which one you want to use.

As for the GUI in GitHub, I don't know of a way to accomplish this same task. But that should be trivial, as the above is the possible way to do it directly using Git and Bash.

4 Comments

It requires two dots or three dots between the commit id's in the above command?
This was probably just copied over from here: gal.steinitz.com/blog/2013/07/27/…
it's worth reading the comments to @kghbln's comment link for details about order of first and second commits, and an option that doesn't rely on wc (namely git rev-list [newer] ^[older] --count)
With two dots, I get nothing. With three dots, it works.
9

Get the number of commits:

git rev-list newer ^older --pretty=oneline --count

Use revision numbers or SHAs:

git rev-list db8fb95e6256bd52a668bae82d8b5a73152869fa ^1aeae117c58c173fee9cb3550297498142887aa5 --pretty=oneline --count
  • [newer] and [older] can be SHA’s, branches or tags.
  • Important: If you have a complicated git graph you should read @torek 's excellent answer.
  • Credit goes to @matt wilkie in his comment and the original source.

Comments

1

commit ranges can fail on a broken repo:

$ git rev-list --count b00aa8ded74..master
error: Could not read 29026cc404895cc9f9afa55c4e2d53b7a4a5a319
fatal: revision walk setup failed

$ git log --oneline b00aa8ded74..master | wc -l
error: Could not read 29026cc404895cc9f9afa55c4e2d53b7a4a5a319
fatal: revision walk setup failed

alternative: git log and grep

depth=$(git log --format=%H $rev2 | grep -m1 -n -x $rev1 | cut -d: -f1)

grep -m1 will stop git log after the first match, so there is no error

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.