如何让Git遵循符号链接?


217

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

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


5
对这样的东西使用硬链接有缺点吗?
Ehtesh Choudhury 2011年

12
在Windows 7中,“ mklink / d”(目录符号链接)不适用于git,但“ mklink / j”(连接)则可以正常工作。
yoyo 2012年

1
如果文件是由应用程序自动生成的,该应用程序以删除文件并创建新文件的方式重新生成文件,则可以,这是硬链接到文件无法解决的问题。
马丁·佩卡

1
@EhteshChoudhury您不能为目录建立硬链接
Gaurav Kansal

Answers:


46

注意:从Git 1.6.1开始,此建议现在已过期。Git过去一直是这种方式,现在不再这样做。


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

但是,当符号链接是目录时,我不小心设法使其添加到符号链接之外的文件。

即:

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

通过做

 git add /bar/foo/baz

当我尝试时它似乎起作用。但是,当时我不希望这种行为,因此我无法提供其他信息。


72
提交725b06050a083474e240a2436121e0a80bb9f175和806d13b1ccdbdde4bbdfb96902791c4b7ed125f6引入了更改,这些更改阻止了您添加文件到符号链接目录之外的位置,因此自1.6.1版开始,此版本在git版本中不起作用
Mark Longair

1
$ git add src / main / path / ConvertSymlinkToDir致命:'src / main / path / ConvertSymlinkToDir'超出了符号链接
user1767316 '17

2
@ user1767316阅读了整个内容和评论。它曾经可以工作,现在不再起作用。软件更改,但堆栈溢出可接受的答案没有。我已经说明这还行不通。再看一个答案。
肯特·弗雷德里克

是的@KentFrederic,但写出确切的错误消息返回帮助堆栈用户搜索其问题的解决方案。试图取消降票但已锁定,对不起。一方面,警告您的答案是正确的,另一方面,应该优先回答现在而不是过去的工作
user1767316

143

为了将符号链接中的文件导入Git而进行的添加操作(我没有使用符号链接,但):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

在Git管理的目录中执行此命令。TARGETDIRECTORY必须在将SOURCEDIRECTORY其安装到其中之前创建。

它可以在Linux上正常运行,但不能在OS X上运行!这个技巧也对Subversion有所帮助。我使用它来包含来自Dropbox帐户的文件,该帐户由Webdesigner负责。


8
如果不需要sudo,这将是一个非常好的方法。
MestreLion 2011年

13
要撤消此绑定,请使用umount [mydir]。(+1为您的技巧,@ user252400)
JellicleCat

10
这仅在会话期间有效。使它“永恒”的最佳方法是什么?
Adobe

17
@Adobe:将其放在/ etc / fstab中,如下所示:/ sourcedir / targetdir none bind
Alexander Garden

8
sshfs可以在不需要sudo的情况下实现这种技巧。
PypeBros 2012年

75

为什么不反过来创建符号链接呢?含义不是从Git存储库链接到应用程序目录,而是以另一种方式链接。

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

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

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


5
似乎是唯一的方法,而且还不错...我认为您的方法相当优雅。git跟踪内容,而不是文件。因此,将所有内容放在一起并从那里链接到其他地方是有意义的
MestreLion 2011年

12
就我而言,我想要一个从一个git repo到另一个git repo的链接,因此我可以在任一位置编辑文件并提交回各自的遥控器。在Windows 7上,结点(“ mklink / j”)起到了作用。
yoyo 2012年

3
当然。有时候答案就这么简单。
BBW Windows

如果要同时混合源和目标怎么办?(因为两者都属于您希望在不同存储库中拥有的不同代码)
DrGC 2016年

1
没有回答问题:(我希望将我的存储库的一部分同步到我的iCloud中。不幸的是,iCloud不遵循符号链接,所以我认为我可以使git遵循符号链接,并将原始文件存储在iCloud中。结果没有人遵循符号链接:\
杰瑞·格林

49

请改用硬链接。这不同于软(符号)链接。所有程序,包括git将文件视为常规文件。请注意,内容可以通过改变被修改或者源或目的地。

在macOS上(10.13 High Sierra之前)

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

要创建硬链接,只需:

hln source destination

macOS High Sierra更新

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

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

developer.apple.com上的APFS常见问题解答中

请遵循https://github.com/selkhateeb/hardlink/issues/31了解未来的选择。

在Linux和其他Unix版本上

ln命令可以建立硬链接:

ln source destination

在Windows上(Vista,7、8,...)

有人建议在Windows上使用mklink创建联结,但我还没有尝试过:

mklink /j "source" "destination"

7
请注意:这基本上是我想要的,但是后来我了解到,在Linux上,硬链接很遗憾无法跨越文件系统边界(这是我的用例)。
sdaau,2015年

26
您不能硬链接到目录,可以吗?
Nanne 2015年

1
ln source destination在OS X中也可以使用。在El Capitan上测试。
Mahdi Dibaiee 2015年

7
@Nanne不,但您可以这样做:cp -al source destination。-l表示硬链接文件,而不是复制文件。
Paolo

6
不幸的是,您不能硬链接目录或跨文件系统边界。这使该解决方案对我来说双重可行。
康拉德·鲁道夫

25

这是一个预提交的挂钩,它将这些索引中的符号链接blob替换为这些符号链接的内容。

将其放入中.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。

尽管经过了一些测试,但此代码中可能存在一些错误/错误。


4
很高兴看到尝试实际回答文件而不是目录的问题。但是,请注意,上面仍然会显示typechangegit status为这实际上是符号链接,虽然现在混帐东西,他们不是文件。
大卫·弗雷泽

1
谢谢你 只是想知道,什么是process_links_to_nondir
sdaau 2015年

@sdaau它是名称/ argv[0],用作sh进程的命令名称。(花了我一些时间才弄清楚,因为我也不记得是什么了)
Abbafei 2015年

3
@Abbafei您可以修改脚本以使其在Ubuntu(14.04)上运行吗?它正在显示find: missing argument to -exec'。可能需要一步一步地执行命令,而不是通过管道将所有内容组合成一行。
库尔希德·阿拉姆

1
@KhurshidAlam对我来说,它删除了命令行之间的注释行。但是,该钩子并没有按预期的方式工作(我得到了typechange@DavidFraser 之类的东西,但是链接的文件似乎不再上演了)
Scz

14

MacOS(我有Mojave / 10.14,git版本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>

其他评论已暗示了这一点,但其他答案中并未明确提供。希望这可以节省一些时间。


对于所有都在Mac OS上运行的团队来说似乎很棒,我认为下面概述的硬链接应该适用于Windows和Linux。
德文·罗德

这很有帮助,我认为MacOS中有用但缺乏功能的最佳解决方案。但是请注意,除非我在命令中使用了完整路径名否则我将收到Failed to resolve... No such file or directory错误。bindfs
电磁铁

谢谢@electromaggot。进一步说明需要完整的路径
ijoseph,

1
在MacOS Catalina上效果很好!
杰里·格林

13

我过去很长时间以来都在符号链接之外添加文件。过去这种方法工作得很好,无需进行任何特殊安排。自从我更新到Git 1.6.1以来,这不再起作用。

您也许可以切换到Git 1.6.0来完成这项工作。我希望Git的未来版本将有一个标志,git-add允许它再次遵循符号链接。


12

我对这里的每个解决方案都已过时或需要root用户感到厌倦,因此我制作了一个基于LD_PRELOAD的解决方案(仅Linux)。

它与Git的内部息息相关,覆盖了“这是一个符号链接吗?” 功能,允许将符号链接视为其内容。默认情况下,内联到回购协议之外的所有链接都是内联的;有关详细信息,请参见链接。


非常有创意的解决方案,LD_PRELOAD用于覆盖库函数!
iBug

是的,但是应该在这里详细说明。你能做到吗?
彼得·莫滕森

不确定会有多少细节帮助?除非我复制粘贴整个源代码,否则此答案将始终依赖于该链接,在该链接中也可以找到自述文件。但是,是的,我想我可以复制自述文件的重要部分。
阿尔卡罗(Alcaro)'18 -10-27

这不能在OS X(Mojave 10.14.2)上编译。遇到四个抱怨“ strchrnul”的错误(您是说“ strchr”?),另一个是关于“ __xstat64”的错误(您是指“ __lxstat64”?)。最后,我收到一个“成员访问不完整类型'dirent64'的错误”错误。无论我使用“ make”,“ make OPT = 1”还是“ sh install.sh”,都会发生。
Erik Veland

@ErikVeland我尝试了一下,但似乎OSX不支持LD_PRELOAD,也没有类似的东西。各种各样的文档都提出了各种各样的建议,但是它们都已经存在了好几年了,Apple喜欢过时的东西。我无法让他们中的任何一个工作。抱歉。
Alcaro

6

在Git 2.3.2+(2015年第一季度)中,还有另外一种情况,Git将不再遵循符号链接:请参见Junio C Hamano gitster(主要的Git维护者)的commit e0d201b

apply:请勿触摸符号链接以外的文件

因为Git将符号链接作为符号链接进行跟踪,所以在其前导部分具有符号链接的路径(例如path/to/dir/filepath/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

4

嗯,mount --bind似乎不适用于达尔文。

有人有招吗?

[编辑]

好的,我发现Mac OS X上的答案是建立硬链接。除了该API不是通过公开的ln,因此您必须使用自己的微型程序来执行此操作。这是该程序的链接:

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

请享用!


1
如果此硬链接的目标目录是另一个git repo的子目录,则可能会造成混乱。在硬链接中执行git操作将适用于此其他git repo。只需仔细检查您在做什么。
yegle 2012年

4
可以通过code.google.com/p/bindfs进行此操作,可以使用port进行安装。
Kit Sunde

0

我使用的是Git 1.5.4.3,如果传递的符号链接带有斜杠,它会遵循传递的符号链接。例如

# Adds the symlink itself
$ git add symlink

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

5
至少在OSX上这会导致fatal: 'src/' is beyond a symbolic link
Dan Rosenstark 2010年

2
正如@马克Longair解释说,这只是工作,直到git的1.6.1
MestreLion

那是我的问题,谢谢!
Mike Q

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.