我们的开发人员使用基于Windows和Unix的操作系统。因此,在Unix机器上创建的符号链接成为Windows开发人员的问题。在windows(msysgit)中,符号链接将转换为文本文件,其中包含指向其所指向文件的路径。相反,我想将符号链接转换为实际的Windows符号链接。
我需要的(更新的)解决方案是:
我没有实现这一点,但我相信这是解决这个问题的可靠方法。
问题:
答案 0 :(得分:171)
我曾经问过这个完全相同的问题(不是在这里,一般情况下),最终提出了一个非常类似于OP的命题的解决方案。首先,我将提供问题的直接答案1 2& 3,然后我将发布我最终使用的解决方案。
git checkout
步骤,但下面的解决方案已经很好地满足了我的需求,因此不需要文字的结账后脚本。我们的开发人员与OP的情况大致相同:Windows和类Unix主机的混合,存储库和带有许多git符号链接的子模块,并且在MsysGit的发布版本中还没有本机支持在Windows主机上智能地处理这些符号链接。
感谢Josh Lee指出git使用特殊文件模式120000
提交符号链接这一事实。有了这些信息,就可以添加一些git别名,允许在Windows主机上创建和操作git符号链接。
在Windows上创建git符号链接
git config --global alias.add-symlink '!'"$(cat <<'ETX'
__git_add_symlink() {
if [ $# -ne 2 ] || [ "$1" = "-h" ]; then
printf '%b\n' \
'usage: git add-symlink <source_file_or_dir> <target_symlink>\n' \
'Create a symlink in a git repository on a Windows host.\n' \
'Note: source MUST be a path relative to the location of target'
[ "$1" = "-h" ] && return 0 || return 2
fi
source_file_or_dir=${1#./}
source_file_or_dir=${source_file_or_dir%/}
target_symlink=${2#./}
target_symlink=${target_symlink%/}
target_symlink="${GIT_PREFIX}${target_symlink}"
target_symlink=${target_symlink%/.}
: "${target_symlink:=.}"
if [ -d "$target_symlink" ]; then
target_symlink="${target_symlink%/}/${source_file_or_dir##*/}"
fi
case "$target_symlink" in
(*/*) target_dir=${target_symlink%/*} ;;
(*) target_dir=$GIT_PREFIX ;;
esac
target_dir=$(cd "$target_dir" && pwd)
if [ ! -e "${target_dir}/${source_file_or_dir}" ]; then
printf 'error: git-add-symlink: %s: No such file or directory\n' \
"${target_dir}/${source_file_or_dir}" >&2
printf '(Source MUST be a path relative to the location of target!)\n' >&2
return 2
fi
git update-index --add --cacheinfo 120000 \
"$(printf '%s' "$source_file_or_dir" | git hash-object -w --stdin)" \
"${target_symlink}" \
&& git checkout -- "$target_symlink" \
&& printf '%s -> %s\n' "${target_symlink#$GIT_PREFIX}" "$source_file_or_dir" \
|| return $?
}
__git_add_symlink
ETX
)"
用法:git add-symlink <source_file_or_dir> <target_symlink>
,其中与源文件或目录对应的参数必须采用相对于目标符号链接的路径的形式。您可以像使用相同的方式使用此别名通常会使用ln
。
,例如,存储库树:
dir/
dir/foo/
dir/foo/bar/
dir/foo/bar/baz (file containing "I am baz")
dir/foo/bar/lnk_file (symlink to ../../../file)
file (file containing "I am file")
lnk_bar (symlink to dir/foo/bar/)
可以在Windows上创建如下:
git init
mkdir -p dir/foo/bar/
echo "I am baz" > dir/foo/bar/baz
echo "I am file" > file
git add -A
git commit -m "Add files"
git add-symlink ../../../file dir/foo/bar/lnk_file
git add-symlink dir/foo/bar/ lnk_bar
git commit -m "Add symlinks"
用NTFS硬链接+联结替换git符号链接
git config --global alias.rm-symlinks '!'"$(cat <<'ETX'
__git_rm_symlinks() {
case "$1" in (-h)
printf 'usage: git rm-symlinks [symlink] [symlink] [...]\n'
return 0
esac
ppid=$$
case $# in
(0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
(*) printf '%s\n' "$@" ;;
esac | while IFS= read -r symlink; do
case "$symlink" in
(*/*) symdir=${symlink%/*} ;;
(*) symdir=. ;;
esac
git checkout -- "$symlink"
src="${symdir}/$(cat "$symlink")"
posix_to_dos_sed='s_^/\([A-Za-z]\)_\1:_;s_/_\\\\_g'
doslnk=$(printf '%s\n' "$symlink" | sed "$posix_to_dos_sed")
dossrc=$(printf '%s\n' "$src" | sed "$posix_to_dos_sed")
if [ -f "$src" ]; then
rm -f "$symlink"
cmd //C mklink //H "$doslnk" "$dossrc"
elif [ -d "$src" ]; then
rm -f "$symlink"
cmd //C mklink //J "$doslnk" "$dossrc"
else
printf 'error: git-rm-symlink: Not a valid source\n' >&2
printf '%s =/=> %s (%s =/=> %s)...\n' \
"$symlink" "$src" "$doslnk" "$dossrc" >&2
false
fi || printf 'ESC[%d]: %d\n' "$ppid" "$?"
git update-index --assume-unchanged "$symlink"
done | awk '
BEGIN { status_code = 0 }
/^ESC\['"$ppid"'\]: / { status_code = $2 ; next }
{ print }
END { exit status_code }
'
}
__git_rm_symlinks
ETX
)"
git config --global alias.rm-symlink '!git rm-symlinks' # for back-compat.
用法:
git rm-symlinks [symlink] [symlink] [...]
这个别名可以一次一个一个地删除git符号链接或一次性删除。符号链接将替换为NTFS硬链接(在文件的情况下)或NTFS联结(在目录的情况下)。使用硬链接+结点的好处&#34; true&#34; NTFS符号链接是提升的UAC权限,以便创建它们。
要从子模块中删除符号链接,只需使用git的内置支持来迭代它们:
git submodule foreach --recursive git rm-symlinks
但是,对于像这样的每一次激烈的行动,反转都很好......
在Windows上恢复git符号链接
git config --global alias.checkout-symlinks '!'"$(cat <<'ETX'
__git_checkout_symlinks() {
case "$1" in (-h)
printf 'usage: git checkout-symlinks [symlink] [symlink] [...]\n'
return 0
esac
case $# in
(0) git ls-files -s | grep -E '^120000' | cut -f2 ;;
(*) printf '%s\n' "$@" ;;
esac | while IFS= read -r symlink; do
git update-index --no-assume-unchanged "$symlink"
rmdir "$symlink" >/dev/null 2>&1
git checkout -- "$symlink"
printf 'Restored git symlink: %s -> %s\n' "$symlink" "$(cat "$symlink")"
done
}
__git_checkout_symlinks
ETX
)"
git config --global alias.co-symlinks '!git checkout-symlinks'
用法:git checkout-symlinks [symlink] [symlink] [...]
,撤消git rm-symlinks
,有效地将存储库恢复到自然状态(除了您的更改,应保持不变)。
对于子模块:
git submodule foreach --recursive git checkout-symlinks
<强>限制:强>
路径中包含空格的目录/文件/符号链接应该可以使用。标签或换行符? YMMV ......(我的意思是:不要这样做,因为不会工作。)
如果您自己或其他人忘记git checkout-symlinks
之前遇到可能带来广泛影响的问题(例如git add -A
),则本地存储库最终可能会处于污染状态。
使用我们的&#34;示例repo&#34;从以前开始:
echo "I am nuthafile" > dir/foo/bar/nuthafile
echo "Updating file" >> file
git add -A
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: dir/foo/bar/nuthafile
# modified: file
# deleted: lnk_bar # POLLUTION
# new file: lnk_bar/baz # POLLUTION
# new file: lnk_bar/lnk_file # POLLUTION
# new file: lnk_bar/nuthafile # POLLUTION
#
...糟糕
出于这个原因,将这些别名作为在构建项目之前和之后为Windows用户执行的步骤而不是在结帐之后或推送之前包含这些别名是很好的。但每种情况都不同。这些别名对我来说非常有用,因此没有必要使用真正的结账后解决方案。
希望有所帮助!
<强>参考文献:强>
http://git-scm.com/book/en/Git-Internals-Git-Objects
http://technet.microsoft.com/en-us/library/cc753194
最后更新:2019-03-13
mklink
次调用之外) - 不再是Bashisms!add-symlink
别名现在更像ln(1),可以从存储库中的任何目录使用,而不仅仅是存储库的根目录。rm-symlink
别名(单数)已被rm-symlinks
别名(复数)取代,后者现在接受多个参数(或根本没有参数,它会查找整个存储库中的所有符号链接,如前所述)有选择地将git符号链接转换为NTFS hardlinks + junctions。checkout-symlinks
别名也已更新为接受多个参数(或根本没有参数,==所有内容),以选择性地反转上述转换。最后注意事项虽然我确实使用Bash 3.2(甚至3.1)测试加载和运行这些别名,但是对于那些可能因为各种原因仍然困在这些古老版本上的人来说,请注意这些旧的版本因其解析器错误而臭名昭着。如果您在尝试安装任何这些别名时遇到问题,首先应该考虑升级shell(对于Bash,请使用CTRL + X,CTRL + V检查版本)。或者,如果您尝试通过将它们粘贴到终端模拟器中来安装它们,那么您可能会更幸运地将它们粘贴到文件中并改为采购它,例如,如
. ./git-win-symlinks.sh
祝你好运!
答案 1 :(得分:94)
您可以通过查找模式为120000
的文件找到符号链接,可能使用以下命令:
git ls-files -s | awk '/120000/{print $4}'
更换链接后,我建议您使用git update-index --assume-unchanged
将其标记为未更改,而不是将其列在.git/info/exclude
中。
答案 2 :(得分:55)
最新版本的git scm(testet 2.11.1)允许启用符号链接。但是您必须再次使用符号链接克隆存储库git clone -c core.symlinks=true <URL>
。您需要使用管理员权限运行此命令。也可以在Windows上使用mklink创建符号链接。
查看wiki。
答案 3 :(得分:26)
mklink
权限git config --global core.symlinks true
切换分支将迫使重新创建缺少的符号链接。
注意,Windows上对git中的Symlinks的支持相对较新。
有些错误仍然会影响某些git客户端。
值得注意的是,由于fixed regression in ligbit2,在某些程序中带有相对(..
)路径的符号链接被破坏了。
例如,GitKraken受此影响。
答案 4 :(得分:14)
它应该在msysgit中实现,但有两个缺点:
我进行了快速搜索,并且正在积极完成这项工作,请参阅问题224。
答案 5 :(得分:9)
我建议你不要在repo中使用符号链接'。将实际内容存储在repo'中,然后将符号链接放在指向内容的repo'旁边。
因此,假设您正在使用回购'比较在* nix上托管您的网站与在win上托管。将内容存储在您的repo中,让我们说/httpRepoContent
和c:\httpRepoContent
,这是通过GIT,SVN等同步的文件夹。
然后,替换您的网络服务器的内容文件夹(/var/www
和c:\program files\web server\www
{名称并不重要,如果必须,请进行编辑}),并使用指向回购邮件内容的符号链接。 Web服务器会将内容视为实际位于“正确”的位置,但您可以使用源代码控制。
但是,如果你需要在repo'中使用符号链接,你将需要查看某种类型的前/后提交脚本。我知道你可以使用它们来做事情,比如通过格式化程序解析代码文件,所以应该可以在平台之间转换符号链接。
如果有人知道如何为常用源代码控制SVN GIT MG学习这些脚本,那么请添加评论。
答案 6 :(得分:9)
简短回答:如果您可以启用开发者模式,现在可以很好地支持它们。
来自https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/
现在,在Windows 10 Creators Update中,用户(具有管理员权限)可以 首先启用开发者模式,然后机器上的任何用户都可以运行 没有提升命令行控制台的mklink命令。
是什么推动了这一变化?符号链接的可用性和使用是一个很大的问题 与现代开发商打交道:
许多流行的开发工具,如git和包管理器,如npm 在创建repos或包时识别并保留符号链接, 分别。然后恢复那些repos或包 在其他地方,符号链接也会被恢复,确保磁盘空间(和 用户的时间)没有浪费。
很容易忽略&#34;创建者更新&#34;的所有其他公告,但如果您启用开发者模式,则可以创建没有提升权限的符号链接。您可能需要重新安装并确保启用支持,因为默认情况下不支持。
答案 7 :(得分:8)
自从发布了这些答案以来,GIT发生了变化,这是使符号链接自
开始在Windows中正常工作的正确说明。2018年8月
1。确保已安装具有gitlink支持的git
2。告诉Bash创建硬链接而不是符号链接
编辑-(git文件夹)/etc/bash.bashrc
添加到底部-MSYS=winsymlinks:nativestrict
3。将git config设置为使用符号链接
git config core.symlinks true
或
git clone -c core.symlinks=true <URL>
注意:我已经尝试将其添加到全局git config中,但目前它不适用于我,所以我建议将其添加到每个存储库中。
4。拉回购
注意:除非您在最新版本的Windows 10中启用了开发人员模式,否则您需要以管理员身份运行bash来创建符号链接
5。重置所有符号链接(可选) 如果您有现有的存储库,或者正在使用子模块,则可能会发现未正确创建符号链接,因此要刷新存储库中的所有符号链接,可以运行以下命令。
find -type l -delete
git reset --hard
注意:这将重置自上次提交以来的所有更改,因此请确保您已先提交
答案 8 :(得分:7)
对于在Vista,Win7或更高版本上使用CygWin的用户,原生git
命令可以创建&#34;正确的&#34; Windows应用程序(例如Android Studio)可识别的符号链接。您只需将CYGWIN
环境变量设置为包含winsymlinks:native
或winsymlinks:nativestrict
:
export CYGWIN="$CYGWIN winsymlinks:native"
这方面的缺点(以及一个重要的一点)是CygWin shell必须是&#34;以管理员身份运行&#34;为了使它具有创建这种符号链接所需的操作系统权限。但是,一旦创建了它们,使用它们就不需要特殊权限。只要其他开发人员在存储库中没有更改它们,git
之后就可以正常用户权限运行。
就我个人而言,我只使用 作为由Windows应用程序(即非CygWin)导航的符号链接,因为这会增加难度。
有关此选项的详细信息,请参阅此问题:How to make symbolic link with cygwin in Windows 7
答案 9 :(得分:7)
我刚刚尝试使用 Git 2.30.0(2020 年 12 月 28 日发布)。
这不是一个完整的答案,但仍然是一些有用的花絮。 (随意蚕食你自己的答案。)
安装 Git for Windows 时有一个文档链接
此链接将您带到此处:https://github.com/git-for-windows/git/wiki/Symbolic-Links -- 这是一个相当长的讨论。
只是为了强调这个维基条目的一个重要方面:我不知道这一点,但是有几种方法表面上都是“某种”符号链接,但在技术层面上却非常不同:
stat
命令实际上识别为“符号链接”的东西。)符号链接也在 the release notes 中不断弹出。截至 2.30.0,此处仍列为“已知问题”:
<块引用>在 1703 之前的 Windows 10 上,或者当开发者模式关闭时,克隆带有符号链接的存储库时需要特殊权限,因此默认情况下禁用对符号链接的支持。使用 git clone -c core.symlinks=true <URL>
启用它,查看详细信息 here。
答案 10 :(得分:5)
这是一个批处理脚本,用于根据Josh Lee的回答转换存储库中的符号链接,仅用于文件。带有管理员权限的额外检查的脚本位于https://gist.github.com/Quazistax/8daf09080bf54b4c7641。
@echo off
pushd "%~dp0"
setlocal EnableDelayedExpansion
for /f "tokens=3,*" %%e in ('git ls-files -s ^| findstr /R /C:"^120000"') do (
call :processFirstLine %%f
)
REM pause
goto :eof
:processFirstLine
@echo.
@echo FILE: %1
dir "%~f1" | find "<SYMLINK>" >NUL && (
@echo FILE already is a symlink
goto :eof
)
for /f "usebackq tokens=*" %%l in ("%~f1") do (
@echo LINK TO: %%l
del "%~f1"
if not !ERRORLEVEL! == 0 (
@echo FAILED: del
goto :eof
)
setlocal
call :expandRelative linkto "%1" "%%l"
mklink "%~f1" "!linkto!"
endlocal
if not !ERRORLEVEL! == 0 (
@echo FAILED: mklink
@echo reverting deletion...
git checkout -- "%~f1"
goto :eof
)
git update-index --assume-unchanged "%1"
if not !ERRORLEVEL! == 0 (
@echo FAILED: git update-index --assume-unchanged
goto :eof
)
@echo SUCCESS
goto :eof
)
goto :eof
:: param1 = result variable
:: param2 = reference path from which relative will be resolved
:: param3 = relative path
:expandRelative
pushd .
cd "%~dp2"
set %1=%~f3
popd
goto :eof
答案 11 :(得分:2)
我在文档根目录和git repo目录之间一直使用sym链接。我喜欢将它们分开。在Windows上我使用mklink / j选项。结点似乎让git正常运行:
label.GetComponent<Text> ().font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font;
例如:
>mklink /j <location(path) of link> <source of link>
答案 12 :(得分:2)
我一直在寻找一个简单的解决方案来处理Windows上的unix符号链接。非常感谢上面的Git别名。 可以对rm-symlink进行一个小的优化,这样它就不会删除目标文件夹中的文件,以防别名第二次意外运行。请在循环中观察新的if条件,以确保在运行逻辑之前文件不是指向目录的链接。
git config --global alias.rm-symlinks '!__git_rm_symlinks(){
for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do
*if [ -d "$symlink" ]; then
continue
fi*
git rm-symlink "$symlink"
git update-index --assume-unchanged "$symlink"
done
}; __git_rm_symlinksenter
答案 13 :(得分:1)
我们使用的一个简单技巧是连续两次调用git add --all
。
例如,我们的Windows 7提交脚本调用:
$ git add --all
$ git add --all
第一个add将链接视为文本,并添加要删除的文件夹。
第二个add正确遍历链接,并通过恢复文件撤消删除。
它不像其他一些提议的解决方案那么优雅,但它是对我们添加了符号链接的一些遗留环境的简单修复。