git-reset - Set HEAD or the index to a known state
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
git reset [-q] [<tree-ish>] [--] <pathspec>…
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>…]
git reset does either of the following:
-
git reset [<mode>] <commit> changes which commit HEAD points to. This makes it possible to undo various Git operations, for example commit, merge, rebase, and pull.
-
When you specify files or directories or pass --patch, git reset updates the staged version of the specified files.
-
git reset [<mode>] [<commit>] -
Set the current branch head (HEAD) to point at <commit>. Depending on <mode>, also update the working directory and/or index to match the contents of <commit>. <commit> defaults to HEAD. Before the operation, ORIG_HEAD is set to the tip of the current branch.
The <mode> must be one of the following (default --mixed):
-
--mixed -
Leave your working directory unchanged. Update the index to match the new HEAD, so nothing will be staged.
If -N is specified, mark removed paths as intent-to-add (see git-add[1]).
-
--soft -
Leave your working tree files and the index unchanged. For example, if you have no staged changes, you can use git reset --soft HEAD~5; git commit to combine the last 5 commits into 1 commit. This works even with changes in the working tree, which are left untouched, but such usage can lead to confusion.
-
--hard -
Overwrite all files and directories with the version from <commit>, and may overwrite untracked files. Tracked files not in <commit> are removed so that the working tree matches <commit>. Update the index to match the new HEAD, so nothing will be staged.
-
--merge -
Reset the index and update the files in the working tree that are different between <commit> and HEAD, but keep those which are different between the index and working tree (i.e. which have changes which have not been added). Mainly exists to reset unmerged index entries, like those left behind by git am -3 or git switch -m in certain situations. If a file that is different between <commit> and the index has unstaged changes, reset is aborted.
-
--keep -
Resets index entries and updates files in the working tree that are different between <commit> and HEAD. If a file that is different between <commit> and HEAD has local changes, reset is aborted.
-
--recurse-submodules -
--no-recurse-submodules -
When the working tree is updated, using --recurse-submodules will also recursively reset the working tree of all active submodules according to the commit recorded in the superproject, also setting the submodules' HEAD to be detached at that commit.
-
git reset [-q] [<tree-ish>] [--] <pathspec>... -
git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>] -
For all specified files or directories, set the staged version to the version from the given commit or tree (which defaults to HEAD).
This means that git reset <pathspec> is the opposite of git add <pathspec>: it unstages all changes to the specified file(s) or directories. This is equivalent to git restore --staged <pathspec>....
In this mode, git reset updates only the index (without updating the HEAD or working tree files). If you want to update the files as well as the index entries, use git-restore[1].
-
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...] -
Interactively select changes from the difference between the index and the specified commit or tree (which defaults to HEAD). The index is modified using the chosen changes.
This means that git reset -p is the opposite of git add -p, i.e. you can use it to selectively unstage changes. See the "Interactive Mode" section of git-add[1] to learn how to use the --patch option.
See "Reset, restore and revert" in git[1] for the differences between the three commands.
The tables below show what happens when running:
git reset --option target
to reset the HEAD to another commit (target) with the different reset options depending on the state of the files.
In these tables, A, B, C and D are some different states of a file. For example, the first line of the first table means that if a file is in state A in the working tree, in state B in the index, in state C in HEAD and in state D in the target, then git reset --soft target will leave the file in the working tree in state A and in the index in state B. It resets (i.e. moves) the HEAD (i.e. the tip of the current branch, if you are on one) to target (which has the file in state D).
working index HEAD target working index HEAD
----------------------------------------------------
A B C D --soft A B D
--mixed A D D
--hard D D D
--merge (disallowed)
--keep (disallowed) working index HEAD target working index HEAD
----------------------------------------------------
A B C C --soft A B C
--mixed A C C
--hard C C C
--merge (disallowed)
--keep A C C working index HEAD target working index HEAD
----------------------------------------------------
B B C D --soft B B D
--mixed B D D
--hard D D D
--merge D D D
--keep (disallowed) working index HEAD target working index HEAD
----------------------------------------------------
B B C C --soft B B C
--mixed B C C
--hard C C C
--merge C C C
--keep B C C working index HEAD target working index HEAD
----------------------------------------------------
B C C D --soft B C D
--mixed B D D
--hard D D D
--merge (disallowed)
--keep (disallowed) working index HEAD target working index HEAD
----------------------------------------------------
B C C C --soft B C C
--mixed B C C
--hard C C C
--merge B C C
--keep B C C git reset --merge is meant to be used when resetting out of a conflicted merge. Any mergy operation guarantees that the working tree file that is involved in the merge does not have a local change with respect to the index before it starts, and that it writes the result out to the working tree. So if we see some difference between the index and the target and also between the index and the working tree, then it means that we are not resetting out from a state that a mergy operation left after failing with a conflict. That is why we disallow --merge option in this case.
git reset --keep is meant to be used when removing some of the last commits in the current branch while keeping changes in the working tree. If there could be conflicts between the changes in the commit we want to remove and the changes in the working tree we want to keep, the reset is disallowed. That’s why it is disallowed if there are both changes between the working tree and HEAD, and between HEAD and the target. To be safe, it is also disallowed when there are unmerged entries.
The following tables show what happens when there are unmerged entries:
working index HEAD target working index HEAD
----------------------------------------------------
X U A B --soft (disallowed)
--mixed X B B
--hard B B B
--merge B B B
--keep (disallowed) working index HEAD target working index HEAD
----------------------------------------------------
X U A A --soft (disallowed)
--mixed X A A
--hard A A A
--merge A A A
--keep (disallowed) X means any state and U means an unmerged index.