Skip to content

Commit

Permalink
Merge pull request #906 from rpjday/reset_demystified
Browse files Browse the repository at this point in the history
Minor tweaks (grammar, fonts) to "Reset Demystified"
  • Loading branch information
ben authored Oct 30, 2017
2 parents 69497c3 + 577a249 commit b5c6ec5
Showing 1 changed file with 14 additions and 15 deletions.
29 changes: 14 additions & 15 deletions book/07-git-tools/sections/reset.asc
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[[_git_reset]]
=== Reset Demystified

Before moving on to more specialized tools, let's talk about `reset` and `checkout`.
Before moving on to more specialized tools, let's talk about the Git `reset` and `checkout` commands.
These commands are two of the most confusing parts of Git when you first encounter them.
They do so many things that it seems hopeless to actually understand them and employ them properly.
For this, we recommend a simple metaphor.

==== The Three Trees

An easier way to think about `reset` and `checkout` is through the mental frame of Git being a content manager of three different trees.
By ``tree'' here we really mean ``collection of files'', not specifically the data structure.
By ``tree'' here, we really mean ``collection of files'', not specifically the data structure.
(There are a few cases where the index doesn't exactly act like a tree, but for our purposes it is easier to think about it this way for now.)

Git as a system manages and manipulates three trees in its normal operation:
Expand All @@ -26,7 +26,7 @@ Git as a system manages and manipulates three trees in its normal operation:

HEAD is the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch.
That means HEAD will be the parent of the next commit that is created.
It's generally simplest to think of HEAD as the snapshot of *your last commit*.
It's generally simplest to think of HEAD as the snapshot of *your last commit on that branch*.

In fact, it's pretty easy to see what that snapshot looks like.
Here is an example of getting the actual directory listing and SHA-1 checksums for each file in the HEAD snapshot:
Expand All @@ -46,7 +46,7 @@ $ git ls-tree -r HEAD
040000 tree 99f1a6d12cb4b6f19... lib
----

The `cat-file` and `ls-tree` commands are ``plumbing'' commands that are used for lower level things and not really used in day-to-day work, but they help us see what's going on here.
The Git `cat-file` and `ls-tree` commands are ``plumbing'' commands that are used for lower level things and not really used in day-to-day work, but they help us see what's going on here.

[[_the_index]]
===== The Index
Expand All @@ -65,9 +65,9 @@ $ git ls-files -s
100644 47c6340d6459e05787f644c2447d2595f5d3a54b 0 lib/simplegit.rb
----

Again, here we're using `ls-files`, which is more of a behind the scenes command that shows you what your index currently looks like.
Again, here we're using `git ls-files`, which is more of a behind the scenes command that shows you what your index currently looks like.

The index is not technically a tree structure it's actually implemented as a flattened manifest but for our purposes it's close enough.
The index is not technically a tree structure -- it's actually implemented as a flattened manifest -- but for our purposes it's close enough.

===== The Working Directory

Expand Down Expand Up @@ -123,8 +123,7 @@ Next we run `git add` on it to stage it into our Index.

image::images/reset-ex5.png[]

At this point if we run `git status` we will see the file in green
under ``Changes to be committed'' because the Index and HEAD differ – that is, our proposed next commit is now different from our last commit.
At this point, if we run `git status`, we will see the file in green under ``Changes to be committed'' because the Index and HEAD differ -- that is, our proposed next commit is now different from our last commit.
Finally, we run `git commit` to finalize the commit.

image::images/reset-ex6.png[]
Expand Down Expand Up @@ -203,7 +202,7 @@ The `reset` command overwrites these three trees in a specific order, stopping w

That covers the behavior of `reset` in its basic form, but you can also provide it with a path to act upon.
If you specify a path, `reset` will skip step 1, and limit the remainder of its actions to a specific file or set of files.
This actually sort of makes sense HEAD is just a pointer, and you can't point to part of one commit and part of another.
This actually sort of makes sense -- HEAD is just a pointer, and you can't point to part of one commit and part of another.
But the Index and Working directory _can_ be partially updated, so reset proceeds with steps 2 and 3.

So, assume we run `git reset file.txt`.
Expand Down Expand Up @@ -237,7 +236,7 @@ So you can selectively unstage or revert content.

==== Squashing

Let's look at how to do something interesting with this newfound power squashing commits.
Let's look at how to do something interesting with this newfound power -- squashing commits.

Say you have a series of commits with messages like ``oops.'', ``WIP'' and ``forgot this file''.
You can use `reset` to quickly and easily squash them into a single commit that makes you look really smart.
Expand Down Expand Up @@ -269,11 +268,11 @@ Like `reset`, `checkout` manipulates the three trees, and it is a bit different
Running `git checkout [branch]` is pretty similar to running `git reset --hard [branch]` in that it updates all three trees for you to look like `[branch]`, but there are two important differences.

First, unlike `reset --hard`, `checkout` is working-directory safe; it will check to make sure it's not blowing away files that have changes to them.
Actually, it's a bit smarter than that it tries to do a trivial merge in the Working Directory, so all of the files you _haven't_ changed in will be updated.
Actually, it's a bit smarter than that -- it tries to do a trivial merge in the Working Directory, so all of the files you _haven't_ changed in will be updated.
`reset --hard`, on the other hand, will simply replace everything across the board without checking.

The second important difference is how it updates HEAD.
Where `reset` will move the branch that HEAD points to, `checkout` will move HEAD itself to point to another branch.
The second important difference is how `checkout` updates HEAD.
Whereas `reset` will move the branch that HEAD points to, `checkout` will move HEAD itself to point to another branch.

For instance, say we have `master` and `develop` branches which point at different commits, and we're currently on `develop` (so HEAD points to it).
If we run `git reset master`, `develop` itself will now point to the same commit that `master` does.
Expand All @@ -289,7 +288,7 @@ image::images/reset-checkout.png[]

The other way to run `checkout` is with a file path, which, like `reset`, does not move HEAD.
It is just like `git reset [branch] file` in that it updates the index with that file at that commit, but it also overwrites the file in the working directory.
It would be exactly like `git reset --hard [branch] file` (if `reset` would let you run that) it's not working-directory safe, and it does not move HEAD.
It would be exactly like `git reset --hard [branch] file` (if `reset` would let you run that) -- it's not working-directory safe, and it does not move HEAD.

Also, like `git reset` and `git add`, `checkout` will accept a `--patch` option to allow you to selectively revert file contents on a hunk-by-hunk basis.

Expand All @@ -299,7 +298,7 @@ Hopefully now you understand and feel more comfortable with the `reset` command,

Here's a cheat-sheet for which commands affect which trees.
The ``HEAD'' column reads ``REF'' if that command moves the reference (branch) that HEAD points to, and ``HEAD'' if it moves HEAD itself.
Pay especial attention to the 'WD Safe?' column if it says *NO*, take a second to think before running that command.
Pay especial attention to the 'WD Safe?' column -- if it says *NO*, take a second to think before running that command.

[options="header", cols="3,1,1,1,1"]
|================================
Expand Down

0 comments on commit b5c6ec5

Please sign in to comment.