25

我在 git 中有两个开发分支,我经常需要在两者之间进行更改。然而,真正令人沮丧的是,每次我在 git 中更改分支时,整个项目都会重新构建,因为某些文件的文件系统时间戳会发生变化。

Ofc,makefile 被配置为将项目构建到两个不同的构建目录中。

有没有办法解决?编译是一个非常漫长和耗时的过程...

编辑:- 这是对该问题的更详细的解释......假设我有一个头文件 Basic.h 包含在许多其他文件中。Basic.h 在分支 1 和分支 2 之间是不同的。

现在假设我已将分支 1 编译为 build_branch1,将分支 2 编译为 build_branch2。假设我目前已签出分支 2。现在我签出分支 1 并更改 File1.cpp 并重新编译。理想情况下,因为自从我上次编译后只有 File1.cpp 发生了变化,所以这是唯一应该重新编译的文件。

但是,由于 Basic.h 由于结帐而更改了时间戳,因此包含 Basic.h 的所有文件都将重新编译。我想避免这种情况。

4

5 回答 5

15

Git 仅更改在分支之间更新的文件。但是,如果您的编译器在任何单个文件被更改的情况下进行完全重建,您始终可以克隆并将不同的分支检出到不同的目录中。这就像:

/your-repo-name.branch1
/your-repo-name.branch2

这需要额外的磁盘空间,但比在一个巨大的 repo 中切换不同的分支要方便得多。

于 2012-04-27T18:52:46.263 回答
11

另一个部分答案:编译器缓存。

当您切换回原始分支并重建时,虽然依赖项说Basic.h必须重建大量依赖的文件,但可以从编译器缓存中提取目标文件。

ccache( http://ccache.samba.org/ ) 仍然需要做一些相当昂贵的工作(处理预处理的翻译单元,因为整个翻译单元都使用哈希键)但它比编译便宜得多。

In some cases ccache can eliminate a compile in the face of a change that does not affect it, like some whitespace changes. For instance if you change a comment in a dependent file (header or source), that does not invalidate the cached object file.

So it can help even if you do a git pull and pick up a new change to Basic.h you haven't seen before.

于 2012-04-27T23:43:51.187 回答
4

如果您知道哪些文件实际上需要编译,并手动进行编译,GNU Make(至少,我不知道其他实现)为您提供了一个标志:-t,它基本上运行在您的 Makefile 上并更改时间戳而不是运行命令。

在使用此标志之前,您仍然需要更新需要更新的文件否则您最终会得到合法过期但看起来已更新的目标文件。有关详细信息,请参阅链接的文档。

您可能也会对该-o选项感兴趣,具体取决于您切换分支时的更改量。

于 2012-04-27T18:53:20.947 回答
3

如果Basic.h分支之间实际上存在差异,那么唯一的解决方法是将其分解为具有更细粒度依赖关系的较小文件,以便在更改时重建更少的内容。

但是假设Basic.h在分支之间实际上是完全相同的,只是git改变了它的时间戳。这是一个错误的触发器,就像 do 一样touch Basic.h,它揭示了基于时间戳的构建系统的局限性。理想情况下,我们希望构建系统在内容更改时重建,而不是在时间戳更改时重建。使用时间戳是因为它们是检测内容更改的廉价替代品。更好的方法是让构建系统保留所有文件的哈希值并检测实际修改,而不考虑时间戳。这也解决了诸如“检测到时钟偏差;您的构建可能不完整”之类的问题。

你不会从 Make 中得到这种构建系统。但是您可能可以针对某些文件处理它的某些方面。例如,您可以编写 Make 规则,使您的目标文件不直接依赖于,Basic.h而是依赖于Basic.h.sha,这是一个标记文件。现在,里面有什么Basic.h.sha?此文件包含 SHA256 哈希Basic.h

每次运行 Make 时,Makefile 中的逻辑都会计算哈希Basic.h并将其与存储在Basic.h.sha. 如果它们不同,则Basic.h.sha用新的哈希覆盖。因此,它的时间戳被碰撞,触发重建。

BASIC_H_SHA := $(shell sha256sum Basic.h)
BASIC_H_SHA_OLD := $(shell cat Basic.h.sha)

ifneq ($(BASIC_H_SHA),$(BASIC_H_SHA_OLD))
$(info Basic.h has changed!)
DUMMY := $(shell echo "$(BASIC_H_SHA)" > Basic.h.sha)
endif

我已经按照这些思路实现了逻辑,以使模块依赖于它们各自的CFLAGS. 基本上,我们可以将任何内容的更改转换为时间戳文件,该文件控制构建的内容。

于 2012-04-27T21:55:50.803 回答
2

没有很好的方法可以保留时间戳并且不会在您的构建环境中遇到麻烦。使用 git clone / git checkout branchB 创建第二个工作目录,用于构建和使用分支 B。不要同时构建你的 Makefile,让每个都构建到自己的构建目录中。

于 2012-04-27T18:54:44.243 回答