Feb 11, 2014

Recovering a commit from Github’s Reflog

This morning when I arrived to work I was presented with a very interesting Git/Github problem by a co-worker. He had pushed a commit from his home computer last night and this morning he had force pushed over the top of it without realizing it. Normally, this isn’t such a big problem since the commit would still exist in Git’s reflog and you could recover it from there. The problem was that he never did a fetch from Github before doing the force push. This effectively erased the commit and made it unrecoverable without his home computer. Or so we initially thought…

First, use Github’s Events API to retrieve the commit SHA.

$ curl https://api.github.com/repos/<user>/<repo>/events

This will return a JSON response which you can read through to find the commit you lost. Use the commit message and approximate times to narrow your search. Here is an example portion of the response (I’ve deleted some info, but you should get the point):

    "id": "1970551769",
    "type": "PushEvent",
    "actor": {
      "id": 563541,
      "login": "<user>",
      "gravatar_id": "<id>",
      "url": "https://api.github.com/users/<user>",
      "avatar_url": "<url>"
    "repo": {
      "id": 9652839,
      "name": "<user>/<repo>",
      "url": "https://api.github.com/repos/<user>/<repo>"
    "payload": {
      "push_id": 303837533,
      "size": 1,
      "distinct_size": 1,
      "ref": "refs/heads/<branch>",
      "head": "a973ddd28d599c9ba128de56182f8769d2b9843b",
      "before": "4ef3d74316c04c892d17250f0ba251b328274e5f",
      "commits": [
          "sha": "384f275933d5b762cdb27175aeff1263a8a7b7f7",
          "author": {
            "email": "<email>",
            "name": "<author>"
          "message": "<commit message>",
          "distinct": true,
          "url": "https://api.github.com/repos/<user>/<repo>/commits/384f275933d5b762cdb27175aeff1263a8a7b7f7"
    "public": false,
    "created_at": "2014-02-06T14:05:17Z"

Next, use Github’s Refs API to create a new branch pointing to that commit:

$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST -d '{"ref":"refs/heads/D-commit", "sha":"384f275933d5b762cdb27175aeff1263a8a7b7f7"}' https://api.github.com/repos/<user>/<repo>/git/refs

Breaking down the JSON in this request we have this:

  "ref": "refs/heads/D-commit",
  "sha": "384f275933d5b762cdb27175aeff1263a8a7b7f7"

The “ref” in the JSON is Git ref we want to create, it MUST be of the form: refs/heads/<branch>, where <branch> is the name of the branch we want to create in Git.
The “sha” is the commit that we want this new branch to point to.

If successful Github will respond back with something like this:

HTTP/1.1 201 Created
Server: GitHub.com
Date: Thu, 06 Feb 2014 14:47:02 GMT
Content-Type: application/json; charset=utf-8
Status: 201 Created
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4991
X-RateLimit-Reset: 1391700034
Cache-Control: private, max-age=60, s-maxage=60
ETag: "43e54fee5cf29edd01fa8bfce094ed1b"
Location: https://api.github.com/repos/&lt;user&gt;/&lt;repo&gt;/git/refs/heads/D-commit
Vary: Accept, Authorization, Cookie, X-GitHub-OTP
X-GitHub-Media-Type: github.beta
X-Content-Type-Options: nosniff
Content-Length: 339
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
Access-Control-Allow-Origin: *
X-GitHub-Request-Id: 4389B15A:3E60:1D2506F:52F3A066

  "ref": "refs/heads/D-commit",
  "url": "https://api.github.com/repos/&lt;user&gt;/&lt;repo&gt;/git/refs/heads/D-commit",
  "object": {
    "sha": "384f275933d5b762cdb27175aeff1263a8a7b7f7",
    "type": "commit",
    "url": "https://api.github.com/repos/&lt;user&gt;/&lt;repo&gt;/git/commits/384f275933d5b762cdb27175aeff1263a8a7b7f7"

Now if you pull up your repository in Github, you will see the new branch and doing a ‘git fetch’ will retrieve that new branch to your local repository. From there you can cherry-pick or merge the commits back into your work.

About the Author

Object Partners profile.

One thought on “Recovering a commit from Github’s Reflog

  1. David Norton says:

    Excellent. You can almost hear the people saying “This is exactly why Git is so [great, terrible]”

  2. Dan Woods says:

    John, you’re a true pro. This will be a life-saver for me later on in life.

  3. WORMSS says:

    I dont know if its just a Windows thing or not, but I had to use double quotes around the outside and escape all nested quotes on the inside. -d “{“ref”:”refs/heads/D-commit”, “sha”:”384f275933d5b762cdb27175aeff1263a8a7b7f7″}”

  4. Jessie Younh says:

    THANK YOU! Just had the exact same thing happen (force pushed from my work comp after making progress on my home comp) and this fixed it for me. 🙂

  5. Vittorio says:

    This is truly a life saver! The new API version require an authorization token to create branches but it’s as simple as adding ‘-H “Authorization: token “‘ to the command line.

    Thanks again!

  6. Tom Klancer says:

    This is great! I just recovered a year-old lost commit.

  7. Hadas says:

    You just saved my butt! thanks.

    By the way, it took me a while to figure out that the events api results are paginated. the default result is just the first page, if you need something older you can check the response header and follow the links to the next page. or you can also set the “page” query parameter to the desired number of page.

  8. Chris says:

    I was accessing a private repo; to do that, I just had to add `-u ` to the commands you provided. Thanks!

  9. Sharang says:

    Thanks for this!

  10. cben says:

    This post has saved me & coworkers about 5 times already 🙂

    Instead of obtaining auth token for creating the branch via API, I was able to open in the browser https://api.github.com/repos///commits/384f275933d5b762cdb27175aeff1263a8a7b7f7 at the desired commit,
    click on the “Tree: 384f275933” dropdown, type the desired name and click “Create branch: “.

  11. xhuman says:

    If you only need to recover one or two files then there is no need to create extra branches and use curl: you can get the file contents directly in your web browser by opening the your JSON API endpoint, i.e. https://api.github.com/repos///events , locating and clicking the URL for the commit you need, and then in the next json that opens click the `raw_url` for your file(s).

Leave a Reply to Sharang Cancel reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Design Systems, Part 1 • Introduction
Business leaders need a practical guide to plan and execute Design System Initiatives. The aim of this series is to be that guide. This installment introduces terms and definitions as a primer on Design Systems.
ML for Translating Dysarthria Speech (Pre-Part 1)
What is Dysarthria? Per the Mayo Clinic, Dysarthria occurs when the muscles you use for speech are weak or you have difficulty controlling them. Dysarthria often causes slurred or slow speech that can be difficult […]
Develop Quality Code
As software continues to dominate every facet of our lives, developers are faced with an ever-increasing pressure to produce bug free code. The responsibility of clean quality software falls upon everyone that is involved in […]
Clean JSX structuring in React
A video guide on how to structure your JSX to make it easier to know when it’s appropriate to split out new components. This will help keep your React code smaller, cleaner, and more DRY.