Извлечение старого файла с оригинальными временными метками создания / изменения - PullRequest
67 голосов
/ 01 февраля 2010

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

Ответы [ 12 ]

48 голосов
/ 11 июля 2013

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

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

(Извините, немного забавный ответ на ответ Якуба)

43 голосов
/ 01 февраля 2010

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

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

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
35 голосов
/ 01 февраля 2010

NO , Git просто не хранит такую ​​(мета) информацию , если вы не используете сторонние инструменты, такие как metastore илиГИТ-кэш-мета.Единственная временная метка, которая будет сохранена, - это время, когда был создан патч / изменение (время автора), и время фиксации было создано (время коммиттера).

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

11 голосов
/ 08 ноября 2012

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

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

#!/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, которая в сотни раз быстрее, чем блокировка для каждого файла. Менее 4 секунд для git (24 000 коммитов, 2500 файлов) и менее 1 минуты для ядра Linux (40 000 файлов, 300 000 коммитов)

5 голосов
/ 09 мая 2015

Он сделал это для меня в 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 
3 голосов
/ 09 января 2017

Я уже некоторое время перестреляюсь с метками времени git и file.

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

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

Таким образом, после некоторой перенастройки скрипт может изменять дату создания и модификации файлов 200k примерно за 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.

1 голос
/ 16 марта 2018

В моей (и других) интерпретации ОП есть некоторая двусмысленность относительно того, означает ли это время фиксации или что-то еще, но если предположить, что это означает время фиксации, то эта простая однострочная строка будет работать в linux (основываясь на фрагменте ответа) от Дитриха Эппа):

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

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

1 голос
/ 21 мая 2016

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

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

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

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

1 голос
/ 22 сентября 2015

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

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

0 голосов
/ 23 мая 2019

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

# 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...