Früher habe ich cp -uav
eine Kopie eines Git-Repos aktualisiert, einschließlich nicht festgeschriebener Dateien.
Warum wird angezeigt, dass Dateien entfernt werden? Es sieht so aus:
$ 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
Antwort1
Ich kann die obigen Meldungen wie folgt reproduzieren:
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
Das Ausführen des cp -ua
Befehls strace
zeigt, dass unlink
die angegebenen Dateien tatsächlich entfernt werden ().
Was passiert ist, ist, dass die Objekte in repo/h/.git/objects
Hardlinks der Objekte in sind repo/g/.git/objects
. (In meinem ursprünglichen Fall habe ich ein Repo kopiert, das Unter-Repos enthielt, die ursprünglich als Klone des Haupt-Repos erstellt wurden.)
cp -a
bedeutet cp --preserve
, was dokumentiert ist als
--preserve[=ATTR_LIST]
Behalte die angegebenen Attribute bei (Standard: Modus, Besitz, Zeitstempel), wenn möglich zusätzliche Attribute: Kontext, Links, Xattr, alle
Die Aufhebung der Verknüpfung erfolgt im Rahmen der Hardlink-Erhaltung:
linkat(AT_FDCWD, "copy/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = -1 EEXIST (Datei existiert)
Verknüpfung aufheben("copy/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885") = 0
linkat(AT_FDCWD, "kopiere/repos/g/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", AT_FDCWD, "kopiere/repos/h/.git/objects/2b/bf350cea1fb4fd036235d7e6c36eb600e68885", 0) = 0
Warum genau werden Meldungen generiert, die mich so verwirren?
Es scheint, als ob -u
( --update
) in diesem Code nicht vollständig implementiert ist. Es handelt sich hauptsächlich um eine Leistungsoptimierung, um unnötiges erneutes Kopieren von Daten zu vermeiden. Für das Erstellen von Hardlinks ist kein Kopieren von Daten erforderlich.
In der Dokumentation sind noch weitere Szenarien zu sehen, in denen cp
ebenfalls Dateien entfernt werden müssen:
-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)
Im Falle von -f
kann ich verstehen, dass es möglicherweise die spezifischen Dateien anzeigen möchte, die es „erzwingen“ muss.
Ich denke, es könnte auch nützlich sein, das Löschen anzuzeigen, falls cp
es unterbrochen wird. Andernfalls würden Benutzer wahrscheinlich nicht erkennen, dass eine Datei (als Zwischenschritt) vom Ziel gelöscht worden sein könnte.
Die eigentliche Frage ist, warum beim erneuten Erstellen der Links nicht auch eine Meldung angezeigt wurde, was weniger verwirrend wäre. Ich vermute, dass dies eine Eigenart der -u
Option ist.