使用原始创建/修改时间戳检出旧文件

Scu*_*cud 72 git

有没有办法知道或获得原始的创建/修改时间戳?谢谢.

B T*_*B T 49

是的,Metastore或git-cache-meta 可以存储这样的(元)信息!Git本身,没有第三方工具,不能.Metastoregit-cache-meta可以存储文件的任何文件元数据.

这是设计,因为metaore或git-cache-meta旨在用于此目的,以及支持备份实用程序和同步工具.

(对不起,只是对Jakub的回答有点乐趣)

  • 你甚至模仿他的全部帽子!如果你也使用粗体,我相信你会得到更多的赞成.;-) (6认同)
  • 可以做!; )让upvotes滚滚而来 (2认同)
  • 所以我有点恼火,主要是因为这两个工具(经过一些深入研究后)在 macOS 上以惊人的方式丢球。它们在 Linux 之外是完全不可移植的。git-cache-meta 依赖于 GNU `find` 的 `-printf` 扩展,而且我几乎可以肯定 Metastore(作为一个 C 项目)在使可移植性方面做得更多。很不幸。如果我发现这种情况发生了变化,我会在这里发帖。 (2认同)

Die*_*Epp 43

我相信Git数据库中记录的唯一时间戳是作者和提交时间戳.我没有看到Git修改文件的时间戳以匹配最近提交的选项,并且这不是默认行为(因为如果是,Makefile将无法正常工作).

您可以编写一个脚本来将文件的修改日期设置为最近提交的时间.它可能看起来像这样:

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

  • 围绕Make设计VCS是短视的.我认为这是Git的错.所以它确实*没有意义,它不是默认行为.Make文件应该在文件内容上运行,而不是时间戳.散列文件并查看散列是否与您构建的内容相匹配更加强大. (12认同)
  • +1也许它并不适用于所有可能的情况,但它是一个很好的简单答案. (10认同)
  • 此代码段有几个问题:1 - 如果文件名中有空格,则会失败; 2 - 对于超过几千个文件的项目可能会失败; 3 - 任何具有几千次提交的中型项目(即使文件很少),性能绝对是悲惨的 (9认同)
  • 是不是OP的问题如何保留原始文件修改的时间戳,而不是绑定文件的提交时间戳? (5认同)
  • 我同意英国电信和部分评论迪特里希.BT对OP的意思是你的答案并不能真正保留文件的原始时间.相反,它会将其替换为原始结帐时间.不一样......*所以*,我认为他明确表示你的帖子包含事实错误.我指出,我可以看到不存储时间戳的决定来自哪里.我也认为英国电信有点回过头来讨论那个推理.我再次同意英国电信的意见 - 没有充分的理由完全无法做到这一点.每个其他VCS都可以做到. (4认同)
  • @BT:很多人使用 Make,特别是如果您计算间接用户,并且许多其他程序使用时间戳。您是否认为我的帖子包含事实错误,或者您只是将这些评论用作平台来表达您对人们使用的构建系统的个人抱怨? (2认同)
  • @Cawas:问题的措辞是“X可能吗?” 我的回答是“X 不受支持,但如果满足您的需求,您可以执行 Y”。你是对的,正如我在回答中所说,这不是同一件事。 (2认同)
  • @Cawas:这在 SVN 中不起作用:仔细阅读,它正在做我在这里解释的同样的事情。如果您打算在 Mercurial 中使用一个将元数据存储在附加文件中的插件,那么您不妨为 Git 编写一个预提交和后签出挂钩来执行相同的操作。 (2认同)
  • `date -j` 应该做什么?我的`date` (Arch Linux) 中没有这个选项。 (2认同)
  • 我不得不将第二个 TIME 行更改为 `TIME=$(date --date="$TIME" +%Y%m%d%H%M.%S)` 以使其在 Ubuntu 上的 bash 中工作。 (2认同)

Jak*_*ski 37

,Git根本不存储此类(元)信息,除非您使用第三方工具,如metastore或git-cache-meta.存储的唯一时间戳是创建时间补丁/更改(作者时间),以及创建时间提交(提交者时间).

这是设计,因为Git是版本控制系统,而不是备份实用程序或同步工具.

  • 我认为你的答案实际上是"是的!Metastore或git-cache-meta可以为你做到这一点!" 我猜它是失败主义者和乐观主义者之间的区别. (7认同)
  • *“这是设计使然,因为 Git 是版本控制系统,而不是备份实用程序或同步工具。”* 这是一个*不合逻辑的*:忽略元数据(*特别是*日期,与版本密切相关)无关作为 VCS 或备份工具。此外,每个 VCS 与备份工具的功能都有很大的内在重叠:它们都努力保留重要的过去状态。最后,即使是 Git 也不会忽略所有元数据(例如,它跟踪执行位),尽管它是一个 VCS。不过,它仍然是设计所为,只是出于不同的原因:Git 只关注内容。 (4认同)
  • 另外,据我所知,*bazaar* 和 *mercurial* 也是存储元信息的“版本控制系统”。[没有什么错](http://stackoverflow.com/a/13284229/274502) 这样做。 (3认同)

Mes*_*ion 11

这个python脚本可能会有所帮助:对于每个文件,应用修改文件的最新提交的时间戳:

  • 核心功能,带--help,调试消息.可以在工作树中的任何位置运行
  • 成熟的野兽,有很多选择.支持任何存储库布局.

下面是一个非常简单的脚本版本.对于实际使用,我强烈建议使用上面一个更强大的版本:

#!/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
Run Code Online (Sandbox Code Playgroud)

所有版本都会解析单个git whatchanged命令生成的完整日志,这比每个文件的填充速度快数百倍.git(24,000次提交,2,500个文件)不到4秒,linux内核不到1分钟(40,000个文件,300,000次提交)

  • 您的其他 [类似答案](http://stackoverflow.com/a/13284229/274502) 比这个好得多! (2认同)

elu*_*dom 6

这对我来说就是ubuntu(在日期(1)缺少OSX的"-j"标志)

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


Dan*_*Lin 5

Native Git不具备该功能,但可以通过hook脚本或第三方工具来实现。

我试过了metastore。它非常快,但我不喜欢需要安装,并且元数据不以纯文本格式存储。git-cache-meta是我尝试过的一个简单工具,但对于大型存储库来说速度非常慢(对于具有数万个文件的存储库,更新元数据文件需要几分钟),并且可能存在跨平台兼容性问题。setgitperms其他方法也有我不喜欢的缺点。

最后,我为这项工作制作了一个钩子脚本:git-store-meta。它具有非常轻的依赖性(*nix shell、sort、 和perl,这是 Git 所必需的,以及可选的chownchgrptouch),因此对于可以运行 Git 的平台来说不需要安装任何额外的东西,具有理想的性能(对于具有数十个的存储库)数千个文件,更新元数据文件需要 < 10 秒;尽管创建时间更长),以纯文本格式保存数据,并且可以自定义要“保存”或“加载”的元数据。

它对我来说效果很好。如果您对 Metastore、git-cache-meta 和其他方法不满意,请尝试此操作。