如何让Git遵循符号链接?

我最好是用一个shell脚本替换符号链接的副本,还是有另一种方式告诉Git遵循符号链接?

PS:我知道这不是很安全,但我只是想在一些特定的情况下这样做。

115395 次浏览

注意:自Git 1.6.1以来,这个通知已经过时了。Git过去是这样的,现在不再是这样了。


Git默认情况下尝试存储符号链接,而不是遵循它们(为了紧凑,这通常是人们想要的)。

但是,当符号链接是一个目录时,我意外地设法让它在符号链接之外添加文件。

例如:

  /foo/
/foo/baz
/bar/foo --> /foo
/bar/foo/baz

通过做

 git add /bar/foo/baz

当我尝试时,它似乎起作用了。然而,这种行为在当时是我不想要的,所以我不能给你更多的信息。

我以前在符号链接之外添加文件已经有一段时间了。这在过去工作得很好,不需要做任何特别的安排。自从我更新到Git 1.6.1后,这就不再有效了。

您可以切换到Git 1.6.0来实现这个功能。我希望Git的未来版本会有一个指向git-add的标志,允许它再次跟随符号链接。

我使用的是Git 1.5.4.3,如果传递的符号链接后面有斜杠,它会跟着它。如。

# Adds the symlink itself
$ git add symlink


# Follows symlink and adds the denoted directory's contents
$ git add symlink/

我所做的是将符号链接中的文件添加到Git中(我没有使用符号链接,但是):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

在Git-managed目录下执行此命令。TARGETDIRECTORY必须在SOURCEDIRECTORY被挂载到它之前创建。

它在Linux上工作得很好,但在OS X上就不行了!这个技巧也帮助了我的Subversion。我用它来包括来自Dropbox帐户的文件,网站设计师在那里做他/她的事情。

如果你想让这个绑定永久存在,在/etc/fstab中添加以下行:

/sourcedir /targetdir none bind

嗯,mount --bind似乎对达尔文不起作用。

有人有什么诀窍吗?

(编辑)

好吧,我在macosx上找到了答案,那就是做一个硬链接。除了API不是通过ln公开的,所以你必须使用你自己的小程序来做这件事。以下是该程序的链接:

在Mac OS X中创建目录硬链接

享受吧!

为什么不反过来创建符号链接呢?这意味着不是从Git存储库链接到应用程序目录,而是以相反的方式链接。

例如,假设我正在设置一个安装在~/application中的应用程序,它需要一个配置文件config.conf:

  • 我将config.conf添加到我的Git存储库中,例如,在~/repos/application/config.conf
  • 然后我通过运行ln -s ~/repos/application/config.conf~/application创建一个符号链接。

这种方法可能并不总是有效,但到目前为止对我来说效果很好。

符号链接的转换可能很有用。链接到Git文件夹中,而不是符号链接通过脚本

这是一个导向钩,它用这些符号链接的内容替换索引中的符号链接blobs。

将其放入.git/hooks/pre-commit,并使其可执行:

#!/bin/sh
# (replace "find ." with "find ./<path>" below, to work with only specific paths)


# (these lines are really all one line, on multiple lines for clarity)
# ...find symlinks which do not dereference to directories...
find . -type l -exec test '!' -d {} ';' -print -exec sh -c \
# ...remove the symlink blob, and add the content diff, to the index/cache
'git rm --cached "$1"; diff -au /dev/null "$1" | git apply --cached -p1 -' \
# ...and call out to "sh".
"process_links_to_nondir" {} ';'


# the end

笔记

我们尽可能多地使用POSIX兼容功能;然而,diff -a不兼容POSIX,可能还有其他原因。

这段代码中可能有一些错误/错误,即使它经过了一些测试。

使用硬链接代替。这不同于软(符号)链接。包括git在内的所有程序都将该文件视为常规文件。注意,可以通过更改源或目标要么来修改内容。

macOS版本(10.13 High Sierra之前版本)

如果你已经安装了git和Xcode, 安装hardlink。这是一个微观的工具创建硬链接

要创建硬链接,只需:

hln source destination

macOS High Sierra更新

苹果文件系统支持目录硬链接吗?

苹果文件系统不支持目录硬链接。在macOS上从HFS+转换为APFS卷格式时,所有目录硬链接都转换为符号链接或别名。

APFS FAQ on developer.apple.com

参考https://github.com/selkhateeb/hardlink/issues/31获取未来的替代方案。

在Linux和其他Unix版本上

ln命令可以创建硬链接:

ln source destination

在Windows (Vista, 7,8,…)

使用mklink在Windows上创建一个连接:

mklink /j "source" "destination"

在Git 2.3.2+(2015年第一季度)中,还有另一种情况,Git将继续使用跟随符号链接:参见提交e0d201b by juno C Hamano (gitster) (Git的主要维护者)

apply:不要触及符号链接以外的文件

因为Git将符号链接作为符号链接来跟踪,所以在其前导部分有符号链接的路径(例如path/to/dir/file,其中path/to/dir是指向其他地方的符号链接,无论是在工作树内部还是外部)永远不会出现在有效应用的补丁中,除非同一个补丁首先删除符号链接以允许在那里创建目录。

检测并拒绝这样的补丁。

类似地,当一个输入创建了一个符号链接path/to/dir,然后创建了一个文件path/to/dir/file时,我们需要将其标记为错误,而不需要在文件系统中实际创建path/to/dir符号链接。

相反,对于输入中的任何在结果中留下路径(即非删除)的补丁,我们通过检查输入中的所有补丁,然后检查补丁应用程序的目标(索引或工作树),根据补丁将创建的结果树检查所有前导路径。

这样,我们:

  • 捕捉恶作剧或错误,同时添加符号链接path/to/dir和文件path/to/dir/file
  • 同时允许一个有效的补丁删除符号link path/to/dir,然后添加文件path/to/dir/file

这意味着,在这种情况下,错误消息不会是像"%s: patch does not apply"这样的通用消息,而是一个更具体的消息:

affected file '%s' is beyond a symbolic link

我厌倦了这里的每个解决方案,要么过时,要么需要根,所以我做了一个基于ld_preload的解决方案(仅Linux)。

它连接到Git的内部,覆盖'这是一个符号链接吗?函数,允许符号链接被视为它们的内容。默认情况下,所有到回购外部的链接都是内联的;详情请参见链接。

在macOS上(我有Mojave/ 10.14, git version 2.7.1),使用bindfs

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

其他评论暗示了这一点,但在其他答案中没有明确提供。希望这能为大家节省一些时间。

@user252400建议的另一种实现是使用bwrap,这是一个小的setuid沙箱,可以在所有主要发行版中找到——通常默认安装。bwrap允许你绑定挂载目录没有 sudo,并在git或shell退出时自动解除绑定。

假设你的开发过程不是很疯狂(见下文),在一个私有的命名空间中启动bash,并在git目录下绑定外部目录:

bwrap --ro-bind / / \
--bind {EXTERNAL-DIR} {MOUNTPOINT-IN-GIT-DIR} \
--dev /dev \
bash

然后做你通常做的所有事情,比如git addgit commit,等等。当你完成时,退出bash。干净简单。

注意:为了防止沙箱转义,bwrap不允许执行其他setuid二进制文件。详见man bwrap

你应该使用硬链接作为硬链接中所做的更改

创建硬链接的语法是ln file1 file2

3.这里file1是硬链接文件的位置 file2是硬链接的位置

我希望这对你有帮助。