Hacker News new | past | comments | ask | show | jobs | submit login

The article talks about eight-character prefixes later in the article, but Git short refs actually use seven-character prefixes when there is no collision on that (and that’s what’s shown earlier in the article). So you can divide time by 16.

For me on a Ryzen 5800HS laptop, lucky_commit generally takes 11–12 seconds. I’m fine with spending that much per commit when publishing. The three minutes eight-character prefixes would require, not quite so much.




I left some details out of the post to make it shorter.

What I’m actually is doing is generating a 7-digit incremental number followed by a fixed 0. Some UIs show 7 characters and some show 8, this felt like a nice compromise. Plus it’s easier to distinguish between the prefix and the suffix when looking at the full SHA when they are always separated by a 0.


Git hasn't used "seven-character prefixes when there are no collisions" in a long time.

It's a combination of the "repo size" (as in, estimated number of objects) and a hard floor of seven characters.

You can see this by running "git log --oneline=7" on any non-trivially sized repository (e.g. linux.git). There's plenty of hashes that uniquely abbreviate to 7 characters, but they're currently all shown with 12 by default.


There may be some extra trigger that causes it to go beyond seven for everything, I don’t know (never worked on a repository anywhere near that large), but there’s certainly still at least some form of collision logic in there (and this is why I said what I said, because I’ve used lucky_commit enough to experience it):

  $ git init x
  Initialized empty Git repository in /tmp/x/.git/

  $ cd x

  $ git commit --allow-empty -m one
  [master (root-commit) 4144321] one

  $ git log --oneline
  4144321 (HEAD -> master) one

  $ lucky_commit

  $ git log --oneline
  0000000 (HEAD -> master) one

  $ git commit --amend --no-edit --reset-author --allow-empty
  [master 3430e13] one

  $ git log --oneline
  3430e13 (HEAD -> master) one

  $ lucky_commit

  $ git log --oneline
  0000000f (HEAD -> master) one

  $ git reflog --oneline
  0000000f (HEAD -> master) HEAD@{0}: amend with lucky_commit
  3430e13 HEAD@{1}: commit (amend): one
  00000005 HEAD@{2}: amend with lucky_commit
  4144321 HEAD@{3}: commit (initial): one

  $ git reflog expire --expire=now --all

  $ git reflog --oneline

  $ git log --oneline
  0000000f (HEAD -> master) one

  $ git gc --aggressive --prune=now
  Enumerating objects: 2, done.
  Counting objects: 100% (2/2), done.
  Writing objects: 100% (2/2), done.
  Total 2 (delta 0), reused 0 (delta 0), pack-reused 0

  $ git log --oneline
  0000000 (HEAD -> master) one


Yes, there's also a collision check, but it's not truncating to 7 characters and adding as needed to get past collisions. Rather it's truncating to N and then adding as needed. N=7 for a new repository, but it'll relatively quickly bump that to 8, then 9 etc

You don't need a very large repository to start bumping it up to 8 etc. E.g. my local redis.git is 9, some local few-thousand commit (partially automated) that I've only ever added to are at 8 etc.

This changed in v2.11 released in late 2016[1], but because the observable default on a new repository is 7 the "it's 7 unless collisions" has persisted in various places online.

All of which is to say that if you brute-force the first commit to be 0000001..., it'll start being displayed as <that><x>, where <x> is a random 0..9a..f character, unless you brute force to 8, 9 etc.

1. https://github.com/git/git/commit/e6c587c733b4634030b353f402...




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: