Eu posso reproduzir as mensagens acima da seguinte forma:
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
A execução do comando cp -ua
em strace
mostrará que, de fato, está removendo ( unlink
) os arquivos que ele diz.
O que aconteceu é que os objetos em repo/h/.git/objects
são hardlinks dos que estão em repo/g/.git/objects
. (No meu caso original, eu estava copiando um repositório que continha sub-repos, que foram originalmente criados como clones do repositório principal).
cp -a
significa cp --preserve
, documentado como
--preserve[=ATTR_LIST]
preserve the specified attributes (default: mode,ownership,timestamps), if possible additional attributes: context, links, xattr, all
O unlink acontece como parte da preservação de hardlink:
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
Por que exatamente gera mensagens que me confundiram?
Parece que -u
( --update
) não está implementado neste código. É principalmente uma otimização de desempenho para evitar a recopiação de dados desnecessariamente. Fazer hardlinks não requer copiar nenhum dado.
Podemos ver outros cenários na documentação em que cp
também deve remover arquivos:
-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)
No caso de -f
, posso entender que talvez seja necessário mostrar os arquivos específicos que ele deve "forçar".
Suponho que também possa ser útil mostrar a exclusão, no caso de cp
ser interrompido. Caso contrário, seria improvável que os usuários percebessem que um arquivo poderia ter sido excluído do destino (como uma etapa intermediária).
A questão final é por que ela também não mostrava uma mensagem quando recriava os links, o que seria menos confuso. Eu suspeito que isso seja uma peculiaridade da opção -u
.