¿Por qué `cp -uav` de un repositorio de git se muestra "eliminado" para algunos archivos?

¿Por qué `cp -uav` de un repositorio de git se muestra "eliminado" para algunos archivos?

Solía cp -uav​​actualizar una copia de un repositorio de git, incluidos los archivos no confirmados.

¿Por qué dice que está eliminando archivos? Se parece a esto:

$ 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

Respuesta1

Puedo reproducir los mensajes anteriores de la siguiente manera:

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

La ejecución del cp -uacomando a continuación stracemostrará que efectivamente está eliminando ( unlink) los archivos que dice.

Lo que sucedió es que los objetos en repo/h/.git/objectsson enlaces duros de los que están en repo/g/.git/objects. (En mi caso original, estaba copiando un repositorio que contenía subrepositorios, que se crearon originalmente como clones del repositorio principal).

cp -asignifica cp --preserve, que está documentado como

--preserve[=ATTR_LIST]

preservar los atributos especificados (predeterminado: modo, propiedad, marcas de tiempo), si es posible atributos adicionales: contexto, enlaces, xattr, todos

La desvinculación ocurre como parte de la preservación del vínculo físico:

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

desvincular("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/bf350cea1fb4fd036235d7e6c36eb600e6888 5", 0) = 0

¿Exactamente por qué genera mensajes que me confundieron tanto?

Parece que -u( --update) no está del todo implementado en este código. Es principalmente una optimización del rendimiento para evitar volver a copiar datos innecesariamente. Para crear enlaces duros no es necesario copiar ningún dato.

Podemos ver otros escenarios en la documentación donde cptambién debemos eliminar archivos:

   -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)

En el caso de -f, puedo entender que es posible que desee mostrar los archivos específicos que tiene que "forzar".

Supongo que también podría resultar útil mostrar la eliminación, en caso de que cpse interrumpa. De lo contrario, es poco probable que los usuarios se den cuenta de que un archivo podría haberse eliminado del destino (como paso intermedio).

La pregunta final es por qué no mostró también un mensaje cuando recreó los enlaces, lo que sería menos confuso. Sospecho que esto es una peculiaridad de la -uopción.

información relacionada