3 回答
TA贡献1789条经验 获得超8个赞
120000
git ls-files -s | awk '/120000/{print $4}'
git update-index --assume-unchanged
.git/info/exclude
.
TA贡献1839条经验 获得超15个赞
建议的解决方案确实有一些缺点,主要是因为存储库污染的可能性增加,或者在文件处于“Windows符号链接”状态时不小心添加重复文件。(下文“限制”一节将对此作更多介绍。) 是的,结帐后脚本是可实现的!也许不是作为一个字面上的帖子- git checkout
步骤,但是下面的解决方案已经很好地满足了我的需求,所以不需要一个文字的签出脚本。 是!
解决办法:
120000
在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符号链接。Symlink将替换为NTFS硬链接(在文件中)或NTFS连接(在目录中)。与“真”NTFS符号链接相比,使用硬链接+连接的好处是 要创建UAC权限,不需要经过提升的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
,本地存储库可能会以 污染状态。使用我们以前的“示例回购”: 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用户执行的步骤是很好的。但每一种情况都是不同的。这些别名对我来说已经足够有用了,所以不需要真正的结帐解决方案。
参考资料:
POSIX的遵守情况(嗯,除了那些 mklink
当然) 巴什主义 !支持包含空格的目录和文件。 零和非零退出状态代码(分别用于通信请求的命令的成功/失败)现在被正确保存/返回。 这个 add-symlink
别名现在更像 并且可以在存储库中的任何目录中使用,而不仅仅是存储库的根目录。 这个 rm-symlink
别名(单数)已被 rm-symlinks
别名(复数),它现在接受多个参数(或者根本不接受参数,它像以前一样在存储库中查找所有的符号链接),用于选择性地将git符号链接转换为NTFS硬链接+连接。 这个 checkout-symlinks
别名还被更新为接受多个参数(或根本不接受,=All),以选择性地逆转上述转换。
最后注:
. ./git-win-symlinks.sh
- 3 回答
- 0 关注
- 858 浏览
添加回答
举报