Of course, one of the important reasons for having version control is being able to go back to an earlier version if need be.
HEAD
If you remember from lesson 1-1, it is possible to reference a commit using the first 7 or more characters of a commit hash.
However, even the first 7 characters of a commit hash can be difficult to remember quickly, and usually involves copying and pasting, which can be difficult to do in the terminal under certain circumstances.
But, if you can remember how many commits away the commit you want is from the local HEAD
(as in the last commit you have locally, including unpushed commits),
then there is another way to reference it.
If you want to refer to the parent of the HEAD
commit, then you would use the parent symbol, ^
:
HEAD^
If you want to refer to commits beyond the parent, then you have to pass a number with the tilde ~
:
HEAD~3
As was mentioned in lesson 1-2, a reset is useful if you want to undo unpushed changes, or briefly go back to a point in your repository's history such that your repository is exactly the way it was at that commit.
For command-line git users, the syntax is pretty simple. You just tell it what commit you want to reset to:
git reset <commit>
where commit
can either be the first 7 (or more) characters of the commit hash, or a reference from HEAD
.
If you use a GUI, its Reset
option should provide you with a list of commits (or a text box to enter the commit in) and a list of the different reset modes.
The tricky thing about git reset
is that there are actually multiple different reset modes. The three main ones that you will use are:
HEAD
pointer back to the specified commit. It does not change git's index or affect the files in the working tree.
In other words, HEAD
will point at the commit you specified, but nothing else will change —
the files in the working tree will remain the way they were before the reset.git reset
mode.To see a full list of the possible modes and their explanations, see man git-reset
.
Basically, what mode you use comes down to a few rules:
After you have done a hard reset, if you have pushed changes after the commit your HEAD
points at, you can get them back simply by doing a pull.
To clear the staging area:
git reset HEAD
To undo all changes since the last commit:
git reset --hard HEAD
To reset the working tree to 7 commits back in history:
git reset --hard HEAD~7
To reset the working tree to commit 845da8b
:
git reset --hard 845da8b
A revert is more useful if you want to more permanently undo the changes done in a commit, if a commit you want to undo is buried in history, or it has already been pushed to the remote repository.
Unlike reset, you can only revert one commit in a time. If you want to revert across multiple commits, you will have to revert each commit individually.
To undo just one commit, the syntax is similar to git reset
:
git revert <commit>
where, again, commit
can be either the shortened hash or a reference from HEAD
.
However, if you want to revert several commits, the syntax is different:
git revert <first-commit>..<last-commit>
where first-commit
is the first (oldest) commit you want to undo, and last-commit
is the last (newest) commit you want to undo.
When you execute the revert command, git will generate reverse diffs for each commit and then give you a commit message to sign off on. If you revert multiple commits, git will ask you to approve the commit message for each individual revert in order (however, it will iterate through every commit automatically).
HEAD
Sometimes, you may find yourself in a situation where you want to get something from a previous commit, but you don't want to go through the hassle of pulling the changes back down after a hard reset. Or perhaps you have unpushed commits that you don't want to lose, but aren't ready to push yet.
There is another way to access your repository at a certain point in history, and this is called having a detached HEAD
.
However, this method is really only usable on the command line.
This method takes advantage of the git checkout
command (which, as you will learn in the next lesson, is used to switch branches)
to put the repository in the state it was when the commit was made, essentially by treating the commit as if it were its own branch.
You can do this by passing the commit reference to git checkout
:
git checkout <commit>
Git will let you know you are entering the detached HEAD
state when you do this:
$ git checkout HEAD^
Note: checking out 'HEAD^'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 845da8b... <commit message title>
Basically, what this does is make git behave like the commit is its own branch. While you can make commits and use git normally, you should note that anything you do won't end up on a branch unless, like the message says, you create a new branch to keep your changes.
You can go back to where your repository was before detaching HEAD
by checking out the branch you were on before:
git checkout master
← 2-1 Basic Operations | 2-2 Revising History | 2-3 Branching → |