Checking out files into a working tree skips any individual files that already exist, reporting them correctly as collisions. This happens when overwriting is prohibited, as is the case in gix clone
. For example, if a separate application creates files inside the working tree gix clone
is checking out, and such a file would be overwritten in checked out, gix clone
declines to check out that specific file and reports it as a collision. This behavior is correct and should not be changed.
Like other operating systems that support symbolic links, Windows permits a symbolic link to point to a location that is inaccessible to the user creating the symbolic link, including to a location where, due to permissions, traversal to the location will fail due to permissions. The user will not be able to deference that symbolic link other than to inspect the target path, not even to check it's target's existence and metadata, but the symlink itself is no problem. Unlike other operating systems that support symbolic links, Windows symbolic links come in two varieties: file and directory symbolic links. For this reason, gitoxide attempts to check the metadata of the symlink's target.
The problem is that, when attempting to check the metadata of the symlink's target fails with a PermissionDenied
error, this is wrongly misinterpreted as a collision, even though there is no collision because the error happens in reading what the index specifies is the symlink's target, not when creating a new file. A wrong or unusual target of a symlink is never a real collision, because checkout does not create or mutate anything at the target.
This is what it looks like to use gix clone
to clone a repository with such a symlink:
C:\Users\ek\src> gix clone git@github.com:EliahKagan/symlink-to-inaccessible.git
20:53:39 indexing done 19.0 objects in 0.00s (60.9k objects/s)
20:53:39 decompressing done 3.6KB in 0.00s (11.2MB/s)
20:53:39 Resolving done 19.0 objects in 0.05s (377.0 objects/s)
20:53:39 Decoding done 3.6KB in 0.05s (70.9KB/s)
20:53:39 writing index file done 1.6KB in 0.00s (7.4MB/s)
20:53:39 create index file done 19.0 objects in 0.06s (343.0 objects/s)
20:53:39 read pack done 2.5KB in 0.09s (27.1KB/s)
20:53:39 checkout done 3.0 files in 0.00s (2.4k files/s)
20:53:39 writing done 1.4KB in 0.00s (1.1MB/s)
HEAD:refs/remotes/origin/HEAD (implicit)
77d5afef8ef5ff6f3af10ab900cd1a08e18fc1cc HEAD symref-target:refs/heads/main -> refs/remotes/origin/HEAD [new]
+refs/heads/*:refs/remotes/origin/*
77d5afef8ef5ff6f3af10ab900cd1a08e18fc1cc refs/heads/main -> refs/remotes/origin/main [new]
symlink: collision (PermissionDenied)
Error: One or more errors occurred - checkout is incomplete: encountered 1 collision(s)
The repository is created, but due to the symlink wrongly being detected as a collision, no symlink is created there:
C:\Users\ek\src> ls symlink-to-inaccessible
Directory: C:\Users\ek\src\symlink-to-inaccessible
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 6/25/2024 8:53 PM .git
-a--- 6/25/2024 8:53 PM 617 COPYING
-a--- 6/25/2024 8:53 PM 826 README.md
This is related to #1420. As there, the error occurs when attempting to access metadata on the symlink's target, which is only done on Windows, so this bug does not affect non-Windows systems, and which is only done when actually attempting to create symbolic links, so this bug does not affect uses of gix clone
where core.symlinks
has been forced to false
(though, as there, #1353 affects this).
Depending on how #1420 is fixed, the fix may automatically take care of this as well, by making it so no PermissionDenied
error can ever be propagated upward from a position where it doesn't represent a real collision. I had originally planned to report this as part of #1420. However, on reflection I decided these are separate bugs, because:
- Other ways of fixing that bug would not necessarily fix this, and vice versa.
- This bug has the additional wrong behavior of reporting a non-collision condition as a collision.
- This bug has the mitigating factor that it does not cause an entire clone to be canceled and the partially checked out working tree to be deleted (though the reason it doesn't do that is that it is wrongly treated as a collision).
- This bug is less straightforward to write a regression test for in the test suite. It can definitely be done, though. Whether it needs to be done, and whether it needs to be done before a change that fixes the bug is accepted, might depend on how this bug is fixed. If it is fixed together with #1420 then the tests for that might be considered enough. Otherwise, it probably needs its own tests.