Восстановить время модификации файла в Git - PullRequest
41 голосов
/ 16 марта 2010

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

Есть ли способ, которым я могу сказать Git сделать это?

(Например, работая над большим проектом, я внес некоторые изменения в configure.ac, обнаружил, что autotools не работает в моей системе, и хотел восстановить configure.ac до его исходного содержимого и время модификации, чтобы make не пытался обновить configure с моими сломанными автоинструментами.)

Ответы [ 7 ]

17 голосов
/ 25 марта 2014

Восстановить время модификации списка файлов до даты автора их последнего коммита с

gitmtim(){ local f;for f;do touch -d @0`git log --pretty=%at -n1 -- "$f"` "$f"; done;}; gitmtim configure.ac

Однако он не изменит рекурсивные каталоги.

Если вы хотите изменить все рабочее дерево, например, после свежего клона или проверки вы можете попробовать

git log --pretty=%at --name-status --reverse | perl -ane '($x,$f)=@F;next if !$x;$t=$x,next if !defined($f)||$s{$f};$s{$f}=utime($t,$t,$f),next if $x=~/[AM]/;'

NB: я нашел utime во встроенном / clone.c и не получил совпадений.

16 голосов
/ 17 марта 2010

Git этого не делает. Как говорится в вашем часто задаваемом вопросе, он сломался бы, используя инструменты анализа зависимостей на основе временных меток, такие как make .

Подумайте, что произойдет, если старые метки времени будут применены к файлам, извлеченным из "старых" коммитов:

  • make из чистого каталога отлично работает
  • извлечение более старой ветки / тега / коммита (файлы теперь будут иметь метки времени старше, чем продукты сборки!)
  • make теперь ничего не делает, потому что все продукты сборки новее, чем их зависимости

Но, если вы действительно этого хотите, вся информация там есть. Вы можете написать свой собственный инструмент для этого.

В вашем случае просто используйте что-то вроде touch -r configure configure.ac, чтобы сбросить время модификации только configure.ac (или перенести настройку во времени с помощью touch configure).


На самом деле это простое «упражнение для читателя», если вы хотите попрактиковаться в чтении С-кода. Функция, которая изменяет временные метки: utime или utimes. Найдите код для использования этих функций (подсказка: git grep utime в клоне git.git). Если есть некоторые варианты использования, проанализируйте пути кода, чтобы выяснить, когда он обновляет временные метки.

6 голосов
/ 27 марта 2016

Следующий скрипт оболочки должен работать в любой POSIX-совместимой системе, чтобы установить модификацию и получить метку времени доступа ко всем отслеживаемым файлам (и каталогам).Единственный недостаток, который я мог определить, это то, что он довольно медленный, но это хорошо для моего случая использования (установка правильных дат при создании архивов релизов).

rev=HEAD
for f in $(git ls-tree -r -t --full-name --name-only "$rev") ; do
    touch -d $(git log --pretty=format:%cI -1 "$rev" -- "$f") "$f";
done
6 голосов
/ 18 марта 2010

Я считаю, что «правильное» исправление - это сравнение SHA1 каждого входного файла, чтобы увидеть, не изменился ли он с последней сборки.

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

См. http://github.com/alecthegeek/gitbuilding - он основан на чем-то похожем, что я сделал несколько лет назад с SVN

2 голосов
/ 28 августа 2016

Этот инструмент должен сделать свое дело. Он обновляет время mtimes на время автора, а время a на время коммиттера. Это будет работать как касса.

Запустите с DEBUG = 1, чтобы он точно сказал вам, что он делает.

Обратите внимание, что он не использует никаких модулей, только базовый Perl, поэтому должен работать где угодно.

#!/usr/bin/perl

# git-utimes: update file times to last commit on them
# Tom Christiansen <tchrist@perl.com>

use v5.10;      # for pipe open on a list
use strict;
use warnings;
use constant DEBUG => !!$ENV{DEBUG};

my @gitlog = ( 
    qw[git log --name-only], 
    qq[--format=format:"%s" %ct %at], 
    @ARGV,
);

open(GITLOG, "-|", @gitlog)             || die "$0: Cannot open pipe from `@gitlog`: $!\n";

our $Oops = 0;
our %Seen;
$/ = ""; 

while (<GITLOG>) {
    next if /^"Merge branch/;

    s/^"(.*)" //                        || die;
    my $msg = $1; 

    s/^(\d+) (\d+)\n//gm                || die;
    my @times = ($1, $2);               # last one, others are merges

    for my $file (split /\R/) {         # I'll kill you if you put vertical whitespace in our paths
        next if $Seen{$file}++;             
        next if !-f $file;              # no longer here

        printf "atime=%s mtime=%s %s -- %s\n", 
                (map { scalar localtime $_ } @times), 
                $file, $msg,
                                        if DEBUG;

        unless (utime @times, $file) {
            print STDERR "$0: Couldn't reset utimes on $file: $!\n";
            $Oops++;
        }   
    }   

}
exit $Oops;
1 голос
/ 11 декабря 2017

У нас была такая же проблема на работе, и мы успешно использовали сценарий git-store-meta perl от Danny Lin.

Это определенно решило проблему, указанную в вашем вопросе.

0 голосов
/ 24 апреля 2014

Я написал небольшой инструмент, который позволит вам восстановить время изменения файлов в каталоге после слияния или извлечения с помощью Git.

https://bitbucket.org/chabernac/metadatarestore/wiki/Home

Используйте инструмент в качестве ловушки в Git, когда делаете коммит, извлечение или слияние. См. 8.3 Настройка Git - Git Hooks для получения информации о Git hooks. Вы можете найти примеры хитов Git в каталоге .git/hooks вашего проекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...