在Git中恢复文件的修改时间

时间:2010-03-16 20:51:31

标签: git

我理解default Git behaviour of updating the modification time every time it changes a file,但有时我想恢复文件的原始修改时间。

有没有办法告诉Git这样做?

(例如,在处理大型项目时,我对configure.ac进行了一些更改,发现autotools不能在我的系统上运行,并希望将configure.ac恢复为其原始内容和修改时间,以便make不会尝试使用我的自动工具更新configure。)

9 个答案:

答案 0 :(得分:17)

使用

将文件列表的修改时间恢复到上次提交的作者日期
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]/;'

注意:我在builtin / clone.c中使用了utime并没有匹配。

答案 1 :(得分:16)

Git没有这样做。就像链接的常见问题解答说的那样,它会破坏使用基于时间戳的依赖性分析工具,如 make

想想如果将旧时间戳应用于从“旧”提交中检出的文件会发生什么:

    来自干净目录的
  • make 正常工作
  • 结帐较旧的分支/标记/提交(文件的时间戳现在早于构建产品!)
  • make 现在什么都不做,因为所有构建产品都比它们的依赖项更新

但是,如果你真的想要它,所有信息都在那里。您可以编写自己的工具来完成它。

在您的情况下,只需使用touch -r configure configure.ac之类的内容重置仅configure.ac的修改时间,(或使用touch configure及时配置前提。)


如果你想练习阅读C代码,这实际上是一个简单的“读者练习”。更改时间戳的功能是utimeutimes。搜索代码以获取这些函数的使用(提示:git.git clone中的git grep utime)。如果有一些用途,请分析代码路径以找出更新时间戳的时间。

答案 2 :(得分:6)

我认为'正确'修复是实际比较每个输入文件的SHA1,看它是否从上一次构建中更改。

这是很多工作,但是我已经开始尝试创建一个概念证明(仍处于早期阶段)。除了确定正确的构建步骤之外,它还旨在为以后的取证创建输入文件的审核列表。

请参阅http://github.com/alecthegeek/gitbuilding - 这是基于我几年前与SVN所做的类似的事情

答案 3 :(得分:6)

以下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

答案 4 :(得分:2)

这个工具应该可以解决问题。它将mtimes更新为作者时间和atimes到提交者时间。它可以作为结账钩子。

使用DEBUG = 1运行,让它准确地告诉你它正在做什么。

另请注意,它不使用任何模块,只使用基本的perl,因此应该在任何地方运行。

str_extract(as.character(dt), "(?<=\\s)(\\d{1,2})(?=:)")
# [1] "11" "9" 

答案 5 :(得分:1)

我们在工作中遇到了同样的问题,并成功使用了Danny Lin的git-store-meta perl脚本。

它肯定解决了你问题中指出的问题。

答案 6 :(得分:1)

https://github.com/MestreLion/git-tools

sudo apt install git-restore-mtime
cd [repo]
git restore-mtime

答案 7 :(得分:1)

在这里给我两分钱。
它需要@stefanct提出的大部分内容,但是在实现类似脚本时,我只是添加了并行功能。

对于我的情况(1000个文件),我从60秒缩短到15秒来并行执行操作。

#!/bin/bash

change_date() {
      local dd=`git log -1 HEAD --pretty="%ci" -- $1`
      if [ -z "$dd" ];
      then echo "$1 is not versionned";
      else touch -d "$dd" $1;
      fi
}
#list_of_files = find .
list_of_files=`git ls-tree -r -t --full-name --name-only HEAD`

for f in $list_of_files;do
  if test "$(jobs | wc -l)" -ge 16; then
    wait
  fi
  {
    change_date  $f;
  } &
done
wait

您可以通过更改此行来调整允许的并行作业数

test "$(jobs | wc -l)" -ge 16

答案 8 :(得分:-1)

我写了一个小工具,允许你在使用Git进行合并或结账后恢复目录中文件的修改时间。

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

在执行提交,签出或合并时,将该工具用作Git中的钩子。有关Git挂钩的信息,请参阅 8.3 Customizing Git - Git Hooks 。您可以在项目的.git/hooks目录中找到Git挂钩的示例。