Recently, my colleagues are starting to get acquainted with git. And one of the questions that interests them is how to roll back to a certain revision. On the Internet you can find a set of commands, but I want to have an understanding of each of them. Pampering with git’s commands without understanding can lead to a loss of development history.
In this article I want to talk about the
git checkout
and
git reset
commands with the -
--soft
and -
--hard
.
So let's start a short educational program on the time machine provided by git. First illustrate the story:

')
Here circles marked commits. The more to the right commit, so it is newer. A commit with a 6e04e hash .. is the very first commit. One of the basic concepts that a newbie should understand is the pointers to commits, or rather, some kind of “nickname” of this or that commit. Their darkness is dark, for example:
HEAD, master, FETCH_HEAD, ORIG_HEAD , etc. This I listed a grain of standard nicknames. You can create them yourself, but more on that in front.
Let's focus our attention on two pointers:
master and
HEAD .
master indicates the most senior commit in the branch called
master (this branch is created when the repository is initialized).
HEAD points to the master pointer (read, the current state of the files). After the first commit appears in the repository,
HEAD and
master point to the same commit. And it will continue this way until we switch to another branch, roll back through the history, or take a series of rash actions. So, we illustrate our history with pointers:

The
HEAD pointer in our case points to
master , and the
master to the d79fb commit ... It is important to understand that the current state of unchanged files under version control is the commit that
HEAD points to. That is, if
HEAD points to a commit with hash 6e04e .., then the files will be in their original state. To "move" the
HEAD pointer, there is a command: git checkout. Those who are familiar with even a little bit of git, learned in this command switching to another branch. Everything is absolutely true - when switching to another branch, we simply transfer the
HEAD pointer to the last commit branch.
Move the HEAD pointer ( git checkout
)
Rollback on commit history:

After the checkout operation is completed, we will be in the state in which there were two commitments back. This is all great - we took a step into the past, we peeped at something there, but how could we go back? I, for example, do not have super-memory, and I do not remember the hash of the most recent commit (the one that is the most right is d79fb ..). If we write
git log
, we will see a story consisting of three commits:
[user@localhost project]$ git log --pretty=oneline 6741a69bd121c295413be95d7597cd7409e713a0 add unit test b3e74f50c3cc48e6b335014b6dc7e301b382a903 add readme 6e04e39d0952a2d6022502d56aaa05d5a064bea Initial commit
Have we really lost the whole story? How to find out the most "new" commit? This is not a problem - there is a way out, and there are several:
- Write a
git log --all
command. This command will print the whole story to us, up to the present, i.e. in our case, the story of five commits:
[user@localhost project]$ git log --pretty=oneline --all d79fb5688af71b4577f450919535e7177e9d74e8 fix bug 478927e3a088d3cec489ca8810eaaca97c6ce0ff documentation 6741a69bd121c295413be95d7597cd7409e713a0 add unit test b3e74f50c3cc48e6b335014b6dc7e301b382a903 add readme 6e04ee39d0952a2d6022502d56aaa05d5a064bea Initial commit
Then it remains to copy the hash we need and re-start the time machine: git checkout
. But this method is not recommended, because it requires too much action. - Git allows you to track all changes to the HEAD pointer. This is possible with the
git reflog
, but this is no longer for beginners and is not used for the purposes we have set. The most competent is to do the following: - Recall that the master pointer points to the most recent commit. Thus, a reset is performed by one command:
git checkout master
. Woo-la:

To clarify the
git checkout
mechanism, create a new devel branch:
[user@localhost project]$ git checkout -b devel
* -b flag means that you need to create a branch with the specified name and immediately switch to it.
We illustrate the action we committed:

Note that the
HEAD pointer points to the top of the
devel branch.
Let's breed several commits in the new branch. The history of the repository will look like this:

Returning to the master branch is also painless:
[user@localhost project]$ git checkout master

So, remember the first item:
- The git checkout room moves the HEAD pointer.
Move the pointer to the top of the branch ( git reset ...
)
In addition, git allows you to move not only
HEAD , but also
continents, pointers to the tops of branches. To do this, there is the
git reset
command with the keys either
--soft
or
--hard
.
- The key
--hard
means that we lose the current state of the files and acquire the state of the commit where the reset was made. - The key
--soft
means that we do NOT lose the current state of the project, but the pointer to the current branch has already been moved, i.e. git status will give us the difference between the current state of the project (from which we reset) and the one we reset.
In both cases, a “nickname” appears for the commit from which the reset was performed -
ORIG_HEAD .
git reset --hard HEAD~2
:

git reset --soft HEAD~2
:
ORIG_HEAD is useful for editing incorrect commits on a local machine (!). Suppose we want to merge the last two commits into one. To do this, preserving the current state of the files, we translate the master pointer to two commits ago:
[user@localhost project]$ git reset --soft HEAD~2
Let's look at the changes:
[user@localhost project]$ git status
Well, now let's do the trick - combine commits
[user@localhost project]$ git commit -c ORIG_HEAD
Enter the message, save. Now our story looks like this:

Important note -
ORIG_HEAD still points to the d79fb commit ... If we now execute the git checkout
command ORIG_HEAD , we will get the so-called detach
HEAD state. It is characterized by the fact that
HEAD points not to the top of the branch, but simply to commit.
HEAD should always point only to the top of any branch!

To “leave” the state of detach
HEAD, you simply switch to a branch or create a new branch with
git checkout -b new_branch_name
So, remember the second paragraph:
git reset
with the --soft
or --hard
moves the pointer to the top of the branch, and with it the HEAD pointer.
And the most important thing! The most frequent operation of the above when working with git `th is switching between branches. All other cases considered are rare, but nevertheless it is necessary to understand everything that happens when using them!
Have a nice trip to the history of your repository!
In preparing the material used the following sources:
The best manual book:
ProGitVisual Information on git:
A Visual Git Reference (
Russian version )
UPD:
In the comments advised another useful resource on git `y:
githowtoPS Thank you for the invite and wish you all a nice weekend!