How do I discard changes in my working copy that are not in the index?

  • See also stackoverflow.com/questions/22620393/… – Cees Timmerman Feb 4 '16 at 17:11
  • 3
    git-clean only removes untracked files from the working tree git-scm.com/docs/git-clean – Gboyega Sep 15 '16 at 12:29
  • 11
    To clarify Asenar's comment above, git-clean -df can be dangerous. It will delete local untracked files (e.g. covered by a .gitignore) Read all below carefully and consider git checkout . instead – jacanterbury Oct 7 '16 at 8:05
  • 8
    'git clean -df ' Be warned! I tried that and lost key folders that are unable to be restored... Ouch! – Gabe Karkanis Oct 27 '16 at 21:01
  • 7
    hitting git status gives a suggestion on how to do that! git checkout -- . – Paulo Dec 21 '17 at 10:42

32 Answers 32

up vote 2187 down vote accepted

Another quicker way is:

git stash save --keep-index

Include --include-untracked if you'd want to be thorough about it.

After that, you can drop that stash with a git stash drop command if you like.

  • 105
    And to be thorough about it, you'd want --include-untracked as well. – T.J. Crowder Mar 23 '15 at 7:45
  • 7
    @KarimSamir: The question specifically asks about changes that are not in the index. The git reset command will discard changes in the index too. – Greg Hewgill Apr 12 '15 at 17:28
  • 106
    git checkout -- . is much faster – Frank Apr 17 '15 at 16:16
  • 31
    Neither the git stash, nor any variety of git checkout will discard unstaged deletes. According to the output of git status, the actual correct answer here is some flavor git reset HEAD – Chris Warth May 27 '15 at 22:27
  • 91
    This pollutes the stash stack. git checkout -- . does the job with one command only. – Felipe Tonello Sep 9 '15 at 11:17

For all unstaged files use:

git checkout -- .

For a specific file use:

git checkout path/to/file/to/revert

Make sure to include the period at the end.

  • 88
    This seems to be the git canonical way. i.e. exactly what git tells you to do if you type git status – ABMagil Aug 18 '14 at 16:01
  • 19
    Doesn't work if there are untracked files. Git says error: The following untracked working tree files would be overwritten by checkout: .... – Michael Iles Aug 24 '14 at 13:26
  • 73
    newbie question, what does "git checkout -- ." mean semantically? – kaid Sep 7 '14 at 19:21
  • 95
    @Ninjack git checkout -- . means the same thing as git checkout ., except that you're explicit about the fact that you're not specifying the branch name. They both say checkout the HEAD version on the branch I am currently on for '.' or './'. If you do git checkout branch-name directory-or-file-name in general, you get the HEAD version of directory-or-file-name on branch branch-name. – akgill Oct 29 '14 at 19:55
  • 17
    IMO this variant is imperfect, as it doesn't handle situation when your changed repository is not on the HEAD revision at the moment of changes cleaning and you DO NOT want to update it to HEAD, and want to just clean the changes. – alexykot Jan 5 '15 at 17:27

It seems like the complete solution is:

git clean -df
git checkout -- .

git clean removes all untracked files (warning: while it won't delete ignored files mentioned directly in .gitignore, it may delete ignored files residing in folders) and git checkout clears all unstaged changes.

  • 93
    The other two answers don't actually work, this one did. – John Hunt Sep 1 '14 at 12:23
  • 14
    @dval this is becues the first command removed the unindexed files and the second one removed the unstaged changes (of indexed files). So if you did not have any staged changes this it is the same as reverting to the last commit with git reset --hard – Amanuel Nega Oct 31 '14 at 10:47
  • 3
    use -dff if the untracked directory is a git clone. – accuya Dec 16 '14 at 2:52
  • 77
    Be careful running git clean -df. If you don't understand what it does, you might be deleting files you mean to keep, like robots.txt, uploaded files, etc. – ctlockey Jan 28 '15 at 14:57
  • 31
    As @ctlockey said, the first command also delete directories if they are composed of ignored files only... Lost a whole bunch of configuration files on my project :( Be careful. – Maxime Lorant Jul 16 '15 at 8:00

This checks out the current index for the current directory, throwing away all changes in files from the current directory downwards.

git checkout .

or this which checks out all files from the index, overwriting working tree files.

git checkout-index -a -f
  • 23
    Hi, what is the difference between git checkout . and git checkout -- .? – Evan Hu Jan 18 '15 at 5:10
  • 2
    @Evan: No difference in this case. – Robert Siemer Apr 19 '15 at 13:48
  • 5
    @Robert Siemer and in the general case? – RJFalconer Jun 5 '15 at 12:20
  • 1
    @Evan: bad place to ask this question. – It is unrelated to the question of the OP, and unrelated to the answer here. – Robert Siemer Jun 5 '15 at 13:53
  • 10
    +1 This is the RIGHT ANSWER, as it correctly handles the case where some files have both staged and un-staged changes. Note that this solution DISCARDS the unstaged changes; if you wish to retain them, then you should use @greg-hewgill 's answer of git stash save --keep-index. – Rhubbarb Jun 15 '15 at 15:12
git clean -df

Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.

-d: Remove untracked directories in addition to untracked files

-f: Force (might be not necessary depending on clean.requireForce setting)

Run git help clean to see the manual

  • why this answer doesn't have all the votes? answered back in the 2011 and still correct. – Eugene Braginets Mar 1 at 13:20

My favorite is

git checkout -p

That lets you selectively revert chunks.

See also:

git add -p
  • 8
    I love the ability to see the actual change before it's discarded. – Penghe Geng Feb 3 '15 at 21:42
  • This is what I use. git checkout -p and then "a" to accept all. – Mattis Apr 24 '15 at 6:51
  • 1
    I've never thought about. That -p adds a nice extra layer of safety. Combine it with git clean -d to actually answer OP. – Stephan Henningsen Apr 27 '16 at 6:39

Since no answer suggests the exact option combination that I use, here it is:

git clean -dfx
git checkout .

This is the online help text for the used git clean options:

-d

Remove untracked directories in addition to untracked files. If an untracked directory is managed by a different Git repository, it is not removed by default. Use -f option twice if you really want to remove such a directory.

-f

If the Git configuration variable clean.requireForce is not set to false, Git clean will refuse to delete files or directories unless given -f, -n, or -i. Git will refuse to delete directories within the .git subdirectory or file, unless a second -f is given.

-x

Don’t use the ignore rules from .gitignore (per directory) and $GIT_DIR/info/exclude, but do still use the ignore rules given with -e options. This allows removing all untracked files, including build products. This can be used (possibly in conjunction with git reset) to create a pristine working directory to test a clean build.

Also, git checkout . needs to be done in the root of the repo.

  • +1 for this solution. Regarding your remark that "git checkout . needs to be done in the root of the repo", maybe you might mention we can just do git reset --hard instead? (which is actually equivalent to git reset --hard HEAD and should work whichever is the current directory...) – ErikMD Jan 15 at 20:19
  • Also regarding the first command git clean -dfx, here is a tip I use to be on the safe side before running it: just run git clean -d -x -n before, to display the list of files-to-be-removed, then confirm the operation by running git clean -d -x -f (I put the argument -n, resp. -f in the end to be able to quickly change it in a terminal) – ErikMD Jan 15 at 20:33
  • 1
    Quick note that this is unreversable, and if you have files in .gitignore you will lose them. So consider backing up your project before this. – Rob Apr 3 at 3:47

I really found this article helpful for explaining when to use what command: http://www.szakmeister.net/blog/2011/oct/12/reverting-changes-git/

There are a couple different cases:

  1. If you haven't staged the file, then you use git checkout. Checkout "updates files in the working tree to match the version in the index". If the files have not been staged (aka added to the index)... this command will essentially revert the files to what your last commit was.

    git checkout -- foo.txt

  2. If you have staged the file, then use git reset. Reset changes the index to match a commit.

    git reset -- foo.txt

I suspect that using git stash is a popular choice since it's a little less dangerous. You can always go back to it if you accidently blow too much away when using git reset. Reset is recursive by default.

Take a look at the article above for further advice.

The easiest way to do this is by using this command:

This command is used to discard changes in working directory -

git checkout -- .

https://git-scm.com/docs/git-checkout

In git command, stashing of untracked files is achieved by using:

git stash -u

http://git-scm.com/docs/git-stash

  • 11
    Twice I've come here, read this answer, and forgotten the . at the end. To future me: the period is essential! – bejado Jun 16 '17 at 17:13
  • 1
    I needed to get rid of all local changes in a sub directory, without blowing away every other change. This answer helped a lot, thanks – Ally Sep 7 '17 at 4:00
  • 1
    Please describe what the two commands do. It's really unhelpful to have no explanation. – Chris Kennedy Sep 9 '17 at 17:22
  • 1
    excellent. the checkout does in one command what the most popular one does in two. can also be followed up with git clean -fd to clean files not in the index. – oligofren Nov 28 '17 at 9:03

If you aren't interested in keeping the unstaged changes (especially if the staged changes are new files), I found this handy:

git diff | git apply --reverse
  • 6
    this misses any untracked files, which may be a good thing – flickerfly Dec 22 '11 at 20:00

As you type git status, (use "git checkout -- ..." to discard changes in working directory) is shown.

e.g. git checkout -- .

  • 1
    Downvoted because it doesn't help to quickly discard all files. The three dots indicate that you are required to list all the files. This is especially bad if you need to discard tons of files at once, eg. during a large merge after you have staged all the modifications you like to keep – usr-local-ΕΨΗΕΛΩΝ Jun 9 '16 at 15:26
  • 2
    Of course, the correct command is "git checkout -- ." a single dot. In the comment, the three dots were a grammatical thing, to indicate there are many other options that could have been used.. – Josef.B Sep 20 '16 at 11:01

git checkout -f


man git-checkout:

-f, --force

When switching branches, proceed even if the index or the working tree differs from HEAD. This is used to throw away local changes.

When checking out paths from the index, do not fail upon unmerged entries; instead, unmerged entries are ignored.

  • 2
    This would discard changes in the index!! (And the OP requires to leave them as is.) – Robert Siemer Apr 19 '15 at 13:59

You can use git stash - if something goes wrong, you can still revert from the stash. Similar to some other answer here, but this one also removes all unstaged files and also all unstaged deletes:

git add .
git stash

if you check that everything is OK, throw the stash away:

git stash drop

The answer from Bilal Maqsood with git clean also worked for me, but with the stash I have more control - if I do sth accidentally, I can still get my changes back

UPDATE

I think there is 1 more change (don't know why this worked for me before):

git add . -A instead of git add .

without the -A the removed files will not be staged

Instead of discarding changes, I reset my remote to the origin. Note - this method is to completely restore your folder to that of the repo.

So I do this to make sure they don't sit there when I git reset (later - excludes gitignores on the Origin/branchname)

NOTE: If you want to keep files not yet tracked, but not in GITIGNORE you may wish to skip this step, as it will Wipe these untracked files not found on your remote repository (thanks @XtrmJosh).

git add --all

Then I

git fetch --all

Then I reset to origin

git reset --hard origin/branchname

That will put it back to square one. Just like RE-Cloning the branch, WHILE keeping all my gitignored files locally and in place.

Updated per user comment below: Variation to reset the to whatever current branch the user is on.

git reset --hard @{u}
  • This is my preferred option, but why do you add all changes first? So far as I'm aware this just modifies the directory listing in Git files, while using git reset --hard, this will be lost anyway while the directories will still be removed. – XtrmJosh Sep 30 '15 at 10:00
  • I dont on mac or linux, github windows powershell sometimes leaves the files there after reset. I think its because git reset sets all files in the repo to its original state. If theyre not added, theyre not touched. The desktop client then will pickup the "hey this file is in here and needs to be committed" – Nick Oct 1 '15 at 17:04
  • Sense made. I don't use Windows so haven't seen that issue (haven't used Windows for the last few months at least, don't remember much before that - it's one huge regrettable blur). Might be worth noting the rationale in your main answer :) – XtrmJosh Oct 2 '15 at 12:18
  • I ran across this issue on a Mac too now. If the file is not tracked in the Repo sometimes git reset doesnt touch it. I cant really isolate the "WHY" but when that happens, if I reset, and i still have 1 uncommitted file or two, i add --all and reset --hard again – Nick Nov 19 '15 at 2:18
  • 2
    A nice little variation of this I like is git reset --hard @{u} which resets the branch to wherever the current remote-tracking branch is – user2221343 Jan 6 '16 at 19:39

Tried all the solutions above but still couldn't get rid of new, unstaged files.

Use git clean -f to remove those new files - with caution though! Note the force option.

If you merely wish to remove changes to existing files, use checkout (documented here).

git checkout -- .
  • No branch is specified, so it checks out the current branch.
  • The double-hyphen (--) tells Git that what follows should be taken as its second argument (path), that you skipped specification of a branch.
  • The period (.) indicates all paths.

If you want to remove files added since your last commit, use clean (documented here):

git clean -i 
  • The -i option initiates an interactive clean, to prevent mistaken deletions.
  • A handful of other options are available for a quicker execution; see the documentation.

If you wish to move changes to a holding space for later access, use stash (documented here):

git stash
  • All changes will be moved to Git's Stash, for possible later access.
  • A handful of options are available for more nuanced stashing; see the documentation.

Just use:

git stash -u

Done. Easy.

If you really care about your stash stack then you can follow with git stash drop. But at that point you're better off using (from Mariusz Nowak):

git checkout -- .
git clean -df

Nonetheless, I like git stash -u the best because it "discards" all tracked and untracked changes in just one command. Yet git checkout -- . only discards tracked changes, and git clean -df only discards untracked changes... and typing both commands is far too much work :)

  • Note: git stash -u will soon (Git 2.14.x/2.15, Q3 2017) evolve a bit: stackoverflow.com/a/46027357/6309 – VonC Sep 3 '17 at 20:10
  • If i get the question of the OP correct the indexed files should be kept. Only unstage changes should be removed. So is should be git stash -k in my opinion. – snap Feb 1 at 8:19

simply say

git stash

It will remove all your local changes. You also can use later by saying

git stash apply 

or git stash pop

This works even in directories that are; outside of normal git permissions.

sudo chmod -R 664 ./* && git checkout -- . && git clean -dfx

Happened to me recently

  • Beware though, that the git ignored content will not retain it's original permissions! Hence it can cause a security risk. – twicejr Dec 10 '14 at 18:06
  • @twicejr You're wrong, please read git help clean "-d Remove untracked directories in addition to untracked files." – GlassGhost Dec 10 '14 at 22:40
  • Why did you set all your files to be world read/write? Not good practice. – Ghoti Sep 28 '15 at 11:31
  • @Ghoti my bad, 664 is correct? you're also welcome to edit the answer. – GlassGhost Sep 28 '15 at 13:29
cd path_to_project_folder  # take you to your project folder/working directory 
git checkout .             # removes all unstaged changes in working directory

Another way to get rid of new files that is more specific than git clean -df (it will allow you to get rid of some files not necessarily all), is to add the new files to the index first, then stash, then drop the stash.

This technique is useful when, for some reason, you can't easily delete all of the untracked files by some ordinary mechanism (like rm).

In my opinion,

git clean -df

should do the trick. As per Git documentation on git clean

git-clean - Remove untracked files from the working tree

Description

Cleans the working tree by recursively removing files that are not under version control, starting from the current directory.

Normally, only files unknown to Git are removed, but if the -x option is specified, ignored files are also removed. This can, for example, be useful to remove all build products.

If any optional ... arguments are given, only those paths are affected.

Options

-d Remove untracked directories in addition to untracked files. If an untracked directory is managed by a different Git repository, it is not removed by default. Use -f option twice if you really want to remove such a directory.

-f --force If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to run unless given -f, -n or -i.

No matter what state your repo is in you can always reset to any previous commit:

git reset --hard <commit hash>

This will discard all changes which were made after that commit.

  • This will also discard everything in the index (not just things not in the index), which is beyond what the OP is asking for. – Linus Arver Jul 8 at 7:51

What follows is really only a solution if you are working with a fork of a repository where you regularly synchronize (e.g. pull request) with another repo. Short answer: delete fork and refork, but read the warnings on github.

I had a similar problem, perhaps not identical, and I'm sad to say my solution is not ideal, but it is ultimately effective.

I would often have git status messages like this (involving at least 2/4 files):

$ git status
# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   doc/PROJECT/MEDIUM/ATS-constraint/constraint_s2var.dats
#       modified:   doc/PROJECT/MEDIUM/ATS-constraint/parsing/parsing_s2var.dats
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   doc/PROJECT/MEDIUM/ATS-constraint/constraint_s2Var.dats
#       modified:   doc/PROJECT/MEDIUM/ATS-constraint/parsing/parsing_s2Var.dats

A keen eye will note that these files have dopplegangers that are a single letter in case off. Somehow, and I have no idea what led me down this path to start with (as I was not working with these files myself from the upstream repo), I had switched these files. Try the many solutions listed on this page (and other pages) did not seem to help.

I was able to fix the problem by deleting my forked repository and all local repositories, and reforking. This alone was not enough; upstream had to rename the files in question to new filenames. As long as you don't have any uncommited work, no wikis, and no issues that diverge from the upstream repository, you should be just fine. Upstream may not be very happy with you, to say the least. As for my problem, it is undoubtedly a user error as I'm not that proficient with git, but the fact that it is far from easy to fix points to an issue with git as well.

When you want to transfer a stash to someone else:

# add files
git add .  
# diff all the changes to a file
git diff --staged > ~/mijn-fix.diff
# remove local changes 
git reset && git checkout .
# (later you can re-apply the diff:)
git apply ~/mijn-fix.diff

[edit] as commented, it ís possible to name stashes. Well, use this if you want to share your stash ;)

  • 5
    Actually Git stash can have a title. For instance git stash save "Feature X work in progress". – Colin D Bennett Dec 9 '14 at 22:39

If all the staged files were actually committed, then the branch can simply be reset e.g. from your GUI with about three mouse clicks: Branch, Reset, Yes!

So what I often do in practice to revert unwanted local changes is to commit all the good stuff, and then reset the branch.

If the good stuff is committed in a single commit, then you can use "amend last commit" to bring it back to being staged or unstaged if you'd ultimately like to commit it a little differently.

This might not be the technical solution you are looking for to your problem, but I find it a very practical solution. It allows you to discard unstaged changes selectively, resetting the changes you don't like and keeping the ones you do.

So in summary, I simply do commit, branch reset, and amend last commit.

None of the solutions work if you just changed the permissions of a file (this is on DOS/Windoze)

Mon 23/11/2015-15:16:34.80 C:\...\work\checkout\slf4j+> git status
On branch SLF4J_1.5.3
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   .gitignore
        modified:   LICENSE.txt
        modified:   TODO.txt
        modified:   codeStyle.xml
        modified:   pom.xml
        modified:   version.pl

no changes added to commit (use "git add" and/or "git commit -a")

Mon 23/11/2015-15:16:37.87 C:\...\work\checkout\slf4j+> git diff
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
diff --git a/LICENSE.txt b/LICENSE.txt
old mode 100644
new mode 100755
diff --git a/TODO.txt b/TODO.txt
old mode 100644
new mode 100755
diff --git a/codeStyle.xml b/codeStyle.xml
old mode 100644
new mode 100755
diff --git a/pom.xml b/pom.xml
old mode 100644
new mode 100755
diff --git a/version.pl b/version.pl
old mode 100644
new mode 100755

Mon 23/11/2015-15:16:45.22 C:\...\work\checkout\slf4j+> git reset --hard HEAD
HEAD is now at 8fa8488 12133-CHIXMISSINGMESSAGES MALCOLMBOEKHOFF 20141223124940 Added .gitignore

Mon 23/11/2015-15:16:47.42 C:\...\work\checkout\slf4j+> git clean -f

Mon 23/11/2015-15:16:53.49 C:\...\work\checkout\slf4j+> git stash save -u
Saved working directory and index state WIP on SLF4J_1.5.3: 8fa8488 12133-CHIXMISSINGMESSAGES MALCOLMBOEKHOFF 20141223124940 Added .gitignore
HEAD is now at 8fa8488 12133-CHIXMISSINGMESSAGES MALCOLMBOEKHOFF 20141223124940 Added .gitignore

Mon 23/11/2015-15:17:00.40 C:\...\work\checkout\slf4j+> git stash drop
Dropped refs/stash@{0} (cb4966e9b1e9c9d8daa79ab94edc0c1442a294dd)

Mon 23/11/2015-15:17:06.75 C:\...\work\checkout\slf4j+> git stash drop
Dropped refs/stash@{0} (e6c49c470f433ce344e305c5b778e810625d0529)

Mon 23/11/2015-15:17:08.90 C:\...\work\checkout\slf4j+> git stash drop
No stash found.

Mon 23/11/2015-15:17:15.21 C:\...\work\checkout\slf4j+> git checkout -- .

Mon 23/11/2015-15:22:00.68 C:\...\work\checkout\slf4j+> git checkout -f -- .

Mon 23/11/2015-15:22:04.53 C:\...\work\checkout\slf4j+> git status
On branch SLF4J_1.5.3
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   .gitignore
        modified:   LICENSE.txt
        modified:   TODO.txt
        modified:   codeStyle.xml
        modified:   pom.xml
        modified:   version.pl

no changes added to commit (use "git add" and/or "git commit -a")

Mon 23/11/2015-15:22:13.06 C:\...\work\checkout\slf4j+> git diff
diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
diff --git a/LICENSE.txt b/LICENSE.txt
old mode 100644
new mode 100755
diff --git a/TODO.txt b/TODO.txt
old mode 100644
new mode 100755
diff --git a/codeStyle.xml b/codeStyle.xml
old mode 100644
new mode 100755
diff --git a/pom.xml b/pom.xml
old mode 100644
new mode 100755
diff --git a/version.pl b/version.pl
old mode 100644
new mode 100755

The only way to fix this is to manually reset the permissions on the changed files:

Mon 23/11/2015-15:25:43.79 C:\...\work\checkout\slf4j+> git status -s | egrep "^ M" | cut -c4- | for /f "usebackq tokens=* delims=" %A in (`more`) do chmod 644 %~A

Mon 23/11/2015-15:25:55.37 C:\...\work\checkout\slf4j+> git status
On branch SLF4J_1.5.3
nothing to commit, working directory clean

Mon 23/11/2015-15:25:59.28 C:\...\work\checkout\slf4j+>

Mon 23/11/2015-15:26:31.12 C:\...\work\checkout\slf4j+> git diff

You could create your own alias which describes how to do it in a descriptive way.

I use the next alias to discard changes.


Discard changes in a (list of) file(s) in working tree

discard = checkout --

Then you can use it as next to discard all changes:

discard .

Or just a file:

discard filename

Otherwise, if you want to discard all changes and also the untracked files, I use a mix of checkout and clean:

Clean and discard changes and untracked files in working tree

cleanout = !git clean -df && git checkout -- .

So the use is simple as next:

cleanout

Now is available in the next Github repo which contains a lot of aliases:

If you are in case of submodule and no other solutions work try:

  • To check what is the problem (maybe a "dirty" case) use:

    git diff

  • To remove stash

    git submodule update

I had a weird situation where a file is always unstaged, this helps me to resolve.

git rm .gitattributes
git add -A
git reset --hard

protected by Community May 31 '14 at 9:57

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.