I want to share a
git hole situation I had a hard time digging
myself out of.
I show how I dug myself into the situation by resetting changes more
than I wanted and show to easily fix the problem by using
If you are in or run into this situation, you won’t have to agonize
how to dig yourself out of the
git hole and can elegantly put the
repository into a desired state.
This article will take you about six minutes to read.
Ever get yourself into a “git hole”, where the repository’s state is not what you want by running the wrong command?
Most of the time, just “pulling down the repository again” will fix it (as with almost all problems related to software).
What if there’s actually work you want to keep or worse, other people’s commits you want to save?
In my situation, a team member fat-fingered a command and put the repository into weird state. A state he didn’t want it to be in.
This article, I share the same situation using a practice repository.
If you want to follow along code in this article:
- Clone repository:
git clone https://github.com/a-leung/tdd_indepth_callbacks.git
- Change to branch:
git checkout fix/update_rails_1
I was looking at recent git history, say before pushing up changes and making sure I have a clean history when pushing up changes:
running bin/rails app:update can be part of the
Rails to 126.96.36.199 commit because they’re the same process.
Clean up History
In this case, the easy thing to do: reset the last commit and amend it into the commit before that.
Step 1, run:
git reset HEAD~1
$ git reset HEAD~11 Unstaged changes after reset: M Gemfile M Gemfile.lock M app/models/order.rb M bin/rails M bin/rake M bin/setup M config/cable.yml M config/environments/development.rb M config/environments/production.rb M config/environments/test.rb M config/initializers/content_security_policy.rb M config/locales/en.yml M config/puma.rb M config/routes.rb M config/spring.rb M db/schema.rb M spec/models/order_spec.rb
What the?! What did I do???
git reset HEAD~11 instead of
git reset HEAD~1!? I jumped
back 11 commits instead of 1!!!!
Is this situation true??? Let’s confirm using
Yeah, there are files that are yet to be commited that are not part of the commit I want to squash. Crap. Did I just lose commit history too?!
git log say??
There’s gotta be a mistake, what’s the current log???
The first entry of git log is from January 18, not July 3, which is what I wanted.
There’s definitely commits missing. In this case, they’re only my commits. If I had commits from team members lost, it would be even worse.
How do I fix this?!
After catching my breath and realizing: well, at least I didn’t lose actual work. That would be even worse. I’ll take the extra “git blame” on those changes. Recreating and extra 10 commits of work, oh boy. Things can definitely be worse. :-)
git has a tool that tracks all the changes of the current HEAD, just
git reflog. When I run it in my case:
This is the last set of actions I took on the repository.
all changes made to the HEAD reference of the repository, stating the
SHA value of the change, the HEAD history from 0, and a description of
How can I use this??
To fix the problem of
git reset HEAD~11, which is in the reflog as:
The solution is the entry just before it:
To have git change HEAD to that entry, just do a
git reset to the
HEAD by running command:
Did that work?!
Let’s check the repository status now, what’s staged?
All clean… how about the git history?? Let’s check that using
Everything’s there again, just like it was at the beginning. All work committed with the right commit history.
If you want to find out more, the best place to look is the official documentation on reflog.
How it works
Although git presents a linear time line of work on the tracked items, under the hood, git is tracking every change in a non-linear manner. This is why you can even recover squashed commits.
reflog is another entry to git’s guts without exposing all the
Why it’s important to know
If you want to be better at your craft, knowing your tools better improves your craft.
git is an essential tool for software development as it’s one of the most used code versioning systems today.
Given this knowledge of using the
reflog - there is another way of
solving the same problem without using the reflog:
If you notice, the entry:
has the same SHA as:
Which refers to this commit:
The original commit I wanted to “reset” to.
This means running, just running
git reset <sha> would have solved
the same problem:
Will have the same effect.
reflog won’t be necessary if you had the commit SHA you want to
return to. Either in your screen’s buffer or even on the upstream
I never knew the
reflog was there and now that I know it, I couldn’t
believe why didn’t I know it sooner!
It would have saved me a lot of stress earlier in my development career and awkward conversations.
reflog, I see it’s a clean way into the guts of git as it’s how
git is tracking what to point to inside it’s own database of stuff.