我曾经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
选项的一个怪癖。