ОБНОВЛЕНИЕ : мое решение теперь упаковано в Debian / Ubuntu / Mint, Fedora, Gentoo и, возможно, в другие дистрибутивы:
https://github.com/MestreLion/git-tools#install
sudo apt install git-restore-mtime # Debian/Ubuntu/Mint
yum install git-tools # Fedora/ RHEL / CentOS
emerge dev-vcs/git-tools # Gentoo
IMHO, отказ от хранения меток времени (и других метаданных, таких как разрешения и владение) является большим ограничением git.
Обоснование Линуса того, что временные метки вредны только потому, что они "сбивают с толку make", неубедительно :
make clean достаточно, чтобы исправить любые проблемы.
Применимо только к проектам, использующим make, в основном, C / C ++. Это совершенно не подходит для таких скриптов, как Python, Perl или документации в целом.
Будет только вред, если вы примените временные метки. Хранить их в репо не повредит . Их применение может быть простым --with-timestampsвариантом для git checkoutдрузей ( cloneи pullт. Д.) По усмотрению пользователя .
И Bazaar, и Mercurial хранят метаданные. Пользователи могут применять их или нет при оформлении заказа. Но в git, поскольку исходные временные метки даже не доступны в репо, такой опции нет.
Итак, для очень небольшого выигрыша (без необходимости заново компилировать все), специфичного для подмножества проектов, gitпоскольку общая DVCS была повреждена , некоторая информация о файлах потеряна , и, как сказал Линус, НЕОБХОДИМО сделать это сейчас. Грустно .
Тем не менее, могу ли я предложить 2 подхода?
1 - http://repo.or.cz/w/metastore.git , Дэвид Хердеман. Пытается сделать то, что git должно было быть сделано в первую очередь : сохраняет метаданные (не только временные метки) в репозитории при фиксации (с помощью хука предварительной фиксации) и повторно применяет их при извлечении (также с помощью хуков).
2 - Моя скромная версия скрипта, который я использовал раньше для создания архивов релизов. Как уже упоминалось в других ответах, подход немного отличается : применять для каждого файла , временная метка из самой последней фиксации , где был изменен файл.
- git-restore-mtime с множеством опций поддерживает любой макет репозитория и работает на Python 3.
Ниже приведена действительно простая версия скрипта в качестве доказательства концепции на Python 2.7. Для фактического использования я настоятельно рекомендую полную версию, указанную выше:
#!/usr/bin/env python
# Bare-bones version. Current dir must be top-level of work tree.
# Usage: git-restore-mtime-bare [pathspecs...]
# By default update all files
# Example: to only update only the README and files in ./doc:
# git-restore-mtime-bare README doc
import subprocess, shlex
import sys, os.path
filelist = set()
for path in (sys.argv[1:] or [os.path.curdir]):
if os.path.isfile(path) or os.path.islink(path):
filelist.add(os.path.relpath(path))
elif os.path.isdir(path):
for root, subdirs, files in os.walk(path):
if '.git' in subdirs:
subdirs.remove('.git')
for file in files:
filelist.add(os.path.relpath(os.path.join(root, file)))
mtime = 0
gitobj = subprocess.Popen(shlex.split('git whatchanged --pretty=%at'),
stdout=subprocess.PIPE)
for line in gitobj.stdout:
line = line.strip()
if not line: continue
if line.startswith(':'):
file = line.split('\t')[-1]
if file in filelist:
filelist.remove(file)
#print mtime, file
os.utime(file, (mtime, mtime))
else:
mtime = long(line)
# All files done?
if not filelist:
break
Производительность очень впечатляет, даже для монстра проектов wine, gitили даже ядра Linux:
bash
# 0.27 seconds
# 5,750 log lines processed
# 62 commits evaluated
# 1,155 updated files
git
# 3.71 seconds
# 96,702 log lines processed
# 24,217 commits evaluated
# 2,495 updated files
wine
# 13.53 seconds
# 443,979 log lines processed
# 91,703 commits evaluated
# 6,005 updated files
linux kernel
# 59.11 seconds
# 1,484,567 log lines processed
# 313,164 commits evaluated
# 40,902 updated files