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

8

521

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:

https://static.mcmap.net/file/mcmap/ZG-Ab5ovKREQZV0hXRyxZF_jZw20be/img651/1559/86421927.png https://static.mcmap.net/file/mcmap/ZG-Ab5ovKREQZV0hXRyxZF_jZw20be/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

Bumblebee answered 3/9, 2010 at 20:21 Comment(6)
have a look at git-scm.com/blog/2011/07/11/reset.htmlKiger
Re: "Is it wrong or overly simplified?" Yes, that first diagram is misleading regarding the difference between checkout and reset. (It may be OK regarding the -- files variants; I'm not sure.) That diagram makes it looks like the main difference is whether they affect the index or the WD. See my answer regarding that. The 2nd and 3rd diagrams are very helpful for seeing the real difference. The 4th and 5th diagrams are useful to check whether you understand what these commands do, but won't really help you get there.Velodrome
I found the section "Check it out" of the "Git Tools Reset Demystified" to give the most helpful summary.Delicatessen
prosseek: If you agree with @Velodrome that the first diagram is misleading, can you remove it, please?Delicatessen
Please note that checkout and reset only emulate the 2nd part of rebase, and additional steps (provided in the linked think-like-a-git.net article) are required to prevent loss of data.Cloud
Where is ADDED 2? 🧐Supraliminal
C
233
  • git reset is specifically about updating the index, moving the HEAD.
  • git checkout is about updating the working tree (to the index or the specified tree). It will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD).
    (actually, with Git 2.23 Q3 2019, this will be git restore, not necessarily git checkout)

By comparison, since svn has no index, only a working tree, svn checkout will copy a given revision on a separate directory.
The closer equivalent for git checkout would:

  • svn update (if you are in the same branch, meaning the same SVN URL)
  • svn switch (if you checkout for instance the same branch, but from another SVN repo URL)

All those three working tree modifications (svn checkout, update, switch) have only one command in git: git checkout.
But since git has also the notion of index (that "staging area" between the repo and the working tree), you also have git reset.


Thinkeye mentions in the comments the article "Reset Demystified ".

For instance, if we have two branches, 'master' and 'develop' pointing at different commits, and we're currently on 'develop' (so HEAD points to it) and we run git reset master, 'develop' itself will now point to the same commit that 'master' does.

On the other hand, if we instead run git checkout master, 'develop' will not move, HEAD itself will. HEAD will now point to 'master'.

So, in both cases we're moving HEAD to point to commit A, but how we do so is very different. reset will move the branch HEAD points to, checkout moves HEAD itself to point to another branch.

https://static.mcmap.net/file/mcmap/ZG-Ab5ovKRcpcC0xWRAQWRft/images/reset/reset-checkout.png

On those points, though:

LarsH adds in the comments:

The first paragraph of this answer, though, is misleading: "git checkout ... will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD)".
Not true: git checkout will update the HEAD even if you checkout a commit that's not a branch (and yes, you end up with a detached HEAD, but it still got updated).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo concurs in the comments:

@LarsH is correct.
The second bullet has a misconception about what HEAD is in will update the HEAD only if you checkout a branch.
HEAD goes wherever you are, like a shadow.
Checking out some non-branch ref (e.g., a tag), or a commit directly, will move HEAD. Detached head doesn't mean you've detached from the HEAD, it means the head is detached from a branch ref, which you can see from, e.g., git log --pretty=format:"%d" -1.

  • Attached head states will start with (HEAD ->,
  • detached will still show (HEAD, but will not have an arrow to a branch ref.
Calliopsis answered 3/9, 2010 at 20:29 Comment(14)
I'd say that git reset is about modifying branch "label" and optionally updating the index or working tree as a side-effect. git checkout is about updating the working tree and switching currently "selected" branch (the HEAD).Spec
@MikkoRantalainen nope. git reset is 100% about the HEAD. It works even in a detached HEAD mode (https://mcmap.net/q/12033/-why-did-my-git-repo-enter-a-detached-head-state), meaning where there is no branch(!). git checkout also works in a detached HEAD mode, or can be used to checkout a SHA1 in a detached HEAD mode: again no branch involved in that case.Calliopsis
Yes, git reset moves HEAD if file .git/HEAD contains an SHA-1. However, if it contains a ref:, it will move the branch pointed by that reference instead. For example, git checkout master && git reset --soft HEAD^ moves the master branch "label" to the parent SHA-1 of the current commit pointed by branch master, right? And the contents of file .git/HEAD is ref: refs/heads/master regardless if git reset is done or not.Spec
@MikkoRantalainen yes, .git/HEAD content doesn't change, but HEAD refers indirectly to a new SHA1 (even when the index and worktree remain unchanged for a reset --soft, as in https://mcmap.net/q/12024/-practical-uses-of-git-reset-soft)Calliopsis
My point was that if HEAD points to ref:, the branch pointed by ref is modified by git reset and in that case, git reset is about modifying the branch "label", not the HEAD itself. In practice, HEAD does point to different commit after the modification (due to modified branch) and if --mixed or --hard is used, the index and possibly working directory is modified, too.Spec
@MikkoRantalainen I see your point, even though changing the branch "label" is effectively changing... its HEAD ;)Calliopsis
Further reading for all lost souls sent here by a search engine, I think it's worth it: git-scm.com/blog/2011/07/11/reset.htmlCureall
@Cureall good reference. I have included it, along with a relevant extract, in the answer for more visibility.Calliopsis
The explanation from Reset Demystified is excellent. The first paragraph of this answer, though, is misleading: "git checkout ... will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD)". Not true ... git checkout will update the HEAD even if you checkout a commit that's not a branch (and yes, you end up with a detached HEAD, but it still got updated). Maybe I'm misunderstanding what you mean by "update"? git checkout a839e8f updates HEAD to point to commit a839e8f.Velodrome
@Cureall the link in your comment is broken -- the one included in the answer is working.Portis
@Velodrome is correct. The second bullet has a misconception about what HEAD is in will update the HEAD only if you checkout a branch. HEAD goes wherever you are, like a shadow. Checking out some non-branch ref (e.g., a tag), or a commit directly, will move HEAD. Detached head doesn't mean you've detached from the HEAD, it means the head is detached from a branch ref, which you can see from, e.g., git log --pretty=format:"%d" -1. attached head states will start with (HEAD ->, detached will still show (HEAD, but will not have an arrow to a branch ref.Falito
@DeNovo Thank you. I have included your comment in the answer for more visibility.Calliopsis
@Calliopsis thanks for including. This involves a common misconception about what HEAD is, see my answer to the "what is HEAD" question.Falito
It's easier just to manually update the file contents than to sort out all of these git commands.Blaney
B
75

In their simplest form, reset resets the index without touching the working tree, while checkout changes the working tree without touching the index.

Resets the index to match HEAD, working tree left alone:

git reset

Conceptually, this checks out the index into the working tree. To get it to actually do anything you would have to use -f to force it to overwrite any local changes. This is a safety feature to make sure that the "no argument" form isn't destructive:

git checkout

Once you start adding parameters it is true that there is some overlap.

checkout is usually used with a branch, tag or commit. In this case it will reset HEAD and the index to the given commit as well as performing the checkout of the index into the working tree.

Also, if you supply --hard to reset you can ask reset to overwrite the working tree as well as resetting the index.

If you current have a branch checked out out there is a crucial different between reset and checkout when you supply an alternative branch or commit. reset will change the current branch to point at the selected commit whereas checkout will leave the current branch alone but will checkout the supplied branch or commit instead.

Other forms of reset and commit involve supplying paths.

If you supply paths to reset you cannot supply --hard and reset will only change the index version of the supplied paths to the version in the supplied commit (or HEAD if you don't specify a commit).

If you supply paths to checkout, like reset it will update the index version of the supplied paths to match the supplied commit (or HEAD) but it will always checkout the index version of the supplied paths into the working tree.

Brittneybrittni answered 3/9, 2010 at 20:43 Comment(2)
It is untrue to say that "checkout" does not change the index : it changes it when used to go from a branch to another.Hurt
In their simplest form, reset resets the index without touching the working tree, while checkout changes the working tree without touching the index. : How confusing is that :|Semeiology
S
63

One simple use case when reverting change:
1. Use reset if you want to undo staging of a modified file.
2. Use checkout if you want to discard changes to unstaged file/s.

Sapient answered 28/1, 2016 at 2:54 Comment(2)
Perfect answer. Thank you.Sarisarid
Yes, also in a similarly simple way said aside from albeit precise but too lengthy comments about index and working tree, reset (resets index = commit on a branch), whereas checkout basically changes a branch (no matter that it can create a temporal branch from a commit = detached head)Richardo
V
20

The key difference in a nutshell is that reset moves the current branch reference, while checkout does not (it moves HEAD).

As the Pro Git book explains under Reset Demystified,

The first thing reset will do is move what HEAD points to. This isn’t the same as changing HEAD itself (which is what checkout does); reset moves the branch that HEAD is pointing to. This means if HEAD is set to the master branch (i.e. you’re currently on the master branch), running git reset 9e5e6a4 will start by making master point to 9e5e6a4. [emphasis added]

See also VonC's answer for a very helpful text and diagram excerpt from the same article, which I won't duplicate here.

Of course there are a lot more details about what effects checkout and reset can have on the index and the working tree, depending on what parameters are used. There can be lots of similarities and differences between the two commands. But as I see it, the most crucial difference is whether they move the tip of the current branch.

Velodrome answered 20/2, 2018 at 18:21 Comment(2)
Good feedback, in addition to my older answer. +1Calliopsis
Precise and on point!Imagine
E
6

brief mnemonics:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Esmeralda answered 17/11, 2019 at 6:31 Comment(0)
H
2

The two commands (reset and checkout) are completely different.

checkout X IS NOT reset --hard X

If X is a branch name, checkout X will change the current branch while reset --hard X will not.

Hurt answered 11/9, 2015 at 16:1 Comment(2)
But if X is a file or folder, then they are the same.Galvin
I think you are wrong. With 'checkout X' you just jump to the branch X. With 'reset --hard X' you discard all changes after X on your current brach. So your current branch will be changed in the latter case, not in the former case. Please correct me, if I am wrong.Goldina
C
2

git reset -> removes all the files from the staged area i.e it undos git add <files>

git reset <commit_ID> -> undos commits and staging of all files after the specified commit.

if added --hard with the reset command, then it removes the files from the staged area as well as deletes it from your directory.

git checkout <commit_ID> -> you are reverted back to that specified commit state but you are not in any branch.

if you type git branch -a, you will see that you are in

(HEAD detached at <commit_ID>)

.

as per the console:

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 switching back to a branch.

and you will be given two options:

  1. git switch -c <new-branch-name>: a new branch will be created from that commit and it will become your current branch.
  2. git switch -c -> it is basically undoing the checkout command which brings you back to your old branch.
Cay answered 28/3, 2023 at 7:31 Comment(0)
R
1

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
Rosin answered 2/10, 2021 at 5:40 Comment(1)
‘2. Also, the staging area and the working directory will remain unchanged(in the similar state they were before the checkout).’ This is incorrect, the working tree is updated according to the documentation of git checkout <branch>: ‘To prepare for working on <branch>, switch to it by updating the index and the files in the working tree, and by pointing HEAD at the branch. Local modifications to the files in the working tree are kept, so that they can be committed to the <branch>.’Compiler

© 2022 - 2024 — McMap. All rights reserved.