Skip to content

gix clone ignores global core.symlinks on Windows #1353

Open
@EliahKagan

Description

@EliahKagan

Current behavior 😯

On Windows, core.symlinks is intended to to false when not set, and in some installations is even set as false in the installation scope. Changing it, if done, is most often done in the global scope, such as by running git config --global core.symlinks true.

But gix clone never honors this global configuration.

Prior to gitoxide 0.36.0, it checked out regular-file stubs rather than symlinks, even on a Windows system where the user running it is capable of creating symlinks in the directory being checked out to, even if core.symlinks was globally set to true. It furthermore would set core.symlinks to false explicitly in the newly cloned repository's .git/config.

Starting in gitoxide 0.36.0, the behavior has changed, but the bug of disregarding core.symlinks in the global scope has remained. The current behavior is to check out symlinks as symlinks on a Windows system where the user running it is capable of creating symlinks in the directory being checked out to, even when core.symlinks is globally set to false.

(This also now happens when core.symlinks is globally unset and not otherwise specified, but even though that differs from the Git behavior, it is not itself obviously a bug or undesirable.)

gix does honor core.symlinks in the command scope, both with -c core.symlinks=true and with GIT_{CONFIG_KEY_VALUE}. But even in that case, gix clone sets a value in the local scope (in the reposiitory's .git/config) reflecting its determination of whether symlinks are supported.

This is not readily checkable on CI without tests specifically for it or other special effort, since the Windows runners for GitHub Actions customize core.symlinks, setting it to true for the installation, at installation time. This coincides with the behavior gix detects is available, in in any case technically involves the installation or system scope rather than the global scope.

Expected behavior 🤔

When core.symlinks is set to true explicitly in the global scope and it has not been overridden in the command scope, gix clone should attempt to check out symbolic links as symbolic links rather than as regular files. I believe it will still not do this as often as it should, though in most cases where it is desired that does now happen, since it creates symlinks when it detects it can.

When core.symlinks is set to false explicitly in the global scope and it has not been overridden in the command scope, gix clone should not attempt to check out symbolic links as symbolic links, but should instead create regular files. This is the expected behavior that, currently, is decisively not satisfied: the global configuration scope cannot currently be used to cause gix clone not to check out symlinks.

Git behavior

Git will check out symlinks as actual Windows symbolic links rather than as regular-file stubs, including in commands such as git clone.

Git also does not set this variable in the local scope. Local repository .git/config are not created with symlinks set in their [core] sections.

Steps to reproduce 🕹

Make the test repository

Create a repository with a symbolic link. For simplicity, it should be a symbolic link to a regular file in the repository, and thus not dangling/broken. (Besides simplicity, this also avoids confusion relating to the separate issue #1354.) This can be done with Git either on Windows or on a Unix-like system; I used Ubuntu, pushed to a remote, and cloned from a remote, to ensure that this bug was not specific to file:// remotes.

git init has-symlink
cd has-symlink
echo 'This is a regular file.' >target
ln -s target symlink
git commit -m 'Initial commit'

Alternatively, the has-symlink repository may be used. It was created that way (then minimal documentation was added in a second commit). It is used in the instructions below, which assume that either PowerShell or Git Bash is used.

Set core.symlinks to false globally and/or check that it is set

On a Windows system, run this command, at least if that has not already been done in your user account:

git config --global core.symlinks false

Checking that it is set in the global scope by running git config core.symlinks should show false.

Clone with gix clone and inspect the repository

On a Windows system in which you have the ability to create symlinks, in a location on a volume that supports them, clone the repository with gix:

gix clone git@github.com:EliahKagan/has-symlink.git

The clone succeeds, but inspecting the checked out files reveals that symlink is a symbolic link, even though it should have been created as a regular file due to the global core.symlinks value of false taken together with the absence of any other more narrowly scoped configuration that would override it.

ls -l has-symlink/symlink

In PowerShell, that shows output like:

    Directory: C:\Users\ek\src\has-symlink

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
la---           6/23/2024  1:31 AM              0 symlink -> target

To verify that gix set core.symlinks to true in the local configuration, inspect has-symlink/.git/config, or run this command, which outputs true:

git -C has-symlink config --local core.symlinks

Redo the clone with core.symlinks set to false in the command

To see how this differs from the behavior of gix when core.symlinks is provided on the command line, first delete the cloned repository:

  • In Git Bash, run: rm -rf has-symlink
  • In PowerShell, run: rm -r -fo has-symlink

Then try the clone again, but this time use the -c option to gix:

gix -c core.symlinks=false clone git@github.com:EliahKagan/has-symlink.git

Check the symlink entry again:

ls -l has-symlink/symlink

This time, that shows that it is a regular file on disk. For example, in PowerShell, it looks like:

    Directory: C:\Users\ek\src\has-symlink

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           6/23/2024  1:04 PM              6 symlink

However, it has still set core.symlinks to true in the newly cloned repository's local configuration. This still outputs false:

git -C has-symlink config --local core.symlinks

Thus the reason -c behaved differently was that it overrode the wrongly set false value that gix placed at repository level. Furthermore, using -c is an insufficient workaround because it is still set otherwise locally (though unsetting it locally after cloning it that way should be a sufficient workaround until a fix is available).

Optionally, compare to the behavior of Git

Deleting the cloned repository again and cloning it with git clone rather than gix clone shows the expected behavior, and -c does not need to be used.

The behavior of Git may go further than desired for gitoxide, however, since it defaults core.symlinks to false on Windows even when it is unset and the user is capable of creating symbolic links. My guess is that, when core.symlinks is unset in all scopes originally, then operating based on capabilities may be the intended behavior of gitoxide.

The key behavior of Git that gitoxide should but does not follow is that an explicit core.symlinks setting should be followed, at least whenever that is possible to do. Following an explicit value of false for core.symlinks is always possible to do.

Optionally, verify that other global configuration is honored

The problem is not that gix doesn't use global configuration in general. I verified this by temporarily breaking ssh for git and gix by running:

git config --global core.sshCommand foo   # Warning: breaks ssh in git until undone!

Then I attempted to clone a repository that I know I can otherwise clone with gix:

gix clone git@github.com:EliahKagan/gitoxide.git

As expected, this attempted to use the bogus foo implementation of SSH:

Error: Failed to invoke program "foo"

Caused by:
    program not found

To undo that, simply run:

git config --global --unset core.sshCommand

Metadata

Metadata

Assignees

Labels

C-WindowsWindows-specific issuesacknowledgedan issue is accepted as shortcoming to be fixedhelp wantedExtra attention is needed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions