Проверка старого файла с оригинальным созданием/изменением временных меток

Есть ли способ узнать или получить оригинальные временные метки создания/изменения? Спасибо.

Ответ 1

Я считаю, что единственными временными метками, записанными в базе данных Git, являются отметки времени автора и фиксации. Я не вижу опции для Git, чтобы изменить временную метку файла, чтобы она соответствовала последней фиксации, и имеет смысл, что это не будет поведение по умолчанию (потому что если бы это было, Makefiles не работал бы корректно).

Вы можете написать script, чтобы установить дату изменения ваших файлов на время последней фиксации. Это может выглядеть примерно так:

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

Ответ 2

ДА, метастор или git -cache-meta могут хранить такую ​​(мета) информацию! Git самостоятельно, без сторонних инструментов, т. Metastore или git -cache-meta может хранить любые метаданные файла для файла.

Это по дизайну, так как metastore или git -cache-meta предназначены для этой цели, а также поддерживают утилиты резервного копирования и инструменты синхронизации.

(Извините, просто немного смешно от ответа Якуба)

Ответ 3

НЕТ, Git просто не сохраняет такую информацию (meta-), если вы не используете сторонние инструменты, такие как метастор или git-cache-meta. Единственная временная метка, которая хранится, - это временный патч/изменение (время автора), и было создано время фиксации (время коммиттера).

Это по дизайну, поскольку Git - это система контроля версий, а не утилита резервного копирования или инструмент синхронизации.

Ответ 4

Этот python script может помочь: для каждого файла применяется метка времени последней фиксации, где файл был изменен:

Ниже приведена действительно голой версия script. Для фактического использования я настоятельно рекомендую одну из более надежных версий выше:

#!/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

Все версии анализируют полный журнал, сгенерированный одной командой git whatchanged, которая в сотни раз быстрее, чем lopping для каждого файла. Менее 4 секунд для git (24 000 коммитов, 2500 файлов) и менее 1 минуты для ядра linux (40 000 файлов, 300 000 коммитов)

Ответ 5

Это он трюк для меня на ubuntu (в котором отсутствует OSX флаг "-j" в дате (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 

Ответ 6

Я уже некоторое время перестал встречаться с git и временными отметками файла.

Протестировал некоторые из ваших идей и сделал мои собственные ужасно огромные и тяжелые сценарии предшественника /ram, пока я не нашел (на некоторой wiki wiki) script в perl, который делает почти то, что я хотел. https://git.wiki.kernel.org/index.php/ExampleScripts

И я хотел бы сохранить последнюю модификацию файлов на основе дат фиксации.

Итак, после некоторой корректировки script может изменить дату создания и изменения файлов 200 тыс. вокруг 2-3 мин.

#!/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;

Предполагая, что ваши хранилища не будут иметь файлы размером 10k +, для выполнения этого потребуется несколько секунд, поэтому вы можете подключить его к выходу, потяните или другим базовым крючкам git.

Ответ 8

Вот мое решение, которое учитывает пути, содержащие пробелы:

#! /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

Обратите внимание, что это не занимает время, которое сообщает git log, это время, сообщаемое системой. Если вы хотите, чтобы время с момента загрузки файлов использовало решение git log вместо date -r

Ответ 9

Native git не имеет функциональности, но это может быть достигнуто с помощью скриптов hook или сторонних инструментов.

Я пробовал metastore. Это очень быстро, но мне не нравится необходимость установки и метаданные не хранятся в текстовом формате. git-cache-meta - простой инструмент, который я пробовал, но он очень медленный для больших репозиториев (для репо с десятками тысяч файлов требуется несколько минут для обновления файла метаданных) и может иметь проблемы с межплатформенной совместимостью. setgitperms и другие подходы также имеют свои недостатки, которые мне не нравятся.

Наконец, я сделал крючок script для этого задания: git-store-meta. Он имеет очень легкую зависимость (* nix shell, sort и perl, которая требуется git и необязательно chown, chgrp и touch), так что для платформы, которая может запускать git, желаемую производительность (для репо с десятками тысяч файлов, ничего не требуется), для обновления файла метаданных требуется менее 10 секунд, хотя дольше для создания), сохраняет данные в формате обычного текста, а какие метаданные, которые будут "сохранены" или "загружены", настраивается.

Это сработало хорошо для меня. Попробуйте это, если вас не устраивает метастор, git -cache-meta и другие подходы.

Ответ 10

Там некоторая двусмысленность в моей (и других) интерпретациях OP о том, означает ли это время фиксации или что-то еще, но если предположить, что это означает время фиксации, то этот простой однострочный шрифт будет работать в Linux (на основе ответного фрагмента из Dietrich Epp ):

git ls-files | xargs -I{} bash -c 'touch "{}" [email protected]$(git log -n1 --pretty=format:%ct -- "{}")'

Но есть более сложные ответы (включая git hooks), связанные с комментарием к исходному вопросу by cregox.

Ответ 11

В среде Windows я написал небольшой (быстрый и грязный) EXE в Delphi 10.1 Berlin, который собирает все даты файлов в исходном дереве в файл .gitfilattr и может снова применить их к проверенному нашему исходному дереву.

Конечно, я разделяю код в GitHub:

https://github.com/michaschumann/gitfiledates/blob/master/gitFileDates.dpr

Я использую его в своей сборной системе на основе бегунов GitLab.

Ответ 12

С инструментами 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)

Ответ 13

Я надеюсь, вы оцените простоту:

# 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 don't 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