Сначала я попытаюсь немного разобраться в проблеме. У нас есть проект, который строится в большом дереве файлов. Сборка составляет несколько сотен МБ, содержит множество (мелких) файлов, лишь небольшая часть которых меняется между сборками. Мы хотим сохранить немного истории этих сборок, и для этого мы хотим жестко связать файлы, которые не меняются между сборками. Для этого мы используем rsync
(как более могущественный брат cp
), из локального источника в локальную мишень с опцией --link-dest
для выполнения магии жесткого связывания.
Это отлично работает для инкрементных сборок: большинство файлов не затрагиваются, и rsync
правильно выполняет трюк с жесткой ссылкой. С полной перекомпиляцией сборок (что мы должны делать по причинам, которые здесь не уместны), кажется, что все работает не так, как ожидалось. Из-за перекомпиляции все файлы получают новую метку времени, но с точки зрения содержимого большинство файлов по-прежнему совпадают с предыдущей сборкой. Но даже несмотря на то, что мы используем rsync
с опцией --checksum
(поэтому rsync
«синхронизирует»/жесткие ссылки на основе содержимого, а не размера файла + метки времени), ничто больше не становится жестко связанным.
Я попытался выделить/проиллюстрировать проблему с помощью этого простого (bash) скрипта:
echo "--- Start clean"
rm -fr src build*
echo "--- Set up src"
mkdir src
echo hello world > src/helloworld.txt
echo "--- First copy with src as hardlink reference"
rsync -a --checksum --link-dest=$(pwd)/src src/ build1/
echo "--- Second copy with first copy as hardlink reference"
rsync -a --checksum --link-dest=$(pwd)/build1 src/ build2/
echo "--- Result (as expected)"
ls -ali src/helloworld.txt build*/helloworld.txt
echo "--- Sleep to have reasonable timestamp differences"
sleep 2
echo "--- 'Remake' src, but with same content"
rm -fr src/helloworld.txt
echo hello world > src/helloworld.txt
echo "Third copy with second copy as hardlink reference"
rsync -a --checksum --link-dest=$(pwd)/build2 src/ build3
# Using --modify-window=10 gives results as expected
# rsync -a --modify-window=10 --link-dest=$(pwd)/build2 src/ build3
echo "Final result, not as expected"
ls -ali src/helloworld.txt build*/helloworld.txt
Первый результат, как и ожидалось: все три копии жестко связаны (один и тот же inode)
30157018 -rw-r--r-- 3 stefaan staff 12 May 10 01:28 build1/helloworld.txt
30157018 -rw-r--r-- 3 stefaan staff 12 May 10 01:28 build2/helloworld.txt
30157018 -rw-r--r-- 3 stefaan staff 12 May 10 01:28 src/helloworld.txt
Конечный результат не такой, как ожидалось/желательно:
30157018 -rw-r--r-- 2 stefaan staff 12 May 10 01:28 build1/helloworld.txt
30157018 -rw-r--r-- 2 stefaan staff 12 May 10 01:28 build2/helloworld.txt
30157026 -rw-r--r-- 1 stefaan staff 12 May 10 01:28 build3/helloworld.txt
30157024 -rw-r--r-- 1 stefaan staff 12 May 10 01:28 src/helloworld.txt
Третья копия build3/helloworld.txt
не имеет жесткой ссылки на копию из build2
, даже если содержимое одинаковое, поэтому проверка контрольной суммы должна видеть это.
Кто-нибудь имеет представление о том, что здесь не так? Неужели мои ожидания ошибочны? Или rsync игнорирует --опция checksum
при синхронизации с локальной на локальную, например, потому что известно, что смотреть на числа inode разумнее, чем тратить время на контрольные суммы?