What's the difference between "git reset" and "git checkout"?

Viewed 156341

I've always thought of git reset and git checkout as the same, in the sense that both bring the project back to a specific commit. However, I feel they can't be exactly the same, as that would be redundant. What is the actual difference between the two? I'm a bit confused, as the svn only has svn co to revert the commit.

ADDED

VonC and Charles explained the differences between git reset and git checkout really well. My current understanding is that git reset reverts all of the changes back to a specific commit, whereas git checkout more or less prepares for a branch. I found the following two diagrams quite useful in coming to this understanding:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

ADDED 3

From http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html, checkout and reset can emulate the rebase.

enter image description here

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

enter image description here

7 Answers

brief mnemonics:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD

Here's a clarification of the ambiguity:

  • git checkout will move the HEAD to another commit(could be a change using a branchname too), but:
    1. on whatever branch you are, the pointer to the tip of that branch(e.g., "main") will remain unchanged (so you might end up in a detached head state).

    2. Also, the staging area and the working directory will remain unchanged(in the similar state they were before the checkout).

Examples:

git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
  • git reset also moves the HEAD, however again, with two differences:

    1. It moves the pointer that points to the commit at the tip of the current branch too. For instance, let's say the pointer to the current branch is named "main", then you perform a git-reset, now, the main pointer will point to another commit, and the HEAD will point to that commit as well(well basically, HEAD points to that commit indirectly through pointing to the main pointer, it is still an attached head(!), but it doesn't make any difference here).

    2. Git-reset doesn't necessarily leave the staging area and the working directory on the same state they were in before the reset was performed. As you know, there are three types of reset: soft, mixed(default) and hard:

      • With the soft reset, the staging area and the working directory both remain in the state they've been on before the reset(similar to checkout in this regard, but don't forget the difference #1).
      • With the mixed reset which is the default type of reset, in addition to difference #1, the staging area's proposed next commit(what you've git-added basically), will also be set to the newly pointed-to-by-HEAD commit. BUT in the working directory, all the files will still have your latest edits to them (that's why this type of reset is the default one, so that you don't lose your work).
      • With the hard reset, in addition to difference #1, all the three trees HEAD, staging-area and ALSO the working-directory will change to the newly pointed-to-by-HEAD commit.

Examples:

git reset --soft 3ad2bcf
git reset da3b47
Related