Will there ever be a case where the output of git rev-list --all --count
will go down if executed at a later date, from any branch of the same repository?
(I want to use it as a build number that will monotonically increase across all branches.)
It is possible depending on certain conditions that you could simply avoid:
--all
finds every reference in refs/
(see git for-each-ref
as well) to get starting-points into the commit DAGgit rev-list
then follows every commit object to all of its parents, all the way back to the root commit(s)--count
prints the number of commits that would have been printed without --count
.This means the question is equivalent to ‘how could one reduce the number of commits visited in this tree traversal?’ and the answer to that is to remove commits from the repository, or even just remove some references that make some of those commits reachable.
For instance, we can start by creating a "raise the count" reference; let's make it a branch to make subsequently raising the count easy as well:
$ git checkout -b raise-the-count
Now let's add a bunch of commits:
$ for i in $(jot 10); do git commit -m "dummy commit $i" --allow-empty; done
The --count
we get now, with this raise-the-count
branch present, is 10 higher than it was before. Now we delete the branch label:
$ git checkout master; git branch -D raise-the-count
and the --count
we get drops back those same 10 commits.
Removing commits is very hard (it amounts to replacing every commit "after" the removed commit; it's the same problem as removing a sensitive file; git filter-branch
will let you do it but it's painful) but deleting a branch—which is recoverable for a while via reflogs—is not very hard and eventually commits that are only on that branch will be garbage-collected.
The same rules apply to all other references (mostly tags and "notes"), so if you impose the rule "never delete anything" upon yourself, and stick to it, you will get a non-decreasing --count
.
The accepted answer is incomplete; it doesn't account for grafts
, replacement objects, or shallow clones. Consider the following example, where a 10-commit history only looks like a 3-commit history when it's cloned using --depth 3
:
$ git init temp
Initialized empty Git repository in /rnsdhpc/code/src/temp/.git/
$ cd temp
$ for i in $(jot 10); do git commit -m "dummy commit $i" --allow-empty; done
[master (root-commit) 32cc222] dummy commit 1
[master a9c1d91] dummy commit 2
[master 3ab734f] dummy commit 3
[master 1d7c4f8] dummy commit 4
[master 74c6116] dummy commit 5
[master 447d696] dummy commit 6
[master a9cf900] dummy commit 7
[master 7cc0a16] dummy commit 8
[master 6a43b81] dummy commit 9
[master 4dbcdc0] dummy commit 10
$ git rev-list --all --count
10
$ cd ..
$ git clone --depth 3 file://$PWD/temp temp2
Cloning into 'temp2'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (4/4), done.
Resolving deltas: 100% (2/2), done.
$ cd temp2
$ git rev-list --all --count
3
$ git log --oneline -3
4dbcdc0 (HEAD -> master, origin/master, origin/HEAD) dummy commit 10
6a43b81 dummy commit 9
7cc0a16 (grafted) dummy commit 8
I've encountered this unexpected behavior when using the Spack package manager to install my software, which uses git --no-replace-objects rev-list --count
to save a revision number. Alas, the revision number always appears as 1 because Spack uses a shallow clone.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With