AGGIORNAMENTO : La mia soluzione è ora impacchettata in Debian / Ubuntu / Mint, Fedora, Gentoo e possibilmente altre distribuzioni:
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, non memorizzare i timestamp (e altri metadati come autorizzazioni e proprietà) è una grande limitazione di git
.
La logica di Linus secondo cui i timestamp sono dannosi solo perché "confonde make
" è debole :
make clean
è sufficiente per risolvere eventuali problemi.
Si applica solo ai progetti che utilizzano make
, principalmente C / C ++. È completamente discutibile per script come Python, Perl o documentazione in generale.
C'è solo un danno se applichi i timestamp. Non ci sarebbe alcun danno a conservarli in repo. Applicarli potrebbe essere --with-timestamps
un'opzione semplice per git checkout
e amici ( clone
, pull
ecc.), In discrezione dell'utente .
Sia Bazaar che Mercurial memorizzano i metadati. Gli utenti possono applicarli o meno durante il check-out. Ma in git, poiché i timestamp originali non sono nemmeno disponibili nel repo, non esiste tale opzione.
Quindi, per un guadagno molto piccolo (non dover ricompilare tutto) che è specifico per un sottoinsieme di progetti, git
poiché un DVCS generale è stato paralizzato , alcune informazioni sui file vengono perse e, come ha detto Linus, è INFEASIBILE da fare ora.Triste .
Detto questo, posso offrire 2 approcci?
1 - http://repo.or.cz/w/metastore.git , di David Härdeman. Cerca di fare ciò che git
avrebbe dovuto fare in primo luogo : memorizza i metadati (non solo i timestamp) nel repository durante il commit (tramite hook pre-commit) e li riapplica durante il pull (anche tramite hook).
2 - La mia modesta versione di uno script che ho usato prima per generare tarball di rilascio. Come accennato in altre risposte, l'approccio è leggermente diverso : applicare per ogni file il timestamp del commit più recente in cui il file è stato modificato.
- git-restore-mtime , con molte opzioni, supporta qualsiasi layout di repository e funziona su Python 3.
Di seguito è riportata una versione davvero essenziale dello script, come prova di concetto, su Python 2.7. Per l'utilizzo effettivo, consiglio vivamente la versione completa sopra:
#!/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
Le prestazioni sono piuttosto impressionanti, anche per i progetti mostruosi wine
, git
o anche per il kernel 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