¿Hay alguna forma de conocer u obtener las marcas de tiempo originales creadas / modificadas? Gracias.
¿Hay alguna forma de conocer u obtener las marcas de tiempo originales creadas / modificadas? Gracias.
Respuestas:
Creo que las únicas marcas de tiempo registradas en la base de datos de Git son las marcas de tiempo de autor y de confirmación. 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).
Puede escribir un script para establecer la fecha de modificación de sus archivos a la hora de la confirmación más reciente. Podría verse algo como 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
SÍ , metastore o git-cache-meta pueden almacenar dicha (meta) información. Git por sí 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 pensados para ese mismo propósito, además de admitir utilidades de respaldo y herramientas de sincronización.
(Lo siento, solo un pequeño giro divertido en la respuesta de Jakub)
findla -printfextensión de GNU , y estoy casi seguro de que metastore (siendo un proyecto de C) es aún más complicado de hacer portátil. Muy desafortunado. Volveré a publicar aquí si descubro que esta situación cambia.
NO , Git simplemente no almacena dicha (meta) información , a menos que utilice 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 la hora en que se creó la confirmación (hora del confirmador).
Eso es por diseño, ya que Git es un sistema de control de versiones, no una utilidad de respaldo o herramienta de sincronización.
ACTUALIZACIÓN : TL; DR: git en sí mismo no guarda los tiempos originales, pero algunas soluciones evitan esto mediante varios métodos. git-restore-mtimees uno de ellos:
https://github.com/MestreLion/git-tools/
Ubuntu / Debian: sudo apt install git-restore-mtime
Fedora / RHEL / CentOS:sudo yum install git-tools
Vea mi otra respuesta para más detalles
Descargo de responsabilidad completo: soy el autor de git-tools
Este script de Python puede ayudar: para cada archivo se aplica la marca de tiempo de la confirmación más reciente donde se modificó el archivo:
A continuación se muestra una versión realmente básica del guión. Para el uso real, sugiero encarecidamente una de las versiones más sólidas 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 git whatchangedcomando, que es cientos de veces más rápido que recortar cada archivo. Menos de 4 segundos para git (24.000 confirmaciones, 2.500 archivos) y menos de 1 minuto para el kernel de Linux (40.000 archivos, 300.000 confirmaciones)
$ python ./git-restore-mtime Traceback (most recent call last): File "./git-restore-mtime", line 122, in <module> 'git rev-parse --show-toplevel --git-dir')).split('\n')[:2] TypeError: Type str doesn't support the buffer API¿Le importaría decirnos qué versión de Python se necesita? Estoy usando 3.3.3
stren Python 2 es el equivalente de bytestringen Python 3, mientras que stren Python 3 es unicodeen Python 2. ¿Puede informar este problema en github.com/MestreLion/git-tools/issues ?
He estado peleando con git y marcas de tiempo de archivos durante algún tiempo.
Probé algunas de tus ideas e hice mis propios scripts tremendamente grandes y predecesores / ram, hasta que encontré (en algún 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 conservar la última modificación de archivos basada en fechas de confirmación.
Entonces, después de un reajuste, el script 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 tendrán más de 10k archivos, esto debería tomar unos segundos en ejecutarse, por lo que puede conectarlo al checkout, pull u otros ganchos básicos de git.
Aquí está mi solución que toma en consideración 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 git loginforma, es el tiempo informado por el sistema. Si desea conocer el tiempo transcurrido desde que se comprometieron los archivos, utilice la git logsolución en lugar dedate -r
Native git no tiene la funcionalidad, pero se puede lograr mediante scripts de gancho o herramientas de terceros.
Lo he intentado metastore. Es muy rápido, pero no me gusta la necesidad de instalar y que los metadatos no se almacenan en formato de texto sin formato. git-cache-metaes una herramienta simple que he probado, pero es extremadamente lenta para repositorios grandes (para un repositorio con decenas de miles de archivos, se necesitan minutos para actualizar el archivo de metadatos) y podría tener problemas de compatibilidad entre plataformas. setgitpermsy otros enfoques también tienen sus defectos que no me gustan.
Por fin hice un script de gancho para este trabajo: git-store-meta . Tiene una dependencia muy ligera (* nix shell`` sorty perl, que es requerido por git, y opcionalmente chown, chgrpy touch) para que no se tenga que instalar nada adicional para una plataforma que pueda ejecutar git, rendimiento deseable (para un repositorio con decenas de miles de archivos, se necesitan menos de 10 segundos para actualizar el archivo de metadatos; aunque más para crearlo), guarda los datos en formato de texto plano , y qué metadatos se "guardar" o "cargar" es personalizable .
Me ha funcionado bien. Pruebe esto si no está satisfecho con metastore, git-cache-meta y otros enfoques.
Espero que aprecies la sencillez:
# getcheckin - Retrieve the last committed checkin date and time for
# each of the files in the git project. After a "pull"
# of the project, you can update the timestamp on the
# pulled files to match that date/time. There are many
# that believe that this is not a good idea, but
# I found it useful to get the right source file dates
#
# NOTE: This script produces commands suitable for
# piping into BASH or other shell
# License: Creative Commons Attribution 3.0 United States
# (CC by 3.0 US)
##########
# walk back to the project parent or the relative pathnames don't make
# sense
##########
while [ ! -d ./.git ]
do
cd ..
done
echo "cd $(pwd)"
##########
# Note that the date format is ISO so that touch will work
##########
git ls-tree -r --full-tree HEAD |\
sed -e "s/.*\t//" | while read filename; do
echo "touch --date=\"$(git log -1 --date=iso --format="%ad" -- "$filename")\" -m $filename"
done
Para el entorno de Windows, escribí un pequeño (rápido y sucio) EXE en Delphi 10.1 Berlín que recopila todas las fechas de archivo en el árbol de fuentes en el archivo .gitfilattr y puede aplicarlas nuevamente en el árbol de fuentes comprobado.
Por supuesto que 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.
Hay cierta ambigüedad en mi (y en la de otros) interpretación del OP sobre si esto significa el tiempo de compromiso o algo más, pero asumiendo que significa tiempo de compromiso, entonces esta simple frase funcionará en Linux (según 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 (incluidos los ganchos de git) vinculadas desde un comentario a la pregunta original de cregox.
--date=@foo
Con herramientas 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 <andrew.wood@ivarch.com>
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
En CentOS 7 tiene /usr/share/doc/rsync-*/support/git-set-file-timesy en Debian (y derivados) el mismo script /usr/share/doc/rsync/scripts/git-set-file-times.gz, el original es de Eric Wong y está aquí https://yhbt.net/git-set-file-times .
Funciona más rápido que otros ejemplos mencionados aquí y puede que le resulte más útil tenerlo ya en su distribución de Linux.
Aquí está el mío.
Un poco más rápido que otros, ya que no estoy llamando a 'obtener registro' para cada archivo encontrado; en su lugar, llamar a 'git log' una vez y transformar esa salida en comandos táctiles.
Habrá casos en los que haya demasiados archivos enumerados en una confirmación para que quepan en un solo búfer de comando de shell; ejecute "getconf ARG_MAX" para ver la longitud máxima de un comando en bytes - en mi instalación de Debian, es 2MB, que es suficiente.
# set file last modification time to last commit of file
git log --reverse --date=iso --name-only | \
grep -vE "^(commit |Merge:|Author:| |^$)" | \
grep -B 1 "^[^D][^a][^t][^e][^:][^ ]" | \
grep -v "^\-\-" | \
sed "s|^\(.*\)$|\"\1\"|;s|^\"Date: *\(.*\)\"$|~touch -c -m -d'\1'|" | \
tr '~\n' '\n ' | \
sh -
descripción por línea:
En términos de velocidad, 5 segundos 1700 se confirman para 6500 archivos en 700 directorios.