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 WarthMay 27 '15 at 22:27

115

This pollutes the stash stack. git checkout -- . does the job with one command only.
– Felipe TonelloSep 9 '15 at 11:17

@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.
– akgillOct 29 '14 at 19:55

21

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.
– alexykotJan 5 '15 at 17:27

The other two answers don't actually work, this one did.
– John HuntSep 1 '14 at 12:23

17

@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 NegaOct 31 '14 at 10:47

3

use -dff if the untracked directory is a git clone.
– accuyaDec 16 '14 at 2:52

85

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.
– ctlockeyJan 28 '15 at 14:57

37

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 LorantJul 16 '15 at 8:00

@Robert Siemer and in the general case?
– RJFalconerJun 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 SiemerJun 5 '15 at 13:53

12

+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.
– RhubbarbJun 15 '15 at 15:12

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.

+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...)
– ErikMDJan 15 '18 at 20:19

1

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)
– ErikMDJan 15 '18 at 20:33

4

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.
– RobApr 3 '18 at 3:47

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

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.

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.BSep 20 '16 at 11:01

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.
– XtrmJoshSep 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"
– NickOct 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 :)
– XtrmJoshOct 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
– NickNov 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
– user2221343Jan 6 '16 at 19:39

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 :)

Setting all permissions to 664 makes a lot of assumptions about what kind of permissions the project needs. I think using that part of the command will cause issues for some people.
– ianrandmckenzieNov 20 '18 at 17:12

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.

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).

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):

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.

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.

If it's almost impossible to rule out modifications of the files, have you considered ignoring them? If this statement is right and you wouldn't touch those files during your development, this command may be useful:

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).