I accidentally rebased my branch with the DEV branch and then pushed it to a remote repository. With the rebase, I selected the current changes and hence my local changes got overwritten.
I lost my earlier commit in the rebase but found it by running git log
. Then I ran git checkout commitId
and even git reset --hard commitId
. However, in both cases my code base still shows the latest rebased code on my branch.
How do I restore my branch back to its previous state?
Checking out a commit’s hash or object name enters what the git documentation refers to as detached HEAD state.
It is sometimes useful to be able to checkout a commit that is not at the tip of any named branch, or even to create a new commit that is not referenced by a named branch. Let’s look at what happens when we checkout commit b (here we show [three] ways this may be done):
$ git checkout v2.0 # or $ git checkout master^^ # or $ git checkout b HEAD (refers to commit 'b') | v a---b---c---d branch 'master' (refers to commit 'd') ^ | tag 'v2.0' (refers to commit 'b')
Notice that regardless of which checkout command we use,
HEAD
now refers directly to commit b. This is known as being in detached HEAD state. It means simply thatHEAD
refers to a specific commit, as opposed to referring to a named branch.
As you observed, git will happily create new commits, rebase, merge, and so on with a detached HEAD, but because no tag or branch refers to the resulting unnamed branch, losing it will be easy. You were able to find your original commit with git log
. When you have done more drastic surgery, the output of git reflog
is another place to look.
Fixing your branch as described in your question will involve the following sequence.
HEAD
to your branch (referred to below as topic/my-branch
)topic/my-branch
to where it was beforeorigin/topic/my-branch
from the earlier push.
Reattach HEAD
Rather than by its SHA-1 hash, check out your branch by name
git checkout topic/my-branch
Fix your local branch
Next, put it back where it was with git reset --hard
. You will use the same command, but the context is different: HEAD
after git checkout
points to topic/my-branch
rather than to commitId directly.
git reset --hard commitId
Fix the remote branch
You said you pushed your rebased branch, so update the remote repository to reflect your changes. The way to do it all in one command is
git push --force origin topic/my-branch
The administrator of the remote repository may have taken the highly reasonable step of denying force pushes (for why, see below). If so, try a sequence of
In the bad old days, we had to delete remote branches with the non-obvious
git push origin :topic/my-branch
but nowadays, it’s spelled
git push --delete origin topic/my-branch
Having cleared the way, now push your branch to put things back to where they were before.
git push origin topic/my-branch
If both force pushes and deletes are disabled on your remote, ask for help from someone with administrative access to that repository.
Most of the time, you have to work very hard to convince git to destroy work. However, git reset --hard
, deleting remote branches, and git push --force
are all sharp tools — useful when you need them but dangerous when used carelessly. As with rm -rf
, pause to consider whether you really mean the command you’re about to run.