开源的Git项目刚刚发布了Git2.29版本,包含了来自89个贡献者的功能和错误修复,其中24个是新的。上次我们追上你的时候,Git 2.28刚刚发布。再过一个版本,让我们来看看自那以后发生的最有趣的特性和变化。
Git2.29包含对使用内容的SHA-256散列(而不是使用SHA-1)编写存储库对象的试验性支持。
这一切意味着什么?为了解释,让我们从头说起。
当您将文件添加到存储库时,Git会将其内容复制到其本地数据库中的BLOB对象中,并创建引用BLOB的树状对象。同样,当您运行git Commit时,这将创建一个引用表示提交状态的树的提交树对象。这些对象如何“引用”彼此,在与Git交互时如何识别它们?答案是,基于其内容的散列,每个对象都被赋予一个唯一的名称,称为其唯一的对象ID。Git使用SHA-1作为其选择的散列算法,并依赖于不同对象的对象ID是唯一的。
回到这篇博客文章中,我们估计,即使你有500万程序员每秒编写一个提交,在太阳吞噬地球之前,你也只有50%的机会意外地产生碰撞,但确实存在一些公开发表的攻击,它们利用SHA-1的弱点,可以减少产生碰撞所需的工作量,但这些攻击的执行成本仍然高达数万美元,而且还没有发布针对Git的已知示例。
正如我们在之前的博客文章中所说的那样,Git(以及使用它的提供商,如GitHub)检查它散列的每个对象,看看是否有证据表明该对象是冲突对的一部分。这可以防止GitHub同时接受该对中的良性和恶意两部分,因为在任何合理的时间内生成冲突所需的数学技巧都可以被Git检测和拒绝。
即便如此,密码散列中的任何弱点都是不好的征兆。即使Git已经实现了阻止已知攻击执行的检测,也不能保证将来不会发现和使用新的攻击。因此,Git项目一直在准备过渡计划,以开始使用一种新的对象格式,并且没有已知的攻击:SHA-256。
$git--version git version2.29.0$git init--object-format=sha256repo/HOME/ttaylorr/repo/.git/$cd repo$ECHO';您好,sha-256!';>;readme.md$git add readme.md$git Commit-m";readme.md:初始提交";[主(根-提交)6e92961]readme.md:初始提交1个文件已更改,1插入(+)创建模式100644 README.md$git rev-parse head 6e929619da9d82c78dd854dfe237c61cbad9e95148c1849b1f96ada5ee800810
从2.29版开始,Git可以在完全SHA-1或完全SHA-256模式下运行。目前,使用不同对象格式的存储库不可能相互互操作,但计划提供最终的支持。还需要注意的是,在撰写本文时,还没有主要的提供商(包括GitHub)支持托管启用了SHA-256的存储库。
在未来的版本中,Git将通过计算其写入的每个对象的SHA-1和SHA-256散列,并在它们之间存储转换表,从而支持不同对象格式的存储库之间的互操作。这最终将允许使用SHA-256存储其对象的存储库与(充分最新的)SHA-1客户端交互,反之亦然。它还允许转换后的SHA-256存储库让它们对旧SHA-1提交的引用仍然正常工作(例如,如果我编写了一个提交,其消息通过其SHA-1名称引用了以前的提交,那么Git仍然能够遵循该引用,即使在通过查询转换表将存储库转换为使用SHA-256之后也是如此)。
有关Git中SHA-256的更多信息,以及未来发布的一些版本可能是什么样子,您可以阅读Git的过渡计划。
当您运行git Fetch Origin时,来自远程原始数据存储库的所有分支都将提取到您的本地文件引用/远程/原始/原始数据层次结构中。Git如何知道要获取哪些分支,以及将它们放在哪里?
答案是您的配置文件包含每个遥控器的一个或多个“refspecs”(请记住,“ref”是Git对历史上任何命名点的描述:分支、标记等)。当您运行git克隆时,它会设置一个默认refspec,以便在您从原始存储库中提取时使用:
这个refspec告诉Git获取冒号左侧的内容(引用/头/中的所有内容;即所有分支),并将它们写入右侧的层次结构中。左手边的意思是“全部匹配”,右手边的意思是“用匹配的零件替换”。
可以有多个参照等级库,它们可以参照单个参照。例如,此命令指示Git另外从远程获取任何git笔记(a--add参数很重要,这样我们就不会覆盖获取分支的默认refspec):
参考规格也被GIT推送使用。即使你只输入一个git推送原点myBranch,最后的那个myBranch也真的是对refs/head/myBranch:refs/head/myBranch的一种速记。这使您可以表达更复杂的场景。假设您正在添加标签,并希望推送您拥有的所有标签,但您还没有完全准备好分享所有分支的提示。在这里,您可以编写如下内容:
在Git 2.29之前,refspecs只能用来说明您需要选择哪种参照。因此,如果要提取除一个分支之外的所有分支,则必须将它们作为参数逐个列出。当然,这假设您事先知道所有其他引用的名称,因此在实践中应该类似于:
$git ls-Remote Origin';Refs/Heads/*';|grep-v ref-to-exclude|awk';{print$2:$2}';|xargs git获取原点。
要获取除要排除的参考/头/参考之外的所有参考中的参考/头/*,请执行以下操作。是啊,一定有更好的办法。
在Git 2.29中,有:负折射。现在,如果refspec以^开头,则表示要排除哪些引用。因此,您可以改写如下内容,而不是上面的内容:
并达到同样的效果。当存在负refspec时,如果引用与至少一个正refspec匹配并且不匹配任何负refspec,则服务器认为该引用值得发送。负反射的行为完全符合您的预期,但有几个警告:
负参照规范可以包含通配符模式,但不能指定目标。这些无论如何都不会有任何意义(你不会想说^refs/head/foo/*:refs/head/bar/*,这就是说,从字面上来说,“把头从Foo映射到bar,但不要一开始就给我发任何foo/reff”)。要排除通配符refspec,只需编写^refs/head/foo/*。
正折射可以通过对象ID引用单个对象,而负折射不能。
当然,这些负反射在配置值中也同样有效。如果您总是想获取除foo之外的所有分支,只需将其添加到您的配置中即可:
虽然您几乎肯定使用过(或听说过)git日志,但对于git Shorlog可能不一定如此。对于那些没有这样做的人来说,Git Shorlog的行为很像Git日志,不同的是它不是按顺序显示提交,而是按照作者对它们进行分组。
事实上,Git版本说明以版本中所有补丁的简短日志结尾,这些补丁由其作者细分,由Git Short log生成[来源]。在撰写本文时,它们看起来如下所示:
Aaron Lipman(12):t6030:Modiize";git二等分运行";测试版本列表:允许二等分和第一父标志cmd_bisect__helper:延迟解析无签出标志[...]Adrian Moennich(1):CI:修复不一致的缩进Alban Gruin(1):t6300:修复与%(Contents:Size)[...]相关的问题。
在旧版本的Git中,Git Shorlog日志只能按提交作者分组(默认行为),也可以选择按提交者身份分组(使用.git Shorlog-c)。这限制了谁通过提交的作者/提交者获得提交的信用。所以,如果你的项目使用的是“合著者”预告片(就像这个在git/git中提交的预告片一样),那么你的合著者就不走运了:没有办法告诉你git短日志是合著者的群组提交。
…。也就是说,直到Git2.29!在此版本中,Git Shorlog学习了一个新的分组参数-GROUP参数,以指定如何对提交进行分组和分配信用。它使用--group=Author(前面的默认行为)和a--group=commter log(等同于git Shorlog-c),但它还接受参数:--group=trailer:<;field>;。
通过后者,我们可以按合著者对提交进行分组,还可以使用更具创造性的用途。如果您的项目使用的是预告片审阅者,您可以使用git快捷日志查看谁审阅的补丁最多:
$GIT SHORTLOG-NS--GROUP=预告片:审阅-由v2.28.0..。海德-N5 40埃里克·阳光10泰勒·布劳4布莱恩·M·卡尔森2以利亚·纽伦1杰夫·金。
Git Shortlog还允许多个参数--group=<;type>;,在这种情况下,每个分组都会计算一次提交。因此,如果你想看看谁贡献最多,无论这个人是第一作者,还是被列为共同作者,那么你可以写道:
…。使作者和合著者处于平等的地位。除了计数,您还可以使用--format选项找到其他有趣的方式来显示数据。例如:
$GIT SHORTLOG--format=";...在%AS";上帮助%an。--group=预告片:帮助-由v2.28.0..v2.29.0 Chris Torek(3):...在2020-08-12帮助勒内·沙尔夫...在2020-08-12帮助勒内·沙尔夫...在2020-08-12帮助勒内·沙尔夫大卫·阿吉拉尔(1):...帮助孙林在2020-05-07 Denton Liu(1):...在2020-08-21帮助Shourya Shukla Derrick Stolee(2):...帮助Taylor Blau在2020-08。-25...在2020-09-17帮助泰勒·布劳[...]。
Git for-each-ref在Git2.29中学习了一些新技巧。既然它们很多,我们就从这里开始吧:
Git for-each-ref通常输出每个ref的名称、类型和对象ID,但是您可以通过它的“--format”选项找到更多信息。Git 2.29学习了一些新字段,包括内容:Size、主题:Sanitize,以及更一致的元素:短修饰符,以获取缩写的对象ID。最后几个是由从事Git项目的谷歌代码之夏(Google Summer Of Code)学生哈里姆·维尔马(Hariom Verma)贡献的。[来源,来源]。
Git for-each-ref现在可以接受多个不合并的参数和不合并的参数,如果至少一个不合并的参数可以访问,则打印引用,而不能从任何不合并的参数中访问。[来源]。
现在,所有的GIT for-each-ref更新都消失了,让我们继续看一下其他所有的花絮:。
当您的git合并导致合并冲突时,您会看到如下所示的消息(此示例由Elijah Newren提供):Conflicts(Rename/Delete):foo.c DELETED in b01dface...(此示例由Elijah Newren提供):Conflict(Rename/Delete):foo.c DELETED in b01dface...。删除了不必要的东西,并在Head中重新命名。Foo.c左侧树的版本头。
你能说出这条信息是什么意思吗?在2.29之前的Git版本中,这一点是模棱两可的:Git是删除了头部中的内容并重命名了文件,还是将“删除了不必要的内容”作为提交消息的名称?事实证明是后者,但你没有办法知道这一点!
在2.29中,Git现在将COMMIT消息的主题括在括号中,使冲突消息的哪一部分来自COMMIT,哪些部分由Git生成。
这里有一个简单的问题!Git支持名为.merge.renormalize的配置选项。如果你不熟悉Git的近5000行/人git-config的全部内容,这里有一个刷新器:.merge.renormalize会导致Git检出和签入三向合并的每个阶段。如果您正在处理的两个分支之间的行尾发生变化,这可能会很有用。这个配置过去不会被.git checkout-m命令(以及一些相关的调用)拾取,但现在它可以了![来源]。
在Git2.26的亮点中,我们讨论了v2协议,该协议在该版本中成为默认协议。在2.26和2.27之间,发现并修复了这个新协议中的错误(有关详细信息,请参阅4fa3f00abb)。为了安全起见,Git 2.27回到了协议“V0”,以简化过渡,并在Git 2.28中标记了这一功能实验版本。现在我们有一些机会来消除Git 2.28之后的任何挥之不去的错误,协议v2在Git 2.29中被重新启用为默认协议。[来源]。
当试图确定错误的来源时,Git二等分是一个非常方便的工具。您标记一个“好”和“坏”端点,然后Git将引导您在端点之间进行二进制搜索,以找到导致问题的提交。在Git 2.29中,Git二等分学习了一个新的“父级优先”选项来修改在这些端点之间遍历哪些提交。理解此选项的一种方法是想象当通过合并一分为二时会发生什么。在此之前,除了合并提交本身之外,您的一分为二还将包括正在合并的分支上的提交。传递“第一父级”会告诉Git避免将仅在合并中的分支上的提交视为潜在的bug来源。如果您的工作流是这样的:只有主分支上的合并是有趣的停止点(因为您主要通过合并Pull请求来工作,并且每个单独的Pull请求可能都有可能甚至不会构建的正在进行的提交),那么“第一父级”允许您跳过所有这些操作。
Git可选地包括一个远程后端,用于从一个新的MediaWiki实例进行推送和拉取。它通常不受支持,并且在默认情况下不会编译,但最近发现的漏洞可能导致执行任意命令,此版本中已打了补丁。请注意,只有在对不受信任的MediaWiki实例使用mediawiki后端时,您才会受到此漏洞的影响(如果您必须问自己是否受到影响,则很可能不会)。[SOURCE]。
Git使用低级的.git index-pack命令接收一个.git推送命令或处理一个.git获取。在Git2.29中,Git索引包学会了在多核计算机上更高效地工作,这意味着您的所有推送和读取只需升级就可以变得更快。[来源,来源]。
当您创建合并提交时,默认消息类似于“Merge at$upstream”into$DEST“。从历史上看,合并到主分支会省略“Into$DEST”部分。Git 2.29是从dmerge.suppressDest配置中了解到的。此多值配置变量中的任何分支都会导致GIT合并程序省略“INTO$DEST”部分.[来源]。
这只是最新版本更改的一个示例。有关更多信息,请在Git存储库中查看2.29的发行说明,或查看任何以前的版本。