DEV Community

leanminmachine
leanminmachine

Posted on

git reflog saved my ass.

I’m a git noob.

I was panicking as usual because I accidentally committed my changes on to the master branch. We’re supposed to just git checkout and create a new branch, opening a pull request before merging to master.

So i was furiously googling, and this came up:

git reset —soft

git checkout - How to revert a Git repository to a previous commit - Stack Overflow
git reset --soft <commit>

  • Revert back while keeping the changes.
  • Does not change the working tree.
  • Goes back to commit status such as unstage files.

I tried using git reset --soft HEAD^ . I’m still not sure what’s the difference between HEAD^ and HEAD. Apparently:

Use ~ most of the time — to go back a number of generations, usually what you want
Use ^ on merge commits — because they have two or more (immediate) parents

Source: What’s the difference between HEAD^ and HEAD~ in Git? - Stack Overflow

So it worked, my changes got unstaged. But when i switched to a new branch, it seemed to have disappeared?? So i was panicking because usually i use git status and git log to check for modified files, staged / unstaged etc. I was so scared that all my code went missing.

git reflog

Thankfully, after googling, i found this command: git reflogRecovering a git reset —soft - Stack Overflow — which logs out commits that are not in my working tree anymore. Lo and behold, my commits are still there. Phew, all i have to do is to just reset back to that commit and make sure to push it up now.

Kinda weird why git log doesn’t show the commits.

Discussion (15)

Collapse
leanminmachine profile image
leanminmachine Author

i havent tried gitkraken, is it better than sourcetree? been using sourcetree but since a few mths back, i've switched to just terminal. now i just use git log --graph --oneline --decorate to see the structure haha

Collapse
foresthoffman profile image
Forest Hoffman

I added the following to my global git config, it's a pretty compact git flow IMO.

[alias]
    lg1=log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
    lg2=log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
    lg=!git lg1
Collapse
jsn1nj4 profile image
JSn1nj4‍‍👨‍💻

I was Terminal-only for a while too. But for a simple GUI that speeds up your most common operations, I have to recommend GitKraken.

I still hang onto my terminal for when I need it though. GitKraken doesn't cover everything that, say, SourceTree does, but its GUI is much cleaner and I'm already comfortable enough in a terminal that I'm fine doing the more advanced stuff that way.

As an aside, I'd recommend being comfortable with git CLI anyway. Trying to learn with a GUI alone tends to hide a lot of the important stuff.

Collapse
divyansh profile image
divyansh

What left me wondering is why the master wasn't protected!?

Anyway, git-revert is super helpful in such incidences, it mutates the branch history though. But it makes sure you don't lose your changes under any incident. If you feel like you lost your changes, you can always go back to the reverted commit, checkout a branch from there and continue.

What i'd suggest in such scenario is,

  1. git branch newBranch: Create a new branch keeping the accedental commit, that'll preserve your development and the code so far.
  2. git reset --hard <commit hash> (on master). That'll leave the master unmutated.

Now switch to newBranch and continue with your business like nothing ever happened!

Collapse
jsn1nj4 profile image
JSn1nj4‍‍👨‍💻

Wouldn't protecting a branch only affect the remote repo? I don't think she pushed to master.

Collapse
gergelypolonkai profile image
Gergely Polonkai

HEAD always points to the commit that is checked out. HEAD~, which is the same as HEAD~1refers to HEADʼs parent. HEAD~2 is the parent of HEAD~1, and so on.

When you git chegkout a different commit, HEAD moves to that commit. When you git commit your changes, HEAD moves to the newly created commit.

When you do a git log <commitish> (where <commitish> can be a branch name, a tag, a commit hash, or pretty much anything then unambiguously refers to a commit, and defaults to HEAD if you donʼt specify it), Git will print that commit, its parent, the parent of that parent, and so on.

Contrast that to git reflog which displays the commit HEAD is pointing to, then the commit HEAD was pointing before (and can be referred to as HEAD@{1}), and so on.

Hope that helps, happy coding!

Collapse
johncip profile image
jmc • Edited on

Whoa. Thanks for this. I also didn't realize they had that difference. But it does make sense that you'd need a way to specify which parent to choose, when more than one exist.

still not sure what’s the difference between HEAD^ and HEAD~

I'd summarize as: when a commit has more than one parent, ^ lets you say which one you want, ~ always returns the first.

What's confusing is that each can take a number, but treats it differently. <rev>^2 means "rev's second parent" and <rev>~2 means "rev's leftmost grandparent." It might help to think of merge commits as having left and right parents (^1 and ^2), but technically they can have more than 2.

Kinda weird why git log doesn’t show the commits.

My guess is the commits became unreachable. The commits are like a tree* where some of the leaves have markers (either tags or branches) pointing to them. Any commit that's pointed to by a marker or another commit is reachable. git log, despite the name, is just a list of the reachable commits.

Unreachable commits eventually get deleted. The reflog lists every commit, but being in the reflog doesn't prevent deletion.


* technically a DAG, because multiple parents are possible.

Collapse
oligospermia profile image
Mesalazine

reflog can even help when you accidentally drop/clear stashed changes (those that weren't even committed really yet).

Collapse
leanminmachine profile image
leanminmachine Author

? how does it work if the changes arent committed or stashed somewhere..?

Collapse
oligospermia profile image
Mesalazine

Well changes should be in the stash of course. Then you accidentally lose it (via git stash clear or git stash drop). However, even if changes weren't committed, they still do have some hash tags in the repository, they are stored as so called "dangled commits". So all you have to do is find such hash and apply it via stash command to restore. You can see an example here:

stackoverflow.com/questions/89332/...

Thread Thread
leanminmachine profile image
leanminmachine Author

nice, thanks for the link!

Collapse
lau0002 profile image
Lo2

Try translate this page to understand reset, checkout, branch and so on. Very good article.

miximum.fr/blog/enfin-comprendre-git/

Collapse
devanghingu profile image
Devang Hingu

GUI's git application provide speedup over all activity but most of users makes mistakes on GUI interface. Guy who on terminal never make kind of mistakes.

Collapse
praneetnadkar profile image
Praneet Nadkar

This can save many from the panic attack. Thanks for posting this.