I want to go back to an earlier commit. How can I do this?
This is what the git log
command shows:
$ git log
commit dddddd
Author: Me & lt; [email protected]>
Date: Thu Nov 4 18:59:41 2010 -0400
Add buzz
commit cccccc
Author: Me & lt; [email protected]>
Date: Thu Nov 4 05:13:39 2010 -0400
Add fizz
commit bbbbbb
Author: Me & lt; [email protected]>
Date: Thu Nov 4 00:55:06 2010 -0400
Add bar
commit aaaaaa
Author: Me & lt; [email protected]>
Date: Wed Nov 3 23:56:08 2010 -0400
Add foo
Answer 1, authority 100%
This question can be understood in different ways:
- What does it mean to go back or rollback: just look, change the contents of the workspace, change the Git history?
- What to rollback: worktree, index (staging area), current branch, remote branch?
- Which position should I rollback to: index, last commit, arbitrary commit?
Let’s designate the initial situation in the following diagram:
(i) (wt)
A - B - C - D -? -?
↑
master
(HEAD)
A
, B
, C
, D
– commits in the master
branch .
(HEAD)
is the location of the HEAD pointer.
(i)
is the state of the Git index. If matches (HEAD)
– empty. If not, it contains changes prepared for the next commit.
(wt)
– the state of the project workspace (working tree). If it matches (i)
– there are no non-indexed changes, if it does not match – there are changes.
↑
denotes a commit pointed to by a particular branch or pointer.
Here are the solutions, depending on the task:
1. Temporarily switch to another commit
If you just need to switch to another commit to, for example, look at its contents, the command git checkout
:
git checkout aaaaaa
(wt)
(i)
A - B - C - D
↑ ↑
(HEAD) master
The repository is currently in the “detached HEAD” state. To switch back, use the branch name (e.g. master
):
git checkout master
2. Switch to commit and continue working from it
If you want to continue from another commit, you need a new branch. You can switch and create it with one command:
git checkout -b new-branch-name aaaaaa
(wt)
(i)
A - B - C - D
↑ ↑
new master
(HEAD)
3. Delete changes in the workspace and revert it to the state of the last commit.
Initial state:
(i) (wt)
A - B - C - D -? -?
↑
master
(HEAD)
3.1 Safe – with a pocket (stash)
3.1.1 Non-indexed only
You can delete only pocket changes that have not yet been indexed (using the add
command):
git stash save --keep-index
Final state:
(wt)
(i)
A - B - C - D -? ?
↑ ↑
master stash {0}
(HEAD)
3.1.2 Indexed and None
This command will undo all indexed and non-indexed changes in the work area, storing them in the stash.
git stash save
Final state:
(wt)
(i)
A - B - C - D?
↑ ↑
master stash {0}
(HEAD)
Recovering unsaved changes : easy and simple.
git stash apply
If you don’t need stash at all, you can remove it.
# delete the last pocket entry
git stash drop
Learn more about using stash .
After that, it is still possible to recover the changes, but it is more difficult: How to recover a dropped stash in Git?
3.2 Dangerous way
Caution! This command permanently removes unsaved current changes from the workspace and from the index If you still need them, use
git stash
.Recovering unsaved changes : non-indexed ones are lost completely, but you can restore what was indexed .
Here we will use git reset --hard
Execute:
git reset --hard HEAD
Final state:
(wt)
(i)
A - B - C - D - x - x
↑
master
(HEAD)
4. Go to an earlier commit in the current branch and remove all subsequent (unpublished) commit from it
Caution This command rewrites the history of the Git repository. If you have already published (
git push
) your changes, then this method cannot be used (see why ) . Use the option from step 5 (git revert
).
4.1 At the same time, save changes to the repository index:
git reset --soft bbbbbb
The repository index will then contain all changes from cccccc
to dddddd
. Now you can make a new commit (or several) based on these changes.
(wt)
(i)
A - B - C - D
↑
master
(HEAD)
4.2 Save changes in the workspace, but not in the index.
git reset bbbbbb
This command simply moves the branch pointer, but does not reflect the change in the index (it will be empty).
(i) (wt)
A - B - C - D
↑
master
(HEAD)
4.3 Just throw changes.
Caution This command will permanently delete unsaved current changes . If the commits to be removed do not belong to any other branch, then they will also be lost.
Restoring commits : Use
git reflog
and this question to find and repair commits; otherwise, the garbage collector will permanently delete them after a while.Recovering unsaved changes : non-indexed ones are lost completely, but you can restore what was indexed .
Initial state:
(i) (wt)
A - B - C - D -? -?
↑
master
(HEAD)
Execute:
git reset --hard bbbbbb
Final state:
(wt)
(i)
A - B - C - D - x - x
↑
master
(HEAD)
5. Undo already published commits with new commits
Use the command git revert
. It creates new commits, one for each undo commit. Thus, if you need to undo all commits after aaaaaa
:
# can list the commits to undo
git revert bbbbbb cccccc dddddd
# you can set a range from earlier to later (new)
git revert bbbbbb..dddddd
# or in relative links
git revert HEAD ~ 2..HEAD
# you can undo a merge commit by explicitly specifying the ancestor number (in our example, there are none):
git revert -m 1 abcdef
# then confirm the changes:
git commit -m 'a detailed description of what was done and why'
Recover : If the revert commit fails, use this answer .