在 Git 中恢复文件的修改时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2458042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Restore a file's modification time in Git
提问by rampion
I understand the default Git behaviour of updating the modification time every time it changes a file, but there are times when I want to restore a file's original modification time.
我了解每次更改文件时更新修改时间的默认 Git 行为,但有时我想恢复文件的原始修改时间。
Is there a way I can tell Git to do this?
有没有办法告诉 Git 这样做?
(As an example, when working on a large project, I made some changes to configure.ac
, found out that autotools doesn't work on my system, and wanted to restore configure.ac
's to its original contents and modification time so that make
doesn't try to update configure
with my broken autotools.)
(举个例子,在做一个大项目时,我对 进行了一些更改configure.ac
,发现 autotools 在我的系统上不起作用,并希望将configure.ac
's恢复到其原始内容和修改时间,这样make
就不会尝试configure
用我坏掉的自动工具更新。)
采纳答案by Chris Johnsen
Git does not do this. Like your linked FAQ says, it would break using timestamp-based dependency analysis tools like make.
Git 不会这样做。就像您链接的常见问题解答所说的那样,使用基于时间戳的依赖项分析工具(如make )会中断。
Think about what would happen if old time stamps were applied to files checked out from ‘old' commits:
想想如果旧时间戳应用于从“旧”提交检出的文件会发生什么:
- makefrom a clean directory works fine
- checkout an older branch/tag/commit (the files would have timestamps older than the build products now!)
- makenow does nothing because all the build products are newer than their dependencies
- 使从一个干净的目录工作正常
- 签出较旧的分支/标记/提交(文件的时间戳将比现在的构建产品更旧!)
- make现在什么都不做,因为所有构建产品都比它们的依赖项更新
But, if you really want it, all the information is there. You could write your own tool to do it.
但是,如果你真的想要它,所有的信息都在那里。你可以编写自己的工具来做到这一点。
In your case, just use something like touch -r configure configure.ac
to reset the modification time of only configure.ac
, (or bring configure forward in time with touch configure
).
在您的情况下,只需使用类似的方法touch -r configure configure.ac
来重置 only 的修改时间configure.ac
,(或及时将配置提前touch configure
)。
Actually this is an easy “exercise for the reader” if you want to practice reading C code. The function that changes timestamps is utime
or utimes
. Search the code for uses of those functions (hint: git grep utime
in a git.git clone). If there are some uses, analyze the code paths to find out when it updates timestamps.
实际上,如果您想练习阅读 C 代码,这是一个简单的“读者练习”。改变时间戳的函数是utime
or utimes
。搜索代码以了解这些函数的用途(提示:git grep utime
在 git.git 克隆中)。如果有一些用途,请分析代码路径以找出它何时更新时间戳。
回答by TallOne
Restore the modificaton time of a list of files to the author date of the their last commit with
将文件列表的修改时间恢复到他们最后一次提交的作者日期
gitmtim(){ local f;for f;do touch -d @0`git log --pretty=%at -n1 -- "$f"` "$f"; done;}; gitmtim configure.ac
It will not change directories recursively, though.
但是,它不会递归更改目录。
If you want to change a whole working tree, e.g. after a fresh clone or checkout, you may try
如果您想更改整个工作树,例如在新的克隆或结帐后,您可以尝试
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: I grepped for utime in builtin/clone.c and got no matches.
注意:我在 builtin/clone.c 中搜索了 utime,但没有匹配项。
回答by stefanct
The following shell script should work on any POSIX-compatible system to set the modification and access timestamp of all tracked files (and directories). The only downside I could determine yet is that it is quite slow but that's fine for my use case (setting the right dates when producing release archives).
以下 shell 脚本应该适用于任何 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
回答by Alec the Geek
I believe the 'proper' fix is to actually compare the SHA1 of each input file to see if it's changed from the last build.
我相信“正确”的修复是实际比较每个输入文件的 SHA1 以查看它是否从上次构建中更改。
This is a lot of work, however I have started a project to try and create a proof of concept (still very early stage). As well as identifying the correct build steps it's also designed to create an audit list of input files for later forensics.
这是很多工作,但是我已经开始了一个项目来尝试创建概念证明(仍处于早期阶段)。除了确定正确的构建步骤外,它还旨在为以后的取证创建输入文件的审计列表。
See http://github.com/alecthegeek/gitbuilding-- it's based on something similar I did a few years ago with SVN
参见http://github.com/alecthegeek/gitbuilding——它基于我几年前用 SVN 做的类似的事情
回答by tchrist
This tool should do the trick. It updates mtimes to the author time and the atimes to the committer time. It would work as a checkout hook.
这个工具应该可以解决问题。它将 mtimes 更新为作者时间,将 atimes 更新为提交者时间。它可以用作结帐挂钩。
Run with DEBUG=1 to get it to tell you exactly what it's doing.
以 DEBUG=1 运行,让它准确地告诉你它在做什么。
Notice also that it uses no modules, just basic perl, so should run anywhere.
还要注意它不使用模块,只使用基本的 perl,所以应该可以在任何地方运行。
#!/usr/bin/perl
# git-utimes: update file times to last commit on them
# Tom Christiansen <[email protected]>
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 "##代码##: Cannot open pipe from `@gitlog`: $!\n";
our $Oops = 0;
our %Seen;
$/ = "";
while (<GITLOG>) {
next if /^"Merge branch/;
s/^"(.*)" // || die;
my $msg = ;
s/^(\d+) (\d+)\n//gm || die;
my @times = (, ); # 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 "##代码##: Couldn't reset utimes on $file: $!\n";
$Oops++;
}
}
}
exit $Oops;
回答by gsl
We had the same issue at work, and have been using successfully the git-store-metaperl script by Danny Lin.
我们在工作中遇到了同样的问题,并且已经成功地使用了 Danny Lin的git-store-metaperl 脚本。
It definitely solved the problem indicated in your question.
它绝对解决了您问题中指出的问题。
回答by Guy Chauliac
I wrote a little tool that will allow you to restore the modification time of the files in a directory after doing a merge or checkout with Git.
我写了一个小工具,可以让你在使用 Git 进行合并或检出后恢复目录中文件的修改时间。
https://bitbucket.org/chabernac/metadatarestore/wiki/Home
https://bitbucket.org/chabernac/metadatarestore/wiki/Home
Use the tool as a hook in Git when doing a commit, checkout or merge. See 8.3 Customizing Git - Git Hooksfor information about Git hooks. You can find examples of Git hooks in the .git/hooks
directory of your project.
在执行提交、签出或合并时,将该工具用作 Git 中的挂钩。有关Git 钩子的信息,请参阅8.3 自定义 Git -Git 钩子。您可以在.git/hooks
项目目录中找到 Git 钩子的示例。