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 -ua
comando a continuación strace
mostrará que efectivamente está eliminando ( unlink
) los archivos que dice.
Lo que sucedió es que los objetos en repo/h/.git/objects
son 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 -a
significa 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 cp
tambié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 cp
se 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 -u
opción.