git-for-windows / git

A fork of Git containing Windows-specific patches.
http://gitforwindows.org/
Other
8.36k stars 2.54k forks source link

Make the 'clean' command skip over unlink failures without user confirmation #3850

Open eur2fe opened 2 years ago

eur2fe commented 2 years ago

Setup

$ git --version --build-options

git version 2.36.1.windows.1
cpu: x86_64
built from commit: e2ff68a2d1426758c78d023f863bfa1e03cbc768
sizeof-long: 4
sizeof-size_t: 8
shell-path: /bin/sh
feature: fsmonitor--daemon
$ cmd.exe /c ver

Microsoft Windows [Version 10.0.19044.1645]
# One of the following:
> type "C:\Program Files\Git\etc\install-options.txt"
> type "C:\Program Files (x86)\Git\etc\install-options.txt"
> type "%USERPROFILE%\AppData\Local\Programs\Git\etc\install-options.txt"
> type "$env:USERPROFILE\AppData\Local\Programs\Git\etc\install-options.txt"
$ cat /etc/install-options.txt

Editor Option: VisualStudioCode
Custom Editor Path:
Default Branch Option: main
Path Option: Cmd
SSH Option: OpenSSH
Tortoise Option: false
CURL Option: WinSSL
CRLF Option: CRLFAlways
Bash Terminal Option: ConHost
Git Pull Behavior Option: Merge
Use Credential Manager: Enabled
Performance Tweaks FSCache: Enabled
Enable Symlinks: Disabled
Enable Pseudo Console Support: Disabled
Enable FSMonitor: Disabled

Details

First, let me say that I am very happy with Git for Windows!

I noticed when I run git clean -xdf, the behavior is different between Windows and Linux. When a file cannot be deleted, the Linux version just skips over the file delete and prints a warning. On Windows, there is an annoying prompt asking me what to do.

Now, I read [PATCH 0/3] mingw: make workaround for unlink failures interactive, I understand the reason why the delete fails, and I am aware of that I can simply close the application that keeps an open handle to the file (in this case Visual Studio), and that there is the environment variable GIT_ASK_YESNO that I can use to skip the prompts.

However, I am still unhappy with the available options:

Basically, what I am proposing is that an unlink failure of a clean command behaves differently that for instance a rebase command, because of the different severity of the failures. I would like to see the clean command to skip over delete failures while printing a warning, just as the Linux version does.

BTW, when I set set GIT_ASK_YESNO=false, the error message is incorrect (I would expect 'Access is denied' instead of 'Invalid argument')

warning: failed to remove .vs/MLLib/v16/Browse.VC.db: Access is denied
warning: failed to remove .vs/MLLib/v16/Browse.VC.db-shm: Access is denied
...
Unlink of file '.vs/MLLib/v16/Browse.VC.db' failed. Should I try again? (y/n) n
warning: failed to remove .vs/MLLib/v16/Browse.VC.db: Invalid argument
Unlink of file '.vs/MLLib/v16/Browse.VC.db-shm' failed. Should I try again? (y/n) n
warning: failed to remove .vs/MLLib/v16/Browse.VC.db-shm: Invalid argument
...
dscho commented 2 years ago

While I am sympathetic to the request, I have doubts that this will be easy to implement (and I would want you to implement it, too): currently, there is no abstraction in Git's source code for deleting files. All Git's source code does is to call unlink(). That's also what git clean does here and here.

For Windows, we have a shim that performs that interactive question.

However, the unlink() function has no indicator that the user wanted to ignore failures. There is no parameter for that.

To fix this, therefore, we would need to introduce a new abstraction, i.e. a new function that does take that parameter. It could be called delete_file, where git-compat-util.h would fall back to defining a thin shim that simply calls unlink(), and we'd #define it to int mingw_delete_file(const char *path, int flags) on Windows. We would then a new flag DELETE_FILE_NON_INTERACTIVE that could be passed to avoid the interactive dialog, and mingw_unlink() would then call this function with 0 as flags.

To get you started,

  1. install Git for Windows' SDK,
  2. sdk cd git,
  3. edit compat/mingw.c, compat/mingw.h and git-compat-util.h
  4. build Git via make -j$(nproc)
  5. test in-place via ./git --exec-path="$PWD" -C <directory> <command>?
  6. open a PR?
eur2fe commented 2 years ago

and I would want you to implement it, too

Fair enough. I will need some time to get familiar with the code base, and then see what I can do.

Thanks for the analysis and the getting started hints!

dscho commented 2 years ago

Thanks for the analysis and the getting started hints!

You're welcome! Please feel free to ask away in this ticket whenever you get stuck.