我正在尝试git 附件,在向 git annex 导入太多内容之前,我想弄清楚如何快速删除“附加的”git 存储库,而不会丢失附加的文件内容及其目录结构。所有“附加的”文件实际上都是符号链接到的.git/annex/objects
,如下所示:
$ git init
Initialised empty Git repository in /tmp/annex/.git/
$ git annex init
init ok
(recording state in git...)
$ touch foo
$ git annex add foo
add foo ok
(recording state in git...)
$ git commit -a
[master (root-commit) 609a6df] Initial
1 file changed, 1 insertion(+)
create mode 120000 foo
$ ls -l foo
lrwxrwxrwx 1 me me 178 Jan 6 15:10 foo -> .git/annex/objects/pX/ZJ/SHA256E-s0--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/SHA256E-s0--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
因此,简单地删除 .git 目录也会删除所有实际文件内容!
我想要的是一个命令,用于获取像上面那样的附加存储库并创建一个仅包含(未符号链接的)文件的新目录:在本例中,仅包含单个文件foo
。为了在删除原始附件目录之前节省空间,我希望该文件foo
是硬链接.git/annex/objects/pX/ZJ/SHA256E-s0--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/SHA256E-s0--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
(显然,在现实的例子中,存储库中会有许多文件)。
git annex 自身用于“取消附加”的命令(例如git annex uninit
)非常有限:特别是它们不能很好地支持将 git annex 存储库快速转换为普通文件目录。这引发了以下问题:
如何复制文件目录,取消引用符号链接,但硬链接到符号链接的引用?
我尝试rsync
过--link-dest
,像这样:
rsync -rLptgoD --safe-links --exclude='.git/' --link-dest=annex annex/ copy
但这不会产生硬链接,大概是因为符号链接的存在意味着 rsync 不知道要硬链接到哪些文件。
答案1
git annex 自身的“取消附加”命令(例如
git annex uninit
)是有限的:特别是它们不能很好地支持将 git annex 存储库快速转换为普通的文件目录。
这听起来不对。该命令以递归方式运行,因此您只需在存储库的根目录下运行git annex unannex .
,即可提取所有文件。
但在 v5 格式的 git-annex 存储库中,您还有另一种选择:使用 切换到“直接”模式git annex direct
。这会将所有文件移出对象存储并直接公开它们,而无需链接。此命令会一次转换整个工作树。
文件仍然由 git-annex 跟踪;v5 直接模式仅仅改变了本地签出的方式,所以它可能是最快的方法,因为它实际上并没有将新数据写入 Git。
所以如果你想克隆整个文件树,您可以 1)将存储库切换到“直接”模式;2)使用 rsync 硬链接所有文件(完全排除 .git);3)如果需要,将原始存储库再次切换到“间接”模式。
或者,切换到直接模式后,只需删除该.git
文件夹...
答案2
这将快速复制文件,同时(某种程度上)保留权限、所有权、时间戳和硬链接,以免使用更多空间(只要副本在同一个文件系统上):
cp -rLlp annex copy
令我惊讶的是,rsync 无法复制这种行为,但据我所知,它不能。
cp 解决方案存在三个问题:
任何未跟踪或直接签入 git 的非附加符号链接都将被替换为它们指向的任何文件(但我怀疑我不会拥有任何文件)。在我意识到我可以使用之前
cp
,我编写了一个 Python 程序,用于os.walk
一次复制一个文件:由于它知道 git annex,因此它会得到正确的结果:它分别运行rsync -ptgo --dirs
以复制目录和cp -Ll
和cp -Pl
非目录附加文件以及其他非目录文件(该程序与实用程序代码有点纠缠,没有经过仔细测试,因此我不会在这里发布它)。虽然
cp
保留了权限,但这些文件可能被“锁定”,这意味着它们处于符号链接的不可编辑状态。因此,可写文件最终在副本中将变为不可写。使用git annex unlock .
代替cp
将避免该问题(这适用于 git annex repo 格式 v6/v7——对于早期格式,我相信您可以切换到直接模式而不是解锁)。您最终会
.git
在目录中得到目录的副本copy
,其中包含相同文件的更多硬链接副本。同样,由于硬链接,它不会占用更多空间,您可以直接sudo rm -rf .git
删除它。
答案3
另一个答案(在存储库的顶层目录中运行此程序):
git annex unlock .
优点:
- 权限被保留(参见我的其他答案)。
- 未跟踪和已解锁的符号链接被保留(再次参见我的其他答案)。
- 运行 strace 发现至少 Joey Hess 诊断出的缓慢问题此处发表评论因为影响
git annex uninit
(也适用于git annex unannex .
)不会影响此命令。不过,我不知道它对于实际存储库有多快:我只是在这里进行先发制人的测试。
缺点:
- 除非您使用 Btrfs 之类的文件系统,GNU cp 支持写时复制,否则 git annex 将复制每个文件(最终,每个附加文件都会同时出现
.git
在工作副本下和常规文件中)。我认为这仍然不应该太慢,但会占用磁盘空间。