I can reproduce the above messages as follows:
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
The running the cp -ua
command under strace
will show that it is indeed removing (unlink
) the files it says.
What's happened is that the objects in repo/h/.git/objects
are hardlinks of the ones in repo/g/.git/objects
. (In my original case, I was copying a repo which contained sub-repos, which were originally created as clones of the main repo).
cp -a
means cp --preserve
, which is documented as
--preserve[=ATTR_LIST]
preserve the specified attributes (default: mode,ownership,timestamps), if possible additional attributes: context, links, xattr,
all
The unlink happens as part of hardlink preservation:
linkat(AT_FDCWD,
"copy/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885",
AT_FDCWD,
"copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0)
= -1 EEXIST (File exists)
unlink("copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885")
= 0
linkat(AT_FDCWD,
"copy/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885",
AT_FDCWD,
"copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0)
= 0
As to exactly why it generates messages which confused me so?
It seems like -u
(--update
) is not quite implemented in this code. It's mainly a performance optimization to avoid re-copying data unecessarily. Making hardlinks doesn't require copying any data.
We can see other scenarios in the documentation where cp
must remove files as well:
-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)
In the case of -f
, I can understand that it might want to show the specific files that it has to "force".
I suppose it might also be useful to show deletion, in case cp
is interrupted. Otherwise, users would be unlikely to realize that a file could have been deleted from the destination (as an intermediate step).
The ultimate question is why it did not also show a message when it re-created the links, which would be less confusing. I suspect this is a quirk of the -u
option.