Why does git clean -xfd sometimes delete tracked files? How can we fix this?

Viewed 7919

From time to time, git clean -xfd will not only remove untracked files and directories but also remove tracked files. After cleaning I can restore those tracked files with git reset --hard head. So my flow tends to be:

git clean -xfd

git status               // check whether git deleted tracked files or not
git reset --hard head    // if git deleted tracked files restore them

I suspect that this over-zealous deletion might be related to having renamed a file or directory in a previous commit, and that the clean then deleted that renamed item. This is only a guess.

Is this a known issue? How can I fix it?

2 Answers

Having the same problem here. Simplified repository structure looks like this:

repository
|
|--dir1
|  |
|  |--junc_dir2
|
|--dir2
|  |
|  |--file
|
|--.gitignore

In the repo root, the folders dir1 and dir2 and one .gitignore file with the following content

dir1 # ignore dir1

The folder dir1 contains an NTFS junction to dir2. The folder dir2 contains a file.

The folder dir1 is ignored and not tracked. The folder dir2 and its child file are tracked.

You call git clean. It will recursively go through the contents of folder dir1 and delete them. That means it will go through the junction into dir2 and delete the one (tracked) file in there. Then going out, it will delete the dir2 junction and the dir1 folder. You will only be left with an empty dir2 folder and the .gitignore file.

Happened to me in the context of a node.js project which contained multiple packages cross-referencing themselves locally (using npm i ../path/to/package). See https://github.com/npm/npm/issues/19091

This can happen on Windows when using directory junctions. See also https://github.com/git-for-windows/git/issues/607.

git init
mkdir tracked
echo content >tracked/file
git add tracked
git commit -m initial
cmd //c mklink //j link tracked
git clean -qdfx

The git clean at the end will delete tracked/file.

Node.js's NPM package manager uses directory junctions when installing local packages. Concretely, npm install file:path/to/package will create a directory junction at node_modules/package. Therefore, it is possible to run into this issue when using Node.js.

The only workaround I know so far is to not use junctions inside Git worktrees.

Related