Por que `cp -uav` de um repositório git mostrou "removido" para alguns arquivos?

Por que `cp -uav` de um repositório git mostrou "removido" para alguns arquivos?

Eu costumava cp -uavatualizar uma cópia de um repositório git, incluindo arquivos não confirmados.

Por que disse que está removendo arquivos? Se parece com isso:

$ 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

Responder1

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 cp -uacomando abaixo stracemostrará que ele está realmente removendo ( unlink) os arquivos que diz.

O que aconteceu é que os objetos em repo/h/.git/objectssão hardlinks daqueles 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 -asignifica cp --preserve, que está documentado como

--preserve[=ATTR_LIST]

preserve os atributos especificados (padrão: modo, propriedade, carimbos de data e hora), se possível atributos adicionais: contexto, links, xattr, todos

A desvinculação acontece como parte da preservação do hardlink:

linkat(AT_FDCWD, "copiar/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "copiar/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = -1 EEXIST (Arquivo existe)

unlink("copiar/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885") = 0

linkat(AT_FDCWD, "copiar/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "copiar/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = 0

Por que exatamente isso gera mensagens que me confundiram tanto?

Parece que -u( --update) não está totalmente implementado neste código. É principalmente uma otimização de desempenho para evitar a cópia desnecessária de dados. Criar hardlinks não requer a cópia de nenhum dado.

Podemos ver outros cenários na documentação onde cptambém devemos 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 ele pode querer mostrar os arquivos específicos que precisa "forçar".

Suponho que também possa ser útil mostrar a exclusão, caso cpseja interrompida. 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 também não mostrou uma mensagem ao recriar os links, o que seria menos confuso. Eu suspeito que isso seja uma peculiaridade da -uopção.

informação relacionada