Wilfred Hughes
Wilfred Hughes

Reputation: 31161

How do I reset the working tree without moving HEAD?

Given a git branch with some commits on it (C is the most recent commit):

A -> B -> C

How do I reset my workspace so that all the files are in the state they were at commit B, but HEAD is still at C?

I've looked at git-reset, but none of the options seem to help. The man page suggests that all the different modes will move HEAD:

--soft
   Does not touch the index file or the working tree at all 
   (but resets the head to <commit>, just like all modes do).

I've tried git reset HEAD~ but that moves HEAD.

Upvotes: 23

Views: 4830

Answers (4)

xaizek
xaizek

Reputation: 5252

git checkout [-p|--patch] [<tree-ish>] [--] <pathspec>...

git checkout with <paths> or --patch is used to restore modified or deleted paths to their original contents from the index or replace paths with the contents from a named <tree-ish> (most often a commit-ish).

So you need to run this at root of your repository (works fine for any sub-tree or file(s) too):

git checkout HEAD~ -- .

This will result in git applying changes necessary to revert files to HEAD~ state not counting file removals, the changes will be in the index. Add --no-overlay flag to allow removal of files added since HEAD~:

git checkout --no-overlay HEAD~ -- .

From man git-checkout (git v2.44.0):

--overlay, --no-overlay
In the default overlay mode, git checkout never removes files from the index or the working tree. When specifying --no-overlay, files that appear in the index and working tree, but not in <tree-ish> are removed, to make them match <tree-ish> exactly.

Upvotes: 20

sh-at-cs
sh-at-cs

Reputation: 167

As pointed out in this answer to a similar question, you can use git restore for that in Git 2.23+, like so:

git restore -s HEAD~ .

According to its manpage, git restore

[restores] specified paths in the working tree with some contents from a restore source.

You use -s (or --source) to specify which commit you want to use as the restore source (here HEAD~) and specify the path(s) to restore (here everything, so .) at the end.

Upvotes: 4

Mad Physicist
Mad Physicist

Reputation: 114300

You could use a combination of hard and soft resets:

git reset --hard B
git reset --soft C

The first would move HEAD to B and make all your files look like B. The second would then move it back to C without changing any files.

This method has the advantage that you are not in a detached-head state and all the differences between B and C will just show up as inverse diffs of your last actual commit. You will still be on your original branch.

You would probably have to specify C as a SHA-1 rather than a ref name, unless you specifically created one for the purpose.

Upvotes: 16

das_j
das_j

Reputation: 4794

Just use git checkout:

$ git checkout HEAD~
$ # Or
$ git checkout HEAD^
$ # Or
$ git checkout B

This will bring you into a detached head state where the HEAD is detached from a branch.

Upvotes: -1

Related Questions