tldr;
This assumes you have not run git clean
on your repo.
Find unreachable commits:
git fsck --full --no-reflogs --unreachable --lost-found | grep commit
Find the commit you are looking for:
git cat-file -p bb00fa599994c3d6f80f99af4cadc8a145ab22e5
Restore:
git branch branch_name bb00fa599994c3d6f80f99af4cadc8a145ab22e5
The Cause
I was doing some work on a project I had not recently worked on. During “re-boarding” I was looking through the branches I had created and not cleaned up before starting a new task in a different project. In my ultimate wisdom I deleted a branch I though I did not need ( I deleted a number of branches ).
git branch -D test
A while after I had a got into context and had my head in the code again and realised I had deleted a branch I needed. ( This was a bit of a stressful moment as I had thought I lost work I needed )
This was my process to resolve the deletion.
PS
I DID NOT clean my repo before trying this.
Internal SDLC
I am messy with my branches especially when I am nervous I am going to break something ( refactor or optimisation ) or trying something I think is risky ( upgrading a npm package ). I quickly create a branch with a high level descriptor of what I am going to be testing and then I make the changes. I make sure I commit all my changes to the branch. I generally do not reset the project.
If I don’t use the branch or my assumptions were correct, something broke. I generally do not clean up the branch, I will keep it alive… just in case I need it in the future.
Resolution
To solve this, we need to get all the unreachable/dangling commits. This is fairly easy.
git fsck --full --no-reflogs --unreachable --lost-found
You will get a result looking something like this:
-<%>- git fsck --full --no-reflogs --unreachable --lost-found
Checking object directories: 100% (256/256), done.
Checking objects: 100% (3593/3593), done.
unreachable tree 2c800985611250f9583ec58d9a02d2546ca15971
unreachable tree 7d80e777a5466d91b8bd5f7ce414a6fa27dfc1d3
unreachable tree 98c05543e139948c730cd2689f32d31de280bf05
unreachable commit bb00fa599994c3d6f80f99af4cadc8a145ab22e5
unreachable blob 2241f07ef822837da76194ffc2c0ad95cca3412b
unreachable tree c1c10fc6b4f412b296b47d4e3e747e2d8f36c5f6
unreachable tree 30425a4cb2ed23efa04789933b018ae3b21a20ce
unreachable tree 6f0257f5be71023cff18b1d710466b995a91e3c4
unreachable tree a182b4b4b32dd88949d49f962989d0977a477358
unreachable tree c2c2e80c022bd9fca5147d47e8fa5419223a4fe7
unreachable tree 1ec37c8940bdd2fbf61676294966b737dd043f5b
unreachable tree 2dc3cf15b58b366dac68037db975dd825deae91e
unreachable blob 348308e9947c314a030a0c9772e13c2bc4eae40e
unreachable tree 02443f99fceacf56ee236838a6d6aa6a4aca7854
unreachable tree 5c84cc75a7f27e47c22c8ed2da77aaa6a4ba543f
unreachable tree 62c476fe7200d16e303b627b90e2d74dfd6259dd
The trick with this is that you can only restore commits, resulting in a grep for commit.
git fsck --full --no-reflogs --unreachable --lost-found | grep commit
This will get you something like this.
unreachable commit bb00fa599994c3d6f80f99af4cadc8a145ab22e5
There are two ways you can go from here, the one is to brute force and restore every commit and hope that is OK. ( This is what I did ).
git branch branch_name bb00fa599994c3d6f80f99af4cadc8a145ab22e5
The more effective way to do this, especially if you have more than one commit, is to get metadata about the commit.
This will give the author, committer and commit message and a timestamp as a unix time.
git cat-file -p bb00fa599994c3d6f80f99af4cadc8a145ab22e5
resulting in this:
git cat-file -p bb00fa599994c3d6f80f99af4cadc8a145ab22e5
tree cc17347e2dbce292d61e9bb4e5dfba24df7e6653
parent c49c38939a718985d018b4710e5a5e7599a683fa
author example@example.com <example@example.com> 1664525456 +0200
committer example@example.com <example@example.com> 1664525456 +0200
feature: test
To get a little more with diff:
git log -p bb00fa599994c3d6f80f99af4cadc8a145ab22e5
Resulting in a git log message with an easy to read timestamp:
commit bb00fa599994c3d6f80f99af4cadc8a145ab22e5
Author: example@example.com <example@example.com>
Date: Fri Sep 30 10:10:56 2022 +0200
feature: test
Going through all the commit until you find the one you were looking for and then restoring the branch and you are back in the game. , I need to start cleaning up the branches before moving on.
Learning
Depending on your workflow you may have the same thing as me, or possibly be prohibited from committing branches into your server which are in testing or not completed work. Possibly having work which is not related to a ticket allocated to you…
Some companies have a period set aside where the team is allowed to work on anything they see fit, or anything they want to fix which may be bothering them. ( Its sort of this sort of scenario which may cause this to happen )
I need to start cleaning up the branches before moving on.