How can I find an unreachable commit hash in a GIT repository by keywords?
When you delete a branch, you also delete its reflog. There's a separate reflog for HEAD
that will retain a reference to commits that were on the deleted branch, but only if you've had them checked-out.
The difference between --lost-found
and --unreachable
is subtle:1 see the git glossary, and/or the illustration below. In general, using --lost-found
and/or --unreachable
will find such commit(s) (and with --lost-found
, also write IDs into the .git/lost-found/commit
directory, which I think has the side effect of protecting them from garbage collection).
In this particular case, the commit you were looking for was not the tip-most commit of the deleted branch. That is, suppose before deleting feature/something
we have this, with the two most recent commits made on the feature branch:
A <- B <- C <-- master
\
D <- E <-- feature/something
Now we delete feature/something
, losing the IDs of commits E
and D
both. Both IDs will show up in the output of git fsck --unreachable
, but only E
's ID will show up (and be saved) by git fsck --lost-found
, because commit D
is "reachable" from E
if/when you restore that commit.
Finding your commit
how could I have found this lost commit by keyword?
It's a bit tricky. Probably your best bet is using git show
on all unreachable commits, something like:
git show $(git fsck --unreachable | git cat-file --batch-check |
awk '/commit/ { print $3 }')
Now you can search for the keyword(s) in the log messages (or the diffs). The internal $(...)
sequence is the method for extracting all the candidate IDs: we just want commits, not tags, trees, and blobs. Once you have the IDs, all regular git commands (git log -1
, git show
, etc) can be used with those.
1In fact, I just learned it myself writing up this answer.