“git checkout” - 如何在切换分支时保留时间戳?

14

我经常在不同分支之间切换。我有一个脚本,将checkout的内容推送到“运行”环境中,在那里我可以看到代码的运行并进行测试(它是一个Web应用程序)。这个推送脚本的核心是使用rsync,它使用时间戳来检测应该传输哪些文件。因为“git-checkout”似乎将文件的时间戳设置为当前时间,所以rsync报告所有文件都被推送了,只是因为时间戳会更新。

如何让“git-checkout”在切换分支时保留时间戳,以便rsync仅报告内容更改?

我不想使用rsync的校验和选项,因为它非常慢。


你真的关心性能吗?还是只关心rsync列出具有内容更改的文件? - Emil Sit
@EmilSit 我确实希望rsync快速运行,这样它就不会妨碍我的工作,而且我希望报告中不会出现对我来说不是“真正”的更改(即没有实际内容更改)。 - Dale Forester
您目前在使用rsync时感觉速度较慢吗? - Emil Sit
不,rsync很好,如果我尝试校验和模式,它会变得很慢。 - Dale Forester
请注意,使用 Git 2.2.2+ 版本时,您的用例现在应该可以更好地工作(截至2015年1月)。请参阅我的答案 - VonC
规范问题的候选者:*Subversion的"use-commit-times"在Git中有什么等效物?(2009)和检出具有原始创建/修改时间戳的旧文件*(2010)。Mercurial有时间戳扩展(尽管这并没有太大帮助)。 - Peter Mortensen
3个回答

10

关于git checkout和时间戳的情况,Git 2.2.2+(2015年1月)应该会更好。

当执行git checkout时,已经是最新的文件的时间戳不应再移动。

请参见Jeff King (peff)commit c5326bd

checkout $tree: 不要丢弃未更改的索引条目

当我们执行“git checkout $tree”时,我们会将路径从$tree拉取到索引中,然后将结果条目检出到工作树中。然而,我们的第一步方法相当笨重,它会覆盖整个现有的索引条目,即使内容相同也是如此。这意味着我们失去了状态信息,导致checkout_entry稍后重新写入具有相同内容的整个文件。因此,让我们看看是否已经在索引中拥有相同的条目,如果是,则将其保留在原地,这样可以让checkout_entry做正确的事情。我们的测试涵盖了两种有趣的情况:1.确保没有更改的文件不会被重写;2.确保我们更新了索引中未更改但具有工作树更改的文件(与$tree相比)。我们保留旧的索引条目,checkout_entry能够意识到我们的状态信息已过期。

7
git checkout 会更新时间戳的原因是,几乎所有源代码的构建系统都依赖于时间戳来确定目标是否需要重新构建。如果git checkout在文件更新时不更新时间戳,则这些构建系统将无法正确进行增量构建。实际上,git checkout只应更新已更改的文件的时间戳。

rsync 在更新时间戳时应该是高效的,并且如果仅元数据已更改,则不传输任何数据。您可以通过 "speedup" 来验证这一点。您还可以使用 -i 标志请求最近版本的 rsync 列出更改项。您可以通过省略 -a-t 来告诉 rsync 不要使用时间戳(仅使用校验和),但是不推荐这样做,根据 rsync(1) 手册。


我想我会把这个作为答案,因为它解释了git的行为。我想在git中没有真正的解决方案适用于我的特定用例。谢谢。 - Dale Forester
如果“git checkout”有一个选项可以不触及时间戳,那就太好了,如果构建系统是唯一的原因。例如,我有一个脚本来按最后修改日期对“git status”的输出进行排序,在切换分支后这是无意义的。 - blueyed
1
嗨!我有一个类似的情况。由于某种原因,git会触及所有文件。而且,我没有使用-a-t标志,但是rsync似乎仍然认为文件已更改。我不能使用--size-only,因为即使字母发生了变化,我也需要更新文件,所以如果rsync只比较校验和,或者git保留原始修改时间,那就太完美了。有什么想法吗? - XedinUnknown
我编写了一个辅助脚本,根据最后提交的时间戳来更新时间戳: https://gist.github.com/tstone2077/86529356dd120eb0e51f使用此脚本,您可以运行以下命令: git checkout && git settimes - tstone2077
事实上,git checkout 只应更新已更改的文件的时间戳。我不太明白你在这里的意思,但是为了扩展原帖的问题:如果我在一个分支上有一个名为 foo.c 的文件,然后切换到另一个也包含 foo.c 的分支,foo.c 的最后修改时间将更改为当前时间。一分钟后,我再次切换回原始分支,foo.c 再次更新为当前时间。两个分支中都没有任何更改,为什么会更新?这变得无法跟踪文件上次更改的时间。 - Motorhead

1

看起来Git这样做的唯一原因是在DVCS环境中,您可能会使用旧的时间戳文件来更新新的时间戳文件并引起构建问题。我认为这不好,因为我们很少使用旧的时间戳文件来更新新的时间戳文件。

  1. 我认为可以以聪明的方式处理这个问题:当用文件B更新文件A时,

    file_timestamp = (timestamp(B) > timestamp(A)) ? timestamp(B) : timestamp(CURRENT);

  2. 或者,这可以设计为可配置选项。


那种行为会破坏大多数构建系统,因为一个依赖文件的时间戳可能比timestamp1和timestamp2都晚,这意味着它不会被重新构建 - 这将破坏构建过程。 - Dietrich Epp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接