为什么 git 存储库的“cp -uav”某些文件显示“已删除”?

为什么 git 存储库的“cp -uav”某些文件显示“已删除”?

我曾经cp -uav更新 git 存储库的副本,包括未提交的文件。

为什么说它正在删除文件?它看起来像这样:

$ cp -uav repos copy
removed 'copy/repos/h/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391'
removed 'copy/repos/h/.git/objects/3b/b3f834dd037db9298b10d71e0cd7383000fa1c'
removed 'copy/repos/h/.git/objects/49/6d6428b9cf92981dc9495211e6e1120fb6f2ba'
removed 'copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885'

$ rpm -q --whatprovides `which cp`
coreutils-8.25-17.fc25.x86_64

答案1

我可以按如下方式重现上述消息:

mkdir test; cd test
mkdir repos; cd repos

mkdir g; cd g
git init
touch a
git add a
git commit -m test
cd ..

git clone g h
cd ..

mkdir copy
cp -ua repos copy
cp -uav repos copy

运行cp -ua下面的命令strace将显示它确实正在删除 ( unlink) 它所说的文件。

发生的情况是 中的对象repo/h/.git/objects是 中的对象的硬链接repo/g/.git/objects。 (在我原来的情况下,我正在复制一个包含子存储库的存储库,这些子存储库最初是作为主存储库的克隆创建的)。

cp -a意味着cp --preserve,记录为

--preserve[=ATTR_LIST]

保留指定的属性(默认:模式、所有权、时间戳),如果可能的话附加属性:上下文、链接、xattr、全部

取消链接作为硬链接保留的一部分发生:

linkat(AT_FDCWD,“复制/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885”,AT_FDCWD,“复制/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885 ", 0) = -1 EEXIST(文件存在)

取消链接(“复制/存储库/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885”)= 0

linkat(AT_FDCWD,“复制/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885”,AT_FDCWD,“复制/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885 ”, 0) = 0

至于为什么它会产生令我如此困惑的消息?

这段代码中似乎-u( ) 没有完全实现。--update它主要是性能优化,以避免不必要的重新复制数据。制作硬链接不需要复制任何数据。

我们可以在文档中看到其他cp也必须删除文件的场景:

   -f, --force

         if an existing destination file cannot be opened, remove it and try again (this option is ignored when the -n option is also used)

在这种情况下-f,我可以理解它可能想显示它必须“强制”的特定文件。

我想,如果被中断的话,显示删除也可能很有用cp。否则,用户不太可能意识到文件可能已从目标中删除(作为中间步骤)。

最终的问题是,为什么它在重新创建链接时没有显示消息,这样就不会那么混乱了。我怀疑这是该-u选项的一个怪癖。

相关内容