git - procedimiento - tecnicas de archivo de documentos
Verificación del archivo antiguo CON sellos de tiempo originales creados/modificados (12)
Aquí está mi solución que toma en cuenta las rutas que contienen espacios:
#! /bin/bash
IFS=$''/n''
list_of_files=($(git ls-files | sort))
unset IFS
for file in "${list_of_files[@]}"; do
file_name=$(echo $file)
## When you collect the timestamps:
TIME=$(date -r "$file_name" -Ins)
## When you want to recover back the timestamps:
touch -m -d $TIME "$file_name"
done
Tenga en cuenta que esto no toma el tiempo que reporta el git log
, es el tiempo reportado por el sistema. Si desea el tiempo transcurrido desde que se cometieron los archivos, use la solución de git log
lugar de la date -r
¿Hay alguna manera de saber u obtener las marcas de tiempo crea / modificadas originales? Gracias.
Con las herramientas de GNU.
s=$(git ls-files | wc -l);
git ls-files -z |
xargs -0 -I{} -n1 bash -c /
"git log --date=format:%Y%m%d%H%M.%S ''--pretty=format:touch -m -t %cd /"{}/"%n'' -n1 -- {}"|
pv -l -s$s |
parallel -n1 -j8
967 0:00:05 [ 171 /s] [=====================================> ] 16%
.
$ git --version ; xargs --version | sed 1q ; ls --version | sed 1q;
parallel --version | sed 1q; pv --version | sed 1q; sh --version | sed 1q
git version 2.13.0
xargs (GNU findutils) 4.6.0
ls (GNU coreutils) 8.25
GNU parallel 20150522
pv 1.6.0 - Copyright 2015 Andrew Wood <[email protected]>
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
Creo que las únicas marcas de tiempo registradas en la base de datos de Git son las marcas de tiempo de autor y de compromiso. No veo una opción para que Git modifique la marca de tiempo del archivo para que coincida con la confirmación más reciente, y tiene sentido que este no sea el comportamiento predeterminado (porque si lo fuera, Makefiles no funcionaría correctamente).
Podría escribir una secuencia de comandos para establecer la fecha de modificación de sus archivos a la hora de la confirmación más reciente. Puede parecerse a esto:
IFS="
"
for FILE in $(git ls-files)
do
TIME=$(git log --pretty=format:%cd -n 1 --date=iso -- "$FILE")
TIME=$(date -j -f ''%Y-%m-%d %H:%M:%S %z'' "$TIME" +%Y%m%d%H%M.%S)
touch -m -t "$TIME" "$FILE"
done
Esta secuencia de comandos python puede ayudar: para cada archivo se aplica la marca de tiempo de la confirmación más reciente donde se modificó el archivo:
- Funcionalidad principal , con --help, debug messages. Se puede ejecutar en cualquier lugar dentro del árbol de trabajo
- Bestia hecha y derecha , con muchas opciones. Admite cualquier diseño de repositorio.
A continuación se muestra una versión realmente escueta del guión. Para el uso real, recomiendo encarecidamente una de las versiones más robustas anteriores:
#!/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
Todas las versiones analizan el registro completo generado por un solo comando git whatchanged
, que es cientos de veces más rápido que cortar para cada archivo. Menos de 4 segundos para git (24,000 commits, 2,500 archivos) y menos de 1 minuto para Linux kernel (40,000 archivos, 300,000 commits)
Esto me engañó en ubuntu (que carece de OSX la bandera "-j" en la fecha (1))
for FILE in $(git ls-files)
do
TIME=$(git log --pretty=format:%cd -n 1 --date=iso $FILE)
TIME2=`echo $TIME | sed ''s/-//g;s/ //;s/://;s/://./;s/ .*//''`
touch -m -t $TIME2 $FILE
done
Hay una cierta ambigüedad en mi interpretación (y la de otros) del OP acerca de si esto significa el tiempo de compromiso u otra cosa, pero suponiendo que signifique tiempo de compromiso, entonces este simple one-liner funcionará en Linux (basado en el fragmento de respuesta de Dietrich Epp )
git ls-files | xargs -I{} bash -c ''touch "{}" --date=@$(git log -n1 --pretty=format:%ct -- "{}")''
Pero hay respuestas más sofisticadas (incluyendo git hooks) vinculadas desde un comentario a la pregunta original de cregox.
He estado escaramuzando con marcas de tiempo git y file desde hace un tiempo.
Probé algunas de sus ideas e hice mis propias secuencias de comandos terriblemente grandes y predecesoras / ram, hasta que encontré (en alguna wiki de git) un script en Perl que hace casi lo que quería. https://git.wiki.kernel.org/index.php/ExampleScripts
Y lo que quería es poder preservar la última modificación de archivos en función de las fechas de confirmación.
Entonces, después de un reajuste, la secuencia de comandos puede cambiar la fecha de creación y modificación de 200k archivos en aproximadamente 2-3 minutos .
#!/usr/bin/perl
my %attributions;
my $remaining = 0;
open IN, "git ls-tree -r --full-name HEAD |" or die;
while (<IN>) {
if (/^/S+/s+blob /S+/s+(/S+)$/) {
$attributions{$1} = -1;
}
}
close IN;
$remaining = (keys %attributions) + 1;
print "Number of files: $remaining/n";
open IN, "git log -r --root --raw --no-abbrev --date=raw --pretty=format:%h~%cd~ |" or die;
while (<IN>) {
if (/^([^:~]+)~([^~]+)~$/) {
($commit, $date) = ($1, $2);
} elsif (/^:/S+/s+1/S+/s+/S+/s+/S+/s+/S/s+(.*)$/) {
if ($attributions{$1} == -1) {
$attributions{$1} = "$date";
$remaining--;
utime $date, $date, $1;
if ($remaining % 1000 == 0) {
print "$remaining/n";
}
if ($remaining <= 0) {
break;
}
}
}
}
close IN;
Suponiendo que sus repositorios no tengan archivos 10k +, esto debería tomar unos segundos para ejecutarse, por lo que puede engancharlo a la caja, tirar u otros ganchos básicos de git.
Native Git no tiene la funcionalidad, pero se puede lograr mediante scripts de gancho o herramientas de terceros.
He intentado con metastore
. Es muy rápido, pero no me gusta la necesidad de instalar y los metadatos no se almacenan en formato de texto plano. git-cache-meta
es una herramienta simple que he probado, pero es extremadamente lenta para grandes repos (para un repositorio con decenas de miles de archivos, lleva minutos actualizar el archivo de metadatos) y podría tener problemas de compatibilidad multiplataforma. setgitperms
y otros enfoques también tienen sus defectos que no me gustan.
Por fin hice un guión de gancho para este trabajo: git-store-meta . Tiene una dependencia muy ligera (* nix shell, sort
y perl
, que es requerida por git, y opcionalmente chown
, chgrp
y touch
) para que no se tenga que instalar nada adicional para una plataforma que pueda ejecutar git, el rendimiento deseable (para un Repo con decenas de miles de archivos, lleva <10 segundos actualizar el archivo de metadatos, aunque es más tiempo de crear), guarda los datos en formato de texto plano y los metadatos que se "guardan" o "cargan" son personalizables .
Me ha funcionado bien Intente esto si no está satisfecho con metastore, git-cache-meta y otros enfoques.
Para el entorno de Windows, escribí un pequeño (rápido y sucio) archivo EXE en Delphi 10.1 Berlin que recopila todas las fechas de archivo en el árbol fuente en el archivo .gitfilattr y puede aplicarlas nuevamente en el árbol de fuentes revisadas.
Por supuesto, comparto el código en GitHub:
https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr
Lo uso en mi sistema de compilación basado en corredores de GitLab.
Ver Metastore
Está contenido en el repositorio debain, solo apt-get install metastore
.
NO , Git simplemente no almacena esa (meta) información , a menos que use herramientas de terceros como Metastore o git-cache-meta. La única marca de tiempo que se almacena es la hora en que se creó el parche / cambio (hora del autor), y se creó el tiempo de confirmación (tiempo del autor).
Eso es por diseño, ya que Git es un sistema de control de versiones, no una utilidad de copia de seguridad ni una herramienta de sincronización.
SÍ , metastore o git-cache-meta puede almacenar esa (meta) información! Git solo, sin herramientas de terceros, no puede. Metastore o git-cache-meta pueden almacenar cualquier metadato de archivo para un archivo.
Eso es por diseño, ya que metastore o git-cache-meta están destinados para ese propósito, así como también son compatibles con herramientas de sincronización y utilidades de respaldo.
(Lo siento, solo un poco de diversión girando en la respuesta de Jakub)