libgit2/libgit2 — pull request #1545 by ethomson (2013-05-03 23:48:01+00:00)
Title: allow checkout to proceed when a dir to be removed is in use (win32)

On win32, one may not remove a directory that is the current working directory of any process. (Or the parent thereof.) Thus, if somebody is to execute a checkout that would remove an in-use directory, we will fail halfway through the checkout.

The most likely culprit here is that somebody has their shell open to that directory.

Core git will prompt the user here, allowing them to retry or to simply continue without removing the directory:

Deletion of directory 'foo' failed. Should I try again? (y/n) y
Deletion of directory 'foo' failed. Should I try again? (y/n) y
Deletion of directory 'foo' failed. Should I try again? (y/n) y
Deletion of directory 'foo' failed. Should I try again? (y/n) n
Switched to branch 'd'

To cope, add a `GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES` that will simply leave in-use directories on-disk. Some plumbing to `rmdir` is required to make this work, and to disambiguate the cases where win32 `rmdir` returns `EACCES` (that is to say, *all* cases return `EACCES`, unfortunately.)

Note that this is worsened by the fact that it is non-obvious that we remove directories that would be added back. Imagine that two branches exist that have files beneath the same directory but no files in common. Eg, branch A has `dir/A` and branch B has `dir/B`. We will remove `dir` (after removing `dir/A`) then add it back for `dir/B`. This implementation detail is not obvious to the user, who expects that they should be able to be in the directory when this checkout occurs.