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

ram*_*ion 47 git

我理解每次更改文件时更新修改时间默认Git行为,但有时我想恢复文件的原始修改时间.

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

(例如,在处理大型项目时,我做了一些更改configure.ac,发现autotools在我的系统上不起作用,并希望将其恢复configure.ac到原始内容和修改时间,这样make就不会尝试configure用我破损的autotools 更新.)

小智 19

将文件列表的修改时间恢复到上次提交的作者日期

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

但它不会递归地更改目录.

如果您想要更改整个工作树,例如在新的克隆或结帐后,您可以尝试

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]/;'
Run Code Online (Sandbox Code Playgroud)

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

  • 回复*“可以尝试”*:它有效吗?在哪里以及如何进行测试? (3认同)

Chr*_*sen 17

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

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

  • 使从一个干净的目录工作正常
  • checkout一个旧的分支/标记/提交(这些文件的时间戳比现在的构建产品早!)
  • make now什么都不做,因为所有构建产品都比它们的依赖项更新

但是,如果你真的想要它,所有信息都在那里.你可以编写自己的工具来做到这一点.

在你的情况下,只需使用类似的东西touch -r configure configure.ac来重置修改时间configure.ac,(或随时带来配置touch configure).


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

  • fwiw,基于make等非强制工具来限制你的版本控制系统并不是设计系统的好方法 (6认同)
  • 我同意,这是一个很好的默认.我只是希望有一个非默认行为的标志或命令.我想现在我会推迟玩git的管道,而只是使用`touch`来完成工作. (5认同)
  • 如果`git archive`可以恢复归档中每个文件的原始文件修改时间,那将是很好的,但不幸的是,它将所有修改时间设置为所选提交的当前时间或时间戳. (4认同)
  • 你错了:`git` repo中没有这些信息.这几天是`git`的一大缺点. (4认同)
  • 关于它如何破坏构建等的所有评论。如果它是一个标志,如果我做了类似 git pull Pictures --restore-times 的事情。- 当我拉下 340 MB 的图片文件时(不关心日期,除了我在更新时将 robocopy 复制到另一个目录......还有 msbuild?不,不是在这种情况下,这些是其它文件..) 。添加标志是有道理的,如果你想使用它,你必须理解它,如果你不这样做并且默认情况下它是关闭的,你很好。将它排除在外的可怕理由:“有人可能会在不了解影响的情况下使用它”.. (3认同)

ste*_*nct 9

以下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
Run Code Online (Sandbox Code Playgroud)

  • 结合这个答案和 @ClementCherlin 的提示,你会得到:``rev=HEAD; for f in $(git ls-tree -r -t --full-name --name-only "$rev") ;do touch -t $(git log --pretty=格式:%cd --date=格式:%Y%m%d%H%m.%S -1 "$rev" -- "$f") "$ F”; 完成``` (3认同)
  • @ClementCherlin 哎呀,你有两个小写的“%m”代表月份——第二个应该是“%M”代表分钟:“--date=format:%Y%m%d%H%M”。 %S` (3认同)
  • 要使其在 macOS 上运行,请使用 `touch -t` 而不是 `touch -d` 和 `--pretty=format:%cd --date=format:%Y%m%d%H%m.%S ` 而不是 `--pretty=format:%cI` (2认同)

Ale*_*eek 6

我相信'正确'的修复方法是实际比较每个输入文件的SHA1,看它是否从上一次构建中改变了.

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

请参阅http://github.com/alecthegeek/gitbuilding - 它基于几年前与SVN类似的内容


And*_*phy 6

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

sudo apt install git-restore-mtime
cd [repo]
git restore-mtime
Run Code Online (Sandbox Code Playgroud)