How Core Git Developers Configure Git
2025-3-1
| 2025-3-9
Words 5483Read Time 14 min
type
status
date
slug
summary
tags
category
icon
password
“哪些 git config 设置现在应该作为默认值?以下是一些即使是核心开发者也会更改的设置。”
在这篇文章中,我将介绍一些可能较为冷门的 Git 配置设置,这些设置是我个人全局启用的,并详细解释它们的作用以及为什么它们应该成为默认设置。
此外,我发现我学到的大部分这些设置,实际上都来自那些每天参与 Git 核心代码开发的人员。
不过,首先,有些人可能并不特别关心 rerere 值的奇妙或复杂的历史。你可能只是想:“直接给我这些设置,让我可以毫不犹豫地把它们放进我的 ~/.gitconfig 文件里。”
好吧,没问题。精彩内容来了:

How do Git core devs configure their Gits?

在我逐一深入探讨这些问题之前,有一个有趣的问题:即使是Git的核心开发者是否也认为某些默认值应该被修改。
这个问题不久前在Git的邮件列表中被提出,说实话,我自己也从这个名为“春季大扫除”的讨论中学到了一些设置。在这个讨论中,Felipe Contreras挑战Git核心团队,要求他们移除所有积累的配置选项和别名,体验一下使用原版Git的感觉。
他挑战列表中的成员,让他们关注哪些设置是他们真正想要修改的,并分享他们认为最重要的设置更改。
结果非常有趣,参与者们基本上达成了一致,提出了一个相当简洁的列表,包括9个配置设置和3个别名,这些设置被认为应该成为新的默认值。让我们先来看看这些提议的配置设置更改。
到目前为止,这些提议的配置设置在实验结束后的三四年里,还没有成为新的默认值。但有趣的是,许多Git开发者自己也发现,如果不启用其中的一些设置,使用Git会变得相当困难。
更有趣的是,你们大多数人可能并不知道这些设置具体是做什么的。
那么,让我们深入探讨一下。这些设置具体有什么作用,为什么你们几乎可以盲目地相信我,并继续启用它们呢?
我将这些设置分为三类:

Clearly Makes Git Better

第一类设置显然在默认情况下让Git变得更好。启用这些设置通常没有任何负面影响。让我们来看看这些设置是什么,以及它们为什么值得启用

列出分支

我在之前的一篇关于 Git 技巧的博客文章中提到过这一点,放在“分支相关”部分。但由于这个问题也出现在“春季大扫除”列表中,我认为大家都同意,默认情况下 Git 分支的列出顺序不应该是按字母顺序排列的。
有两个设置可以帮助改善这一点:branch.sortcolumn.ui。第一个设置会按最近提交日期排序(这样更相关的分支可能会排在前面),而不是按字母顺序。第二个设置会将分支名称以列格式显示,这样你可以在屏幕上看到更多内容。
column.ui 设置还会影响其他列出命令的输出(如 cleanstatustag),但总的来说,我认为它比默认设置更好。
notion image
你也可以按其他条件排序,但我认为按提交日期排序显然是最有用的一个选项。

列出标签

说到列出内容,标签的默认排序方式也相当不合理,因为这几乎不是任何人真正想要的。
通常情况下,如果你按字母顺序列出标签,你会得到类似这样的结果:
没有人希望 0.5.101 排在 0.5.1000 之后,但这就是字母顺序的排序方式。你可以通过以下设置来解决这个问题:
这个设置会按照你期望的方式排序,将点分版本号视为一系列整数值进行排序。相信我,直接启用这个设置吧!

默认分支

这个设置可能稍微有些争议,因为它可能被看作是一个带有政治色彩的问题,但 Git 应该有一个默认分支名称,而不是每次你初始化一个新仓库时都发出警告。
就我个人而言,我并不介意使用 master,而且我的大多数仓库仍然使用这个名称,因为这是以前的默认值。不过,我也完全可以接受 main。所以,无论你想用什么名称,直接设置它就好了。
我觉得最让人无语的是,Git 现在对这个问题表现得非常烦人,而不是直接更新默认值。我希望 Git 能在这方面更有品味一些,但他们没有做到,所以你应该直接设置一个你认为合理的名称。不过,随便吧。

更好的差异比较

关于 Git 的差异比较算法(diff algorithms),其实可以写一整篇博客文章来详细讨论,但简而言之,默认情况下 Git 使用一种古老、快速且相当可靠的差异比较算法,称为“Myers diff”。
为了让你了解“古老”是什么意思,这个算法最早发表于 1986 年的一篇论文中,所以它现在已经有近 40 年的历史了。如果你像我一样年纪不小,或许我可以给你一些童年视角来理解这意味着什么。那一年上映的电影包括《三个阿米哥》、《美国鼠谭》和第一部《高地人》。
无论如何,自那时以来已经有了一些进展(当然也有一些权衡),你可能会惊讶地发现,Git 实际上内置了 4 种差异比较算法:myersminimalpatience 和 histogram
几乎可以肯定的是,你应该使用的是 histogram 算法(它是 patience 算法的改进版本),而不是默认的 myers。你可以通过以下方式全局更改它:
以下是一个简单的代码移动示例,展示了 myers 和 histogram 的差异,让你感受一下 histogram 算法的智能之处:
假设我们将一个 CSS 类移动到一个类似的类下面,并稍作修改,然后使用默认的 myers 算法运行 git diff。我们可能会得到类似这样的结果:

示例:myers 算法的输出


示例:histogram 算法的输出


为什么 histogram 更好?

  • 更智能的匹配histogram 算法能够更好地识别代码的移动和修改,而不是简单地逐行比较。
  • 更清晰的输出:它减少了不必要的差异显示,让你更容易理解代码的实际变化。

更清晰的差异显示

从上面的例子可以看出,histogram 算法让代码的变化更加清晰明了。
就在去年,Elijah(我们 Git Merge 活动的知名人物)建议将 histogrampatience 作为更好的默认算法,这与 Felipe 在“春季大扫除”中的建议一致。然而,实际上这个改动可能不会很快通过 Git 核心团队的审查。
除了这个大的改动,你还可以对 git diff 进行一些小的调整:
其中,colorMoved 也在“春季大扫除”的建议列表中,因此它也应该成为默认设置的一部分。
以下是一个启用 colorMoved 后的代码移动示例:

示例:启用 colorMoved 后的差异显示


这些设置的作用

  1. diff.colorMoved = plain
      • 作用:为移动的代码块添加颜色标记,使其更容易识别。
      • 为什么启用它:它可以帮助你更直观地看到代码的移动,而不是仅仅显示删除和添加。
  1. diff.mnemonicPrefix = true
      • 作用:在差异输出中使用更有意义的符号前缀(例如 i/ 表示索引,w/ 表示工作目录)。
      • 为什么启用它:它让差异输出的上下文更加清晰,尤其是在复杂的 Git 操作中。
  1. diff.renames = true
      • 作用:自动检测文件重命名,并在差异中显示。
      • 为什么启用它:它避免了将文件重命名误判为删除和添加,让差异输出更准确。

更好的推送体验

从 Git 早期开始,正确设置跟踪分支(tracking branches)一直是一个让我感到困惑和沮丧的问题。当我推送时,它会推送到哪里?或者它是否会推送?
有三个更新的推送设置,我认为它们可以显著改善默认体验。第一个设置(push.default simple)自 Git 2.0 以来已成为新的默认值,但其他设置仍然需要显式配置。

1. push.default = simple

  • 作用:这是自 Git 2.0 以来的默认设置,适用于集中式工作流。它会将当前分支推送到远程仓库的同名分支。
  • 为什么启用它:这是一个非常合理的默认设置,避免了不必要的复杂性。

2. push.autoSetupRemote = true

  • 作用:如果当前分支没有设置上游分支(upstream branch),Git 会自动设置它。
  • 为什么启用它:这避免了以下常见错误:
    • 这个错误你可能已经见过无数次了。启用 push.autoSetupRemote 后,Git 会自动为你设置上游分支,省去了手动操作的麻烦。

3. push.followTags = true

  • 作用:每次推送时,Git 会自动推送所有本地存在但远程仓库没有的标签(tags)。
  • 为什么启用它:如果你曾经在本地创建过标签,但忘记推送到远程仓库,这个设置可以确保标签不会被遗漏。这对于团队协作非常重要。

更好的拉取体验

有些人可能会认为,保留一些曾经在服务器上但现在已经删除的分支和标签的本地副本是有用的,但我并不认同这种观点。
我个人认为,Git 的默认行为应该是让你的远程引用尽可能与远程仓库保持一致。删除那些已经不存在的内容,等等。
因此,我认为以下拉取设置应该成为默认值:
这些设置的作用是确保如果服务器上的 blah 分支被删除,我们也会删除本地的 origin/blah 引用,并且自动为我们配置的所有远程仓库执行此操作。这对我来说似乎非常合理。

1. fetch.prune = true

  • 作用:在拉取时,自动删除本地已经不存在于远程仓库的分支引用。
  • 为什么启用它:这可以保持本地仓库的干净,避免积累大量无用的远程分支引用。

2. fetch.pruneTags = true

  • 作用:在拉取时,自动删除本地已经不存在于远程仓库的标签引用。
  • 为什么启用它:与 fetch.prune 类似,这可以确保本地标签与远程仓库保持一致。

3. fetch.all = true

  • 作用:在拉取时,自动对所有配置的远程仓库执行操作,而不仅仅是默认的远程仓库。
  • 为什么启用它:如果你有多个远程仓库,这个设置可以确保你一次性拉取所有远程仓库的更新,而不是逐个操作。

为什么不试试呢?

接下来这组设置通常是无害的,偶尔还会很有帮助。
我不确定是否一定要更改这些默认设置,但我也认为它们不会对任何人造成伤害,而且在许多情况下会更有用,所以我把它们列入了我的清单。

1. 自动纠正提示

正如我在之前的文章中详细解释的那样,Git 有一个非常不错的功能:如果你在输入命令时打错了字,它会猜测你的意图并尝试运行它。
默认情况下,Git 不会这样做。而我更喜欢让它猜测并提示你。
如果你想详细了解这个设置的背景、原理和历史,我正好有一篇文章适合你。

重用已记录的冲突解决方案

这个设置只有在你在反复进行有冲突的变基(rebase)时才有用。虽然这种情况并不常见,但即使启用后从未使用,也不会有什么问题。
  • rerere.enabled:确保 Git 记录变基冲突前后的状态。
  • rerere.autoupdate:如果再次遇到相同的冲突,Git 会自动重新应用之前记录的解决方案。
我之前在一篇文章中详细讨论过这个功能,所以这里就不再赘述了。

全局忽略文件

这听起来可能有点傻,但既然有一个 ~/.gitconfig 文件用于存储全局配置,那么如果有一个 ~/.gitignore 文件用于存储全局忽略规则,那会非常方便。以下设置可以实现这一点:
实际上,这个设置有点多余,因为 Git 已经会在以下两个位置查找全局忽略规则:~/git/ignore~/.config/git/ignore。但由于这些路径有点隐蔽,我觉得使用更直观的路径(如 ~/.gitignore)会更方便。

更友好的变基(Rebase)体验

这部分主要与你在修复和压缩提交(squashing commits)时的使用场景有关。如果你不知道这是什么,请查看我们之前关于自动压缩提交(autosquashing)的博客文章。
不过,如果你经常(或偶尔)进行压缩提交和变基操作,这些设置会对你有所帮助,而且肯定不会有什么负面影响。
  • rebase.autoSquash = true:自动将标记为 fixup!squash! 的提交合并到目标提交中。
  • rebase.autoStash = true:在变基时自动暂存工作目录的更改,并在变基完成后重新应用它们。
  • rebase.updateRefs = true:在变基时自动更新相关的引用(例如分支栈中的其他分支),确保它们也被移动到正确的位置。
说实话,updateRefs 设置几乎应该成为默认值。它只是确保在变基时,分支栈中的相关引用也会被正确移动。
如果你想了解更多关于如何使用 fixupautosquashupdateRefs 的内容,最简单的方法是观看我在这里的演讲视频(几分钟即可):

个人偏好

接下来的这组设置基于个人偏好,但很多人可能并不知道它们的存在,而许多人可能会觉得它们很有用。它们在我的 TLDR 设置中被注释掉了。

更好的合并冲突显示

虽然这个问题在“春季大扫除”讨论中被提出,认为它可能应该成为新的默认设置,但我不确定你们所有人都会同意。
当你在 Git 中遇到合并冲突时,除了插入来自左侧和右侧的冲突标记外,你还可以要求 Git 插入冲突的基础版本(base)。有时这非常有用,但有些人可能会觉得它很烦人。
在 Git 邮件列表中,曾经有过讨论是否将其设为默认值。实际上,GitButler 在处理合并冲突标记时使用了 diff3 策略,但说实话,并不是所有人都喜欢它。
以下是一个简单的合并冲突标记示例,你可能在合并或变基时在文件中看到:
notion image
With the merge.conflictStyle zdiff3 setting, it would look like this:
notion image
本质上,除了显示你如何修改代码块(<<<<<<)和对方如何修改代码块(>>>>>>)的部分外,Git 还会添加一个 ||||||| 部分,显示在你们双方修改之前,这段代码块的样子。
这个额外的上下文(即在你和对方修改之前,这段代码的样子)有时会非常有用,但通常它只是增加了更多的信息量,可能会让人感到困惑。
实际上,是否启用这个功能取决于你是否喜欢更多的上下文信息。

更好的拉取体验

关于合并(merge)与变基(rebase)的争论可能永远无法达成一致,但大多数人都有自己的偏好。不过,你可能不知道你可以设置 git pull 的默认行为,使其只执行其中一种操作。不再需要 git pull --rebase,你可以将其设为默认行为:
这是一个个人选择,但因为我最近已经转向了“只使用变基”的阵营,所以这个设置实际上已经存在于我的配置中。

启用文件系统监视器(fsmonitor)

这个功能主要适用于较大的仓库,也许你并不希望文件系统监视器到处运行,但如果你有较大的工作目录,它可以显著加快诸如 git status 等操作的速度。
也许它不应该成为默认设置,但它并没有什么坏处,而且可以带来很大的性能提升。也许 git clone 应该询问你是否要启用它。无论如何,这是一个可供你选择的选项。
这些设置会运行一个文件系统监视器(每个仓库一个),它会注意到文件的更改并更新缓存。这样,git status 就不需要遍历每个文件并通过大量的 mtime 系统调用来检查是否有更改,而是可以直接查看一个简单的文件更改日志。

 

最后的一些想法

希望这篇文章能成为一个有用的参考,也许你学到了一些新的 Git 配置技巧,其中一些几乎应该已经成为默认设置,而这在 Git 邮件列表社区中甚至不是一个有争议的话题。
当然,还有很多其他方法可以优化你的 Git 体验(例如别名、酷炫的外部分页器和差异比较工具等),但我认为最好还是专注于全局有用且相对简单的原生 Git 设置。
希望你喜欢这篇文章,下次见!
  • git
  • Distributed Systems Programming Has Stalled理解和防止并发系统中的死锁Understanding And Preventing Deadlocks In Concurrent Systems
    Loading...