Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git reset vs git reset HEAD

Tags:

Every time a file has been staged, Git offers helpful instructions in the event you needed to unstage a file:

(use "git reset HEAD <file>..." to unstage)

However the decent Git Tutorials by Atlassian simply say:

git reset <file>

This seems more straightforward, so why the difference?

like image 528
skube Avatar asked Nov 21 '15 23:11

skube


People also ask

What is git reset head?

The git reset HEAD~2 command moves the current branch backward by two commits, effectively removing the two snapshots we just created from the project history. Remember that this kind of reset should only be used on unpublished commits.

What is the difference between git reset and git reset -- hard?

git reset --soft , which will keep your files, and stage all changes back automatically. git reset --hard , which will completely destroy any changes and remove them from the local directory. Only use this if you know what you're doing.

Does git reset HEAD keep changes?

The easiest way to undo the last Git commit is to execute the “git reset” command with the “–soft” option that will preserve changes done to your files. You have to specify the commit to undo which is “HEAD~1” in this case. The last commit will be removed from your Git history.

What does git reset soft head do?

When using git reset --soft HEAD~1 you will remove the last commit from the current branch, but the file changes will stay in your working tree. Also the changes will stay on your index, so following with a git commit will create a commit with the exact same changes as the commit you "removed" before.


Video Answer


2 Answers

No difference (from git reset man page) in term of default parameter:

The <tree-ish>/<commit> defaults to HEAD in all forms.

That message initially did not include HEAD: commit 3c1eb9c, Jan. 2007, git 1.5.0-rc1, but since the default is not always known, the help message makes it clear to which commit you are supposed to reset.

HEAD appears in commit 367c988, Nov. 2007, Git 1.5.4:

# On branch master # Changes to be committed: #   (use "git reset HEAD <file>..." to unstage) 

torek points out an actual difference in the comments:

By specifying HEAD, you guarantee that the first word after HEAD is taken as a path name.
For instance, suppose you run git reset zorg. Is zorg a tree-ish, such as a tag name, or is it a path name, ./zorg?
Git's answer is: it's a tree-ish if git rev-parse can turn it into a tree ID, otherwise it's a path.
You can either write git reset -- zorg or git reset HEAD zorg to make sure that git treats it as a path.

See more on the double hyphen syntax ( -- ) in "Deleting a badly named git branch".




The OP skube adds in the comments:

As an aside, they do suggest it for discarding changes in working directory
(i.e git checkout -- <file>).
It just seems inconsistent with git reset HEAD <file>.

While git reset man page clearly indicates the lack of tree-ish in git reset <tree-ish> -- <paths> means HEAD, it is not so for git checkout <tree-ish> -- <paths>.

git checkout <tree-ish> -- <pathspec> 

When <paths> are given, git checkout does not switch branches.
It updates the named paths in the working tree from the index file or from a named <tree-ish> (most often a commit).

That means git checkout -- path will override the working tree with what has already been staged (git add'ed).
While git reset -- PATH (being the mixed form of git reset) will reset the index with what HEAD contains (effectively un-staging what was added)

git reset and git checkout don't use the same default, and:

  • you can represent the default tree for git reset <tree-ish> <file>: HEAD.
    Hence git reset HEAD <file>;
  • but you cannot represent the default parameter when you don't provide a tree for git checkout: it is the index.
    Hence git checkout -- file.

The -- has to be used in the git checkout case, since there is only one parameter, and it needs to be clear that parameter represents files.

Note that git checkout HEAD files is different: torek mentions in the comments

git checkout HEAD path copies from the HEAD commit (the tree-ish) to the index and then on to the working dir.


Note: with Git 2.23+, August 2019, you might use git restore instead

See the examples:

To restore a file in the index to match the version in HEAD (this is the same as using git-reset)

$ git restore --staged hello.c 

man page:

git restore --staged hello.c does not specify a source, and restore the index only (--staged): it does so (by default) using HEAD as source.

By default, the restore sources for working tree and the index are the index and HEAD respectively.
--source could be used to specify a commit as the restore source.

Other examples:

You can restore both the index and the working tree (this the same as using git-checkout)

$ git restore --source=HEAD --staged --worktree hello.c 

or the short form which is more practical but less readable:

$ git restore -s@ -SW hello.c 

git restore is a more natural command name, and has no ambiguity.

like image 162
VonC Avatar answered Sep 29 '22 20:09

VonC


By default, git reset is equivalent to git reset HEAD

Quoting the man page (my emphasis):

git-reset - Reset current HEAD to the specified state.

git reset [-q] [<tree-ish>] [--] <paths>… git reset (--patch | -p) [<tree-ish>] [--] [<paths>…​] git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>] 

In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The <tree-ish>/<commit> defaults to HEAD in all forms.

[...]

git reset [-q] [<tree-ish>] [--] <paths>…​ 

This form resets the index entries for all <paths> to their state at <tree-ish>. (It does not affect the working tree or the current branch.)

This means that git reset <paths> is the opposite of git add <paths>.

From this you see that there's no actual difference in behavior.

This seems more straightforward, so why the difference?

Since they're both the same, you might as well use the shortest version of the two.

like image 45
code_dredd Avatar answered Sep 29 '22 19:09

code_dredd