We’re going to talk about three basic git commands in this episode:
reset. Instead of making up any abstractions or metaphors, we will focus straight on how these commands modify your repository’s internal state.
The state of a Git repository is, on the highest level, represented by a chain (or a graph) of commits. That’s exactly what the
git log command presents to you, for example.
Commits can be divided even further. For instance, each of them contains a reference to a tree object which in turn will eventually end up referencing one or more blob objects.
In a previous article (From Subversion to Git: Snapshots), we did an exploration of those. For now, the concept of a commit is sufficiently granular to reason about the three basic commands we are going to explore.
So let’s get started!
Here’s the state of a sample repo that contains an initial commit already:
o 55cd47f Initial Commit <--- master <--- HEAD
The repo has one branch, master, pointed to by HEAD. The numbers on the left (the commit hash) serve as a unique identifier for the initial commit.
1) git commit
We can use
commit to create a chain of commit objects. After applying the command two times, our repo will look like that:
o 55cd47f Initial Commit | o 6411a56 Second Commit | o 78bae34 Third Commit <--- master <--- HEAD
Each of these commit objects (or just commits) represents a snapshot of the entire repository, i.e. a certain state of the file system.
2) git checkout
In the previous listings, HEAD always pointed to the latest commit on the master branch.
To jump back and forth between commits, we can use
checkout. This will detach HEAD from the master branch and bring our working copy to the state stored in the commit we are jumping to. In other words: that commit will be checked out.
Here’s what happens after
git checkout 6411a56:
o 55cd47f Initial Commit | o 6411a56 Second Commit <--- HEAD | o 78bae34 Third Commit <--- master
Only HEAD changed. Apart from that, our working copy has been updated accordingly: it now represents the state we captured when creating commit 6411a56.
3) git reset
We’ve seen how to manipulate the HEAD pointer using
checkout. Similarly, we can use
reset to modify where branches point to.
Starting with the previous state of the repo, we can move master to the second commit using
git reset --hard 6411a56:
o 55cd47f Initial Commit | o 6411a56 Second Commit <--- master <--- HEAD | o 78bae34 Third Commit
What happened? By
resetting, we essentially moved the
master pointer to the second commit. Here it gets apparent that
reset can be quite a dangerous operation: the ‘Third Commit’ is now not referenced at all (i.e. branch or tag). This, in turn, means that it is subject to deletion by git’s garbage collector (
We have seen how to use three basic git commands to manipulate the state of a sample repository. We have talked about how to think about them in terms of the graph of commits maintained by git.
Refer to Pro Git to find out more!