Site icon Bytefreaks.net

About restoring a deleted Git branch

Advertisements

Recently, a branch was deleted from the server without it being merged.
Luckily for us, we had a local copy.

We used used the command git reflog to get access to the reference logs of the branch.
The command returned results similar to the below:

271f0084 HEAD@{0}: pull: Merge made by the 'recursive' strategy.
 0e71c0b HEAD@{1}: commit: Minor change: Cracked NSA systems
 c81624b HEAD@{2}: pull: Fast-forward
 ef1f281 HEAD@{3}: commit (amend): Deployed satelite
 1ed1a5a HEAD@{4}: commit (amend): Deployed satelite
 a8682cb HEAD@{5}: commit (amend): Deployed satelite
 e4560c8 HEAD@{6}: commit (amend): Deployed satelite
 1679a90 HEAD@{7}: commit (amend): Deployed satelite
 d27d2c9 HEAD@{8}: commit: Deployed satelite
 aaf8261 HEAD@{9}: checkout: moving from master to crack-nsa-systems
 2500e11 HEAD@{10}: clone: from ssh://git@bytefreaks.net:7999/secret/bananas.git

From this information we got the hash value in front of the commit which we wanted to use to restore, which was 271f0084.

Then, we checked out that version using

git checkout 271f0084;

When we tried to push the branch back to the server the Git pre commit hooks blocked the operation.
Based on the rsa key used, we could only submit changes that were committed by the owner of that key.
The option to disable temporarily the pre commit hooks was unfortunately out of the question.
So we had to replace all author names and emails with the name of the one holding the key.

To do so we used the following command before pushing to the server once more:

git filter-branch --commit-filter '
   if [ "$GIT_COMMITTER_NAME" = "Doe, John" ];
   then
     GIT_COMMITTER_NAME="Squarepants, Bob";
     GIT_AUTHOR_NAME="Squarepants, Bob";
     GIT_COMMITTER_EMAIL="bob@bytefreaks.net";
     GIT_AUTHOR_EMAIL="bob@bytefreaks.net";
     git commit-tree "$@";
   else
     git commit-tree "$@";
   fi' HEAD

git filter-branch lets you rewrite Git revision history by rewriting the branches mentioned, in our case it was HEAD, applying custom filters on each revision. Those filters can modify each tree (e.g. removing a file or running a perl rewrite on all files) or information about each commit. Otherwise, all information (including original commit times or merge information) will be preserved.

HEAD is a reference to the currently checked out commit. In normal states, it’s actually a symbolic reference to the branch you have checked out.
Looking at the contents of .git/HEAD you’ll see something similar to ref: refs/heads/master.
The branch itself is a reference to the commit at the tip of the branch.

This post is also available in: Greek

Exit mobile version