I try to clone a repository with submodules and symlinks. I'm on Windows 10 and clone onto an NTFS SSD.
I'm cloning with
$git clone -c core.symlinks=true --recurse-submodules -b develop [email protected]/my-project.git
When cloned, the config contains the line symlinks = false
and the symlinks are not created.
I have to use
$git config core.symlinks true
$git reset --hard
after cloning to create the symlinks.
Why does it not work when cloning directly?
When the git clone
code creates the new (empty) repository, it uses the init_db
function, which ends with a block including this code:
/* Check if symlink is supported in the work tree */
path = git_path_buf(&buf, "tXXXXXX");
if (!close(xmkstemp(path)) &&
!unlink(path) &&
!symlink("testing", path) &&
!lstat(path, &st1) &&
S_ISLNK(st1.st_mode))
unlink(path); /* good */
else
git_config_set("core.symlinks", "false");
Since you are getting an explicit core.symlinks = false
, this line must be overriding your request to set core.symlinks = true
. Note that the setting depends on the actual OS support, rather than any command line option. However, if you move the work-tree elsewhere later, the explicit setting remains in the .git/config
file.
Meanwhile, there are two other issues. One is what ElpieKay mentioned in a comment: For most commands, you can temporarily override the configuration using git -c name=value subcommand
, which would be git -c core.symlinks=true clone arguments
. This is worth trying, in case your particular Git version is out of date and does not match the code I am quoting and linking-to here.
However, git clone
is quite special: it's essentially an optional mkdir
to create the repository and work-tree directories, followed by a git init
, followed by some configuration setting, followed by a git fetch
and a git checkout
. So this means you can use git -c name=value clone -c name=value ...
. The first name=value
setting is in use while the repository gets created, i.e., during git init
. The second name=value
is the one that git clone
drops into the new clone, using this bit of code:
init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
if (real_git_dir)
git_dir = real_git_dir;
write_config(&option_config);
git_config(git_default_config, NULL);
The write_config
function is where Git writes your core.symlinks=true
from your git clone -c core.symlinks=true ...
command. So this in theory should override the core.symlinks=false
setting that init_db
computed. This is the part I find curious: that it doesn't.
The subsequent git_config
call reads the actual config written into the new repository's .git/config
. This will set the internal has_symlinks
variable, which will control the internal git checkout
that git clone
runs. So if this did override the init_db
setting, everything would work just the way you want. What's not obvious is why it doesn't override. The code here is a bit twisty, but it seems like your command-line option should override the init_db
setting.
(Of course, if symlinks actually work in the work-tree, the init_db
code should not be setting core.symlinks=false
in the first place!)
That should be fixed with Git 2.21 (Q1 2019)
Refspecs configured with "git -c var=val clone
" did not propagate to the resulting repository, which has been corrected.
See commit 7eae4a3, commit 515be83, commit 3e42cb3 (14 Nov 2018) by SZEDER Gábor (szeder
).
(Merged by Junio C Hamano -- gitster
-- in commit 84d1783, 04 Jan 2019)
clone: respect additional configured fetch refspecs during initial fetch
The initial
fetch
during a clone doesn't transfer refs matching additionalfetch
refspecs given on the command line as configuration variables, e.g. '-c remote.origin.fetch=<refspec>
'.
This contradicts the documentation stating that configuration variables specified via 'git clone -c <key>=<value> ...
' "take effect immediately after the repository is initialized, but before the remote history is fetched" and the given example specifically mentions "adding additional fetch refspecs to the origin remote".Furthermore, one-shot configuration variables specified via '
git -c <key>=<value> clone ...
', though not written to the newly created repository's config file, live during the lifetime of the 'clone
' command, including the initial fetch.All this implies that any fetch refspecs specified this way should already be taken into account during the initial fetch.
The reason for this is that the initial fetch is not a fully fledged '
git fetch
' but a bunch of direct calls into the fetch/transport machinery with clone's own refs-to-refspec matching logic, which bypasses parts of 'git fetch
' processing configured fetch refspecs.
This logic only considers a single default refspec, potentially influenced by options like '--single-branch
' and '--mirror
'.The configured refspecs are, however, already read and parsed properly when clone calls
remote.c:remote_get()
, but it never looks at the parsed refspecs in the resulting 'struct remote
'.Modify
clone
to take the remote's configured fetch refspecs into account to retrieve all matching refs during the initial fetch.Note that we have to explicitly add the default fetch refspec to the remote's refspecs, because at that point the remote only includes the fetch refspecs specified on the command line.
Add tests to check that refspecs given both via '
git clone -c ...
' and 'git -c ... clone
' retrieve all refs matching either the default or the additional refspecs, and that it works even when the user specifies an alternative remote name via '--origin=<name>
'.
Caveat:
Due to limitations in the current implementation, some configuration variables specified via '
git clone -c var=val
' (or 'git -c var=val clone
') are ignored during the initialfetch
andcheckout
.Let the users know which configuration variables are known to be ignored ('
remote.origin.mirror
' and 'remote.origin.tagOpt
') under the documentation of 'git clone -c
', along with hints to use the options '--mirror
' and '--no-tags
' instead.
The man page for git clone
now includes:
Due to limitations of the current implementation, some configuration variables do not take effect until after the initial fetch and checkout.
Configuration variables known to not take effect are:
remote.<name>.mirror
remote.<name>.tagOpt
.Use the corresponding
--mirror
and--no-tags
options instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With