LinuxCommandLibrary

git-reset

Undo commits and changes

TLDR

Unstage everything

$ git reset
copy

Unstage specific file(s)
$ git reset [path/to/file1 path/to/file2 ...]
copy

Interactively unstage portions of a file
$ git reset [[-p|--patch]] [path/to/file]
copy

Undo the last commit, keeping its changes (and any further uncommitted changes) in the filesystem
$ git reset HEAD~
copy

Undo the last two commits, adding their changes to the index, i.e. staged for commit
$ git reset --soft HEAD~2
copy

Discard any uncommitted changes, staged or not (for only unstaged changes, use git checkout)
$ git reset --hard
copy

Reset the repository to a given commit, discarding committed, staged and uncommitted changes since then
$ git reset --hard [commit]
copy

SYNOPSIS

git reset [--soft | --mixed | --hard | --merge | --keep] [commit] [--] [path...]

PARAMETERS

commit
    The target commit to reset to. This can be a commit hash, branch name, tag, or a relative reference like HEAD~1. If omitted, it defaults to HEAD.

--soft
    Moves the HEAD pointer to the target commit. The index (staging area) and working directory are left completely untouched. Changes from the reset commits appear as staged changes, ready to be committed again.

--mixed
    (Default behavior) Moves the HEAD pointer to the target commit and updates the index to match it. The working directory remains unchanged. Changes are now in the working directory but unstaged.

--hard
    Moves the HEAD pointer, updates the index, and overwrites the working directory to match the target commit. All uncommitted changes and staged changes are irrevocably lost. Use with extreme caution.

--merge
    Resets the HEAD and index to the target commit, but keeps local changes in the working directory. Attempts a merge of the changes into the working directory; fails if there are conflicts.

--keep
    Resets the HEAD and index to the target commit, but only if the working directory has no uncommitted changes for the files that are tracked by the reset target. Useful for discarding some changes while preserving others.

--
    A separator used to distinguish between options and file paths. It's often used when a path might be mistaken for an option (e.g., if a file name starts with a hyphen).

path...
    One or more file or directory paths. When paths are specified, git reset typically operates only on the index, unstaging the specified files to match the commit (or HEAD if no commit is given), without moving the HEAD pointer.

DESCRIPTION

git reset is a powerful and versatile Git command used to undo changes, move the HEAD pointer, and manipulate the staging area (index) and the working directory. It operates primarily on "three trees" of Git: the HEAD commit (the last commit), the index (the staging area), and the working directory (your current files).

The command has three main modes, each affecting these trees differently:

--soft: This mode moves the HEAD pointer to the specified commit but leaves the index and working directory unchanged. This effectively unstages the commits that were "reset" off HEAD, making their changes appear as pending, ready to be restaged and recommitted.

--mixed (default): This mode, the default behavior, moves the HEAD pointer to the specified commit and then updates the index to match that commit. The working directory remains untouched. Changes that were part of the "reset" commits are now in your working directory but unstaged, allowing you to re-examine, modify, and re-add them.

--hard: This is the most drastic and destructive mode. It moves the HEAD pointer, updates the index, and overwrites the working directory to match the specified commit. All uncommitted changes in the working directory and the staging area are irrevocably lost. Use with extreme caution.

git reset can also be used with a pathspec to unstage specific files, leaving HEAD unchanged. It's an essential tool for managing changes before committing, correcting mistakes, and navigating through commit history.

CAVEATS

git reset --hard is destructive: It irrevocably discards all uncommitted changes in your working directory and staging area. If you haven't committed the changes, they are lost forever unless you can recover them via the reflog (which is not guaranteed).

Rewriting shared history: Using git reset to move HEAD on a branch that has already been pushed to a remote repository (i.e., shared history) will rewrite that history. This can cause significant problems for collaborators who have based their work on the old history. In such cases, git revert is generally the preferred and safer method for undoing commits.

Understanding 'The Three Trees': Misunderstanding how git reset interacts with HEAD, the index, and the working directory can lead to unintended data loss or confusion. Always be clear about which mode you are using and its implications.

THE THREE TREES OF GIT

To effectively use git reset, it's crucial to understand Git's core concept of "three trees" (or states):

HEAD: Represents the last commit on the current branch. It's the immutable history of your repository. This is where HEAD (the current branch tip or detached HEAD) points.

Index (Staging Area): Also known as the cache or staging area, this is a virtual snapshot of what your next commit will look like. When you run git add, you're updating the index.

Working Directory: These are the actual files and directories on your local filesystem that you are currently editing. This is where you make your changes.

Each mode of git reset specifically targets how these three trees are updated or left untouched, allowing precise control over your repository's state.

HISTORY

git reset has been a fundamental command since the early days of Git, providing a versatile way to manipulate commits, the index, and the working directory. Its different modes (--soft, --mixed, --hard) were designed to cover various "undo" scenarios. Over time, some of its functionalities, particularly those related to restoring files, have been refined and split into more specialized commands like git restore and git switch (starting from Git 2.23) to make the command set clearer and safer, reducing the "overload" of git checkout and git reset. Despite these newer commands, git reset remains central for managing HEAD and unstaging changes.

SEE ALSO

git revert(1), git restore(1), git checkout(1), git add(1), git commit(1)

Copied to clipboard