Ale Paredes Software development and stuff

Recovering from some Git disasters

Git is one of those tools I can’t live without. It makes my life easier until some disastrous mistake happens and :boom:. So let’s cut to the chase and show how to fix them.

Scenario 1: Recover a commit after git reset –hard

You are working on a feature and you had made a couple of commits. But you have to reset back to a previous commit because requirements changed. So you do

$ git reset --hard <commit-sha> 

Great you’re at the point you want, you continue working and later on you realize that a part of your previous work you need it back. What can you do? git reflog to the rescue. Run:

$ git reflog <branch-name>
c826da7 HEAD@{0}: commit: Adds awesome feature
528c323 HEAD@{1}: checkout: moving from master to new_awesome_feature
8d31d0a HEAD@{2}: pull origin master: Fast-forward
766fd7a HEAD@{4}: commit: Adds temp news

It will show a history of your branch. The first column shows 7 characters that are the beginning of the commit’s SHA1. The second one is the pointer on the history. The third one shows the action you performed. And the last one shows the message. Once you see the commit you’re looking for, you take the SHA1 or the pointer. You can do git show <commit_sha> to see the diff and then you can just do checkout, cherry-pick or merge depending on how you want your commit back.

Scenario 2: Recovering a commit after a git push –force

So you like to live dangerously and you did git push –force (I’m one of those persons :sweat: ). After you found out that someone else pushed to the branch you just rewrote and you didn’t pulled, what can you do now?

$ git push --force <branch-name>
Counting objects: 3, done.
Delta compression using up to 4 threads.
p objects: 100% (2/2), done.
...

<BEFORE_SHA>...<AFTER_SHA> branch_name -> branch_name (forced update)

An awesome thing about using GitHub is that it stores everything and you can use the API to get what you need. With ‘BEFORE_SHA’ you go to https://github.com/your-organisation/your-repo/commit/BEFORE_SHA, you will be able to see all the missing code and get the FULL_BEFORE_SHA. Now you can use the GitHub API to push your old history back. If you’re using 2-step auth please read this to get the auth token and then:

$ curl -u <your_username> -H 'Authorization: token <your_token>' \
--request PATCH https://api.github.com/repos/your-organisation/your-repo.git/git/refs/heads/<branch_name> \
--data '{"sha": "#{FULL_BEFORE_SHA}", "force": true}'

PROTIP: Make sure you have global push.default set to simple (git config --global push.default simple) to avoid an even more disastrous accident.

That’s all for today…