Here's what I did:
git status
displays all my changes.git add -A
git commit -m "Foo"
. A pre-commit git hook fires with husky
and lint-staged
.git commit -m "Foo"
again and immediately cancel.git status
is clean, git log
and git reflog
do not show a new commit.Why did my changes get reverted? How do I recover them?
OK, it was lint-staged
to blame. It stashed my changes.
So running git stash apply
recovered them!
⚠ Do not attempt running multiple instances of lint-staged
in parallel on the same git repo (e. g. on each project in a monorepo). This will destroy your changes without any way to recover them.
If you work on a monorepo, either lint projects sequentially or give up lint-staged
and lint the whole codebase, including unstaged files.
For all of you who are: TL;DR
- Option 1 - which you mentioned you already did: use git reflog
&& git reset
- Option 2 - Use your editor history
- Option 3 - If you added those files grab them from the staging area but you will need to find them
# Find all dangling files
git fsck --all
## Now use git cat-file -p to print those hashes
git cat-p <SHA-1>
Before answering, let's add some background, explaining what this HEAD
is.
First of all what is HEAD?
HEAD
is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD
at any given time (excluding git worktree
).
The content of HEAD
is stored inside .git/HEAD
and it contains the 40 bytes SHA-1 of the current commit.
detached HEAD
If you are not on the latest commit - meaning that HEAD
is pointing to a prior commit in history it's called detached HEAD
.
On the command line, it will look like this - SHA-1 instead of the branch name since the HEAD
is not pointing to the tip of the current branch:
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# Create a new branch forked to the given commit
git checkout -b <branch name>
git reflog
You can always use the reflog
as well. git reflog
will display any change which updated the HEAD
and checking out the desired reflog entry will set the HEAD
back to this commit.
Every time the HEAD is modified there will be a new entry in the reflog
git reflog
git checkout HEAD@{...}
This will get you back to your desired commit
git reset --hard <commit_id>
"Move" your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
git rebase --no-autostash
as well.git revert <sha-1>
"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in the history as well.
# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrates which command does what.
As you can see there, reset && checkout
modify the HEAD
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With