Git 2.28中的亮点

2020-07-28 03:04:18

开源的Git项目刚刚发布了Git2.28,其中包含来自超过58个贡献者的特性和错误修复,其中13个是新的。我们上一次关注Git的最新消息是在2.26发布的时候。下面我们来看一下从那时起引入的一些最有趣的功能和更改。

当您使用git init从头开始初始化一个新的Git存储库时,Git总是创建一个名称为master的初始第一个分支。在Git2.28中,引入了一个新的配置选项init.defaultBranch来取代硬编码术语。(有关此更改的更多背景信息,请参阅软件自由保护协会的这份声明。)。

从Git2.28开始,git init在新存储库中创建第一个分支时将改为查看init.defaultBranch的值。如果该值未设置,则init.defaultBranch默认为master。在这里,重要的是要注意以下几点:

此配置变量可由用户设置,覆盖默认值非常简单,如下所示:

此配置变量仅影响新存储库,不会导致重命名现有项目中的分支。Git克隆还将继续尊重您从中克隆的存储库的头部,因此在维护人员启动分支名称更改之前,您不会看到分支名称的更改。

这一更改支持许多社区,无论是在GitHub上还是在更广泛的Git社区中,这些社区都在考虑将其存储库的默认分支名称从master重命名。

要了解有关GitHub正在进行的补充更改的更多信息,请参见GitHub/Renaming。GitLab和Bitbucket也在进行类似的改变。

在Git2.27中,提交图文件格式被扩展为存储更改路径的Bloom过滤器。这一切意味着什么?从某种意义上说,这些新信息可以帮助Git更快地在历史中找到触及给定路径的点(例如,git log--<;path>;,或git故障)。Git2.28利用这些优化提供了一些可观的性能改进。

在我们开始讨论所有这些之前,无论您是刚接触这个概念,还是熟悉它们,通过提交图来回顾一下都是值得的。(如果您很熟悉,并且想要深入了解,请查看这篇博客文章,解释所有有趣的技术细节)。最简单地说,提交图文件存储有关提交的信息。本质上,提交图充当有关提交的常用访问信息的高速缓存:它们的父对象是谁,它们的根树是什么,诸如此类的东西。它还存储计算出的信息,如提交的世代号和更改路径的Bloom过滤器(稍后将详细介绍)。

为什么要存储所有这些信息?要理解这个问题的答案,粗略了解Git如何存储对象是有帮助的。Git以两种方式之一存储对象:一种是松散对象(在这种情况下,对象的内容存储在磁盘上该对象唯一的单个文件中),另一种是打包对象(在这种情况下,对象是从*.pack文件中的压缩格式组合而成的)。无论以哪种方式存储提交,我们都必须先对其进行解析和解压缩,然后才能访问其字段,如“根树”和“父级”。

使用提交图文件,所有这些信息都是即时的:对于给定的提交C,Git确切知道在提交图文件中查找我们存储的所有字段的位置,并且可以立即读取它们,不需要解压缩或拼接。这可以减少您通常的Git操作本身的一些时间,但是提交图真正闪耀的地方是它存储的计算数据。

代号是一种可达性指数,可以帮助Git非常快速地回答可达性和拓扑排序等问题。由于代号在此版本中并不新鲜(尝试快速解释它们会失去更仔细阐述的很多好处),因此我将转而向您推荐新人Hubber Derrick Stolee就此问题撰写的这篇博客文章。

好的,如果您已经走到这一步,那么您已经很好地掌握了提交图是什么,以及它们有什么用处。现在,让我们来看一些有趣的细节。在Git2.27中,提交图文件了解了如何存储更改路径的Bloom过滤器。你会问,什么是更改路径的布隆过滤器?Bloom filter是一个概率集合;也就是说,它是一个项目集合,但是查询该集合中是否存在某些项目x会返回“x肯定不在这个集合中”或“x可能在这个集合中”,但决不会返回“x肯定在这个集合中”。提交图为驻留在提交图中的提交存储这些Bloom过滤器之一,并使用在该提交及其第一个父级之间更改的路径列表填充该Bloom过滤器。

这些Bloom过滤器对许多Git命令的性能都有很大的帮助。一般模式是这样的:如果您有一个计算差异的Git命令(有时开销成比例),那么当Git的Bloom筛选器为感兴趣的路径返回“绝对不”时,通过跳过某些提交的计算,使用Bloom Filters可以计算更少的差异。

以git log--/path/to/file为例。在Git2.27之前,在确定是否显示之前,Git日志必须计算遍历中每个修订的差异(即,差异是否有/path/to/file的任何条目)。在Git2.27和更新版本中,Git可以通过查询每个提交C的更改路径Bloom过滤器并查询/path/to/file来完全跳过计算这些差异。再说一次:如果查询返回“肯定不是”,那么Git知道计算这种差异完全没有意义。

因为计算提交之间的差异可能代价很高(至少,相对于为其生成差异的算法的复杂性而言),减少总体计算的差异数量可以极大地提高性能。

这将生成启用了更改路径布隆过滤器的提交图文件。[1]您应该能够在git log--<;path>;、git log-L、git disput等命令中看到性能改进,以及根据给定的路径规范计算第一父差异的任何其他命令。

既然我们已经讨论了过去几个版本中的几个主要变化,让我们来看一下🔎的更多新特性。

你有没有在寻找改变过某些道路的那部分历史?也许您只想了解修改了某些文件的提交,运行git log--<;path>;就可以很容易地找到这些提交。有时,您可能不仅对哪些提交涉及<;path>;感兴趣,而且还对哪些合并提交将这些提交带入开发主线感兴趣。你有没有发现这些合并很难找到?你不是一个人。在大多数情况下,Git将跳过向您显示与git log--<;path>;的那种合并,因为这些提交本身不会修改<;path>;。现在,您可以使用Git的新的--show-ull标志来修改遍历命令(如git log和git rev-list),从而使这些合并重新回到视图中来。在大多数情况下,Git会跳过向您显示那些与git log--<;path>;的合并,因为这些提交本身不会修改<;path>;。要获得特别丰富的视图,请尝试:

当您在跟踪远程分支时在存储库中运行git Pull时,可能会发生以下四种情况之一:可能没有更改、服务器、客户端或两者都没有更改。只要两个方向都没有变化,解决差异就很简单:当根本没有变化时,就没有什么可做的了。当服务器严格领先于客户端时,客户端会快进到服务器上的状态。但是,当客户端和服务器上都发生更改时:会发生什么情况?这取决于您是否有pul.rebase配置集。如果您这样做了,您的分支将基于您拉入的位置重新建立基础,否则,将执行合并。这些合并可能会扰乱您的历史记录,如果不从头开始您的拉取,则很难退出。Git2.28现在警告您这种情况(具体地说,如果没有设置pul.rebase,并且您没有显式指定--[no-]rebase作为git Pull的参数)。

Git现在包括一个GitHub操作工作流,您可以使用它在各种平台和编译器上运行Git自己的集成测试。您不需要额外的工作:如果您在GitHub上有一个git/git分支,那么每次推送都将通过一系列必要的测试来验证您的更改。但是,等等:Git不是使用邮件列表进行开发吗?是的,但现在您可以在git/git存储库上使用GitGitGadget。这意味着您可以打开一个Pull请求,并让GitGitGadget代表您将其发送到邮件列表。因此,如果您更愿意像这样为Git贡献内容,而不是手动撰写电子邮件,那么您现在可以使用GitHub从头到尾为Git贡献内容。

另一方面,如果您不介意发送一两封电子邮件,当您通过运行git bugreport遇到bug时,现在与Git邮件列表进行交互要容易得多。运行这个新命令将打开$EDITOR,其中包含一种预先填充的问题形式,这些问题在调试问题时会很有用。它还包括一些关于您的系统的有用信息,比如您的CPU体系结构、您正在运行的Git版本等等。完成后,您可以将该文件作为电子邮件正文发送到Git邮件列表,并确保您已经打开了一个有用的错误报告。

我们已经多次讨论过Git的清洁和污点过滤器以及相应的进程过滤器(它在单个进程中模拟多个清洁和污点过滤器)。直到最近,这些筛选器的协议还相对简单:Git提供内容的一端,筛选器生成另一端。在Git 2.27中,通过协议提供更多信息,比如在Git签出的情况下关于要签出的分支的元数据,或者在Git取出的情况下联系的远程的元数据。这个新信息可以用在诸如Git LFS之类的工具中,以便找出联系哪个遥控器以获取额外数据。

最后但并非最不重要的一点是,Git Status也学到了一些新技巧。您可能还记得最近的一篇博客文章,我们讨论了稀疏结账如何缩小您的Monorepo的大小。现在,git状态可以通过告诉您已签出文件的百分比来提醒您何时处于稀疏签出状态。对于git-timpt.sh的粉丝来说,如果您也处于稀疏签出状态,则提示现在将显示为稀疏。

这只是最新发布的几个版本中的一些更改示例。有关更多信息,请查看Git存储库中2.27和2.28的发行说明或任何以前的版本。

[1]:请注意,由于Bloom过滤器不是自动持久化的(也就是说,您必须在每次后续写入时显式传递更改过的路径),因此最好禁用自动生成提交图的配置,如fetch.writeCommittee Graph和gc.writeCommittee Graph。