Почему `cp -uav` в репозитории git показывает «удалено» для некоторых файлов?

Почему `cp -uav` в репозитории git показывает «удалено» для некоторых файлов?

Раньше я cp -uavобновлял копию репозитория git, включая незафиксированные файлы.

Почему он сказал, что удаляет файлы? Это выглядит так:

$ 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

решение1

Я могу воспроизвести приведенные выше сообщения следующим образом:

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

Выполнение cp -uaкоманды straceпокажет, что она действительно удаляет ( unlink) указанные в ней файлы.

Произошло следующее: объекты в repo/h/.git/objectsявляются жесткими ссылками на объекты в repo/g/.git/objects. (В моем первоначальном случае я копировал репозиторий, содержащий подрепозитории, которые изначально были созданы как клоны основного репозитория).

cp -aозначает cp --preserve, что документировано как

--preserve[=СПИСОК_АТТР]

сохранить указанные атрибуты (по умолчанию: режим, владение, временные метки), если возможно, дополнительные атрибуты: контекст, ссылки, xattr, все

Отмена ссылки происходит в рамках сохранения жесткой ссылки:

linkat(AT_FDCWD, "copy/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = -1 EEXIST (Файл существует)

unlink("копия/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885") = 0

ссылка(AT_FDCWD, "копировать/репозитории/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "копировать/репозитории/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = 0

А почему именно он генерирует сообщения, которые меня так сбивают с толку?

Похоже, -u( --update) не совсем реализовано в этом коде. Это в основном оптимизация производительности, чтобы избежать ненужного повторного копирования данных. Создание жестких ссылок не требует копирования каких-либо данных.

В документации мы можем увидеть cpи другие сценарии, когда необходимо удалить файлы:

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

В случае с -f, я могу понять, что он может захотеть показать конкретные файлы, которые ему нужно «заставить».

Я полагаю, что также может быть полезно показывать удаление, на случай cpпрерывания. В противном случае пользователи вряд ли поймут, что файл мог быть удален из места назначения (как промежуточный шаг).

Главный вопрос в том, почему он также не показал сообщение при повторном создании ссылок, что было бы менее запутанным. Я подозреваю, что это особенность опции -u.

Связанный контент