Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can "git rev-list --all --count" ever go down?

Tags:

git

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.)

like image 489
Robert Atkins Avatar asked Jan 07 '23 12:01

Robert Atkins


2 Answers

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 DAG
  • git rev-list then follows every commit object to all of its parents, all the way back to the root commit(s)
  • and --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.

Summary (jump here if "tl;dr")

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.

like image 74
torek Avatar answered Jan 14 '23 22:01

torek


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.

like image 43
Seth Johnson Avatar answered Jan 14 '23 21:01

Seth Johnson