Git 核心开发者都在用的 Git 配置,你知道几个?

在这篇文章里,我会分享一些我个人已在全局启用的、可能相对生僻的Git配置设置,同时解释它们的功能,以及为何它们理应成为默认设置。

此外,我发现自己学到的这些技巧,大多源自那些日常实际参与Git核心代码库开发的人员。

Git 配置

简述

首先,有些人或许并不太在意rerere相关配置那些精彩又复杂的来历。你们可能只想说:“直接把设置给我,让我能无脑复制到~/.gitconfig文件里就行。”

好吧,这很公平。以下是有趣的部分:

# clearly makes git better
[column]
     ui = auto
[branch]
    sort = -committerdate
[tag]        
    sort = version:refname
[init]       
    defaultBranch = main
[diff]       
    algorithm = histogram        
    colorMoved = plain        
    mnemonicPrefix = true        
    renames = true
[push]        
    default = simple        
    autoSetupRemote = true        
    followTags = true[fetch]        
    prune = true        
    pruneTags = true        
    all = true

# why the hell not?

[help]       
    autocorrect = prompt
[commit]        
    verbose = true
[rerere]        
    enabled = true        
    autoupdate = true
[core]       
    excludesfile = ~/.gitignore
[rebase]       
    autoSquash = true       
    autoStash = true        
    updateRefs = true

# a matter of taste (uncomment if you dare)
[core]        
    # fsmonitor = true        
    # untrackedCache = true
[merge]        
    # (just 'diff3' if git version < 2.3)       
    # conflictstyle = zdiff3 
[pull]        
    # rebase = true

复制粘贴吧,朋友们。

Git核心开发者是如何配置Git的?

在深入探讨各项内容之前,有个很有意思的问题:就连Git核心开发者,是否也觉得某些默认值应当有所改变呢?

这个问题此前在Git邮件列表中被提了出来。说实话,我自己学到的部分设置,就源自这个名为“春季大扫除”的帖子。在帖子里,Felipe Contreras向Git核心团队发起挑战,让大家去除所有积累下来的配置选项和别名,去体验一下使用原生、开箱即用的Git是怎样一种感受。

他请邮件列表的成员留意那些自己真正想要更改的设置,并将看起来最为重要的顶级设置更改分享到列表中。结果十分有趣,形成了一个相当简洁的列表,包含9项配置设置和3个别名,参与实验的人员基本一致认为,这些设置理应成为新的默认设置。下面,就让我们来看看这些被提议的配置更改。

merge.conflictstyle = zdiff3
rebase.autosquash = true
rebase.autostash = true 
commit.verbose = true
diff.colorMoved = true
diff.algorithm = histogram
grep.patternType = perl
feature.experimental = true
branch.sort = committerdate

尽管在这项实验结束后的三四年间,这些设置没有一项成为新的默认配置,但有意思的是,不少Git开发者要是不开启其中几项功能,都觉得Git不太好用。

更有意思的是,你们当中的大多数人,可能对这些配置全然不知。

那么,接下来让我们深入探究一番。这些配置有什么作用,为什么你几乎可以毫无保留地信任我,进而启用它们呢?

我把这些设置归为三类:

  • 让Git用起来更清晰明了
  • 值得一试
  • 属于个人偏好范畴

那现在,咱们开始吧。

让Git用起来更清晰明了

第一组设置,能显著提升Git在默认状态下的使用体验。启用这些设置,通常不会带来任何弊端。

分支列表显示优化

我在之前一篇博客的分支技巧板块提到过这一点。鉴于它也出现在“春季大扫除”列表里,想必大家都认同,Git分支列表默认按字母顺序排列,或许并非最佳方式。

有两个设置能够改善这一情况:branch.sortcolumn.ui。前者依据最近提交日期进行排序(如此一来,更受关注的分支便会显示在顶端),而非按字母顺序。后者则将分支名称以列格式呈现,这样每屏能够展示更多内容。

git config --global column.ui auto
git config --global branch.sort -committerdate

column.ui设置同样会对其他列表命令的输出(如clean、status、tag)产生影响。不过总体而言,我觉得它比默认设置更为出色。

你也可以按照提交日期以外的方式进行排序,但在我看来,按提交日期排序显然是最实用的。

说到列表展示,标签列表默认的排序方式并非如此,这其实挺不合理的,毕竟按提交日期排序才是大多数人真正想要的。

通常情况下,如果按字母顺序列出标签,你会得到这样的结果:

$ git tag
nightly/0.5.100n
ightly/0.5.1000
nightly/0.5.1001
nightly/0.5.101
nightly/0.5.1010

没人希望0.5.101排在0.5.1000后面,但按字母顺序就是会出现这种情况。你可以通过设置以下内容来解决这个问题:

git config --global tag.sort version:refname

这样设置后,通常会按照你期望的方式工作,它会把带点的版本号当作一系列整数值来排序。相信我,直接启用它就对了。

默认分支设置

这一点可能存在一些争议,因为在某种程度上它带有政治性色彩。不过,在Git中确实应该有一个默认分支名,这样每次你执行init初始化一个新仓库时,它就不会报错。

git config --global init.defaultBranch main

就我个人而言,我对master这个分支名没有意见,我的大多数仓库也都在使用它,毕竟它曾经是默认设置。但我对main也不排斥,所以不管你想用哪个,直接设置就好。

我觉得Git现在在这方面的处理方式挺让人恼火的,它本应直接更新默认值。我原本期望Git在这方面能有点前瞻性,但它没有,所以你得自行设置一个你认为合理的值。唉,随它去吧。

更优的差异比对

其实,关于git diff算法,完全可以专门写一篇博客来详细阐述。简单来讲,Git默认采用一种名为“myers diff”的旧式差异比对算法,它速度快且相当可靠。

要理解“旧式”的概念,得知道这个算法最早在1986年的一篇论文中发表,算起来它都快40岁了。要是你和我年纪差不多,或许我能从童年记忆给你找点参照:在那一年,电影《三个火枪手》《美国鼠谭》以及第一部《挑战者》都在影院上映。总之,自那时起,相关技术已经有了不少进步(当然也有一些取舍)。你可能会惊讶地发现,Git实际上内置了4种可供使用的差异算法,分别是myersminimalpatiencehistogram

几乎可以肯定,你会想用histogram算法(它是对patience算法的进一步优化),而不是默认的myers算法。你可以通过下面的命令全局更改设置:

git config --global diff.algorithm histogram

下面通过一个简单的代码移动示例,对比myershistogram算法,直观展示histogram算法的智能之处。假设我们把一个CSS类移动到另一个类似的类下面,并稍作修改,然后运行默认myers算法的git diff,可能会得到这样的结果:

git diff 默认输出

嗯,看起来有点让人摸不着头脑。在同样的场景下,histogram算法会给出这样的结果:

git diff使用histogram算法的输出结果

这样一来,实际发生的变化就清晰多了。就在去年,Elijah(大家还记得他在Git Merge大会上的演讲吧)建议把histogrampatience算法设为默认选项,这和Felipe在“春季大扫除”建议中提出的观点一致。但实际上,这项变更短期内很难通过审核流程。

除了算法替换,这是个重要改进,你还可以对git diff做一些小调整:

git config --global diff.colorMoved plain
git config --global diff.mnemonicPrefix true
git config --global diff.renames true

colorMoved也在“春季大扫除”建议列表中,所以它也理应成为默认设置。

下面是启用colorMoved后,代码移动效果的示例:

git diff使用colorMoved算法的输出结果

这下,你真的能看出移动代码和添加行之间的区别了。使用colorMoved,代码移动部分会以不同颜色显示,和添加、删除的行区分开来。

diff.renames选项能检测文件是否被重命名,这通常很实用(尽管会稍微消耗点性能)。而diff.mnemonicPrefix会替换差异头部输出中的a/b/,显示差异的来源,比如i/(索引)、w/(工作目录)或c/(提交)。

所以,如果我对索引到工作目录的更改进行比较,会得到这样的差异头部:

❯ git diff
diff --git i/apps/web/page.js w/apps/web/page.js
index 7568be2ef..b9e9a00d7 100644
--- i/apps/web/page.js
+++ w/apps/web/page.js

从这个例子可能不太容易看出来,但通过前面的路径名,你就能区分哪一侧来自索引,哪一侧来自工作目录。这个区别很细微,但我挺喜欢。

优化推送体验

从Git早期开始,正确设置跟踪分支这件事就一直让我感到困惑和头疼。每次推送时,我都得琢磨它会推送到哪里,或者到底能不能推送成功。

有三个相对较新的推送设置,我觉得能极大提升默认的使用体验。第一个(push.defaultsimple)从Git 2.0版本起就已经成为新的默认设置了,不过其他设置仍需要手动明确配置。

git config --global push.default simple # (自2.0起为默认设置)
git config --global push.autoSetupRemote true
git config --global push.followTags true

在Git里,这一直是个不大不小的麻烦。新的simple默认设置,本质上是为集中式工作流设计的,它会默认将当前分支推送到远程仓库中同名的分支上。我觉得这作为默认设置挺合理的。

但是,要是远程分支不存在,而且又没有设置跟踪分支,你还是会碰到这样的错误提示:

$ git push
fatal: The current branch my-branch-name has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin my-branch-name

我猜你们大概率已经见过这个问题无数次了。

要是你把push.autoSetupRemote设为true,就再也不会被这个错误困扰了。一旦上游分支未设置,它会自动帮你完成设置。我真的太喜欢这个设置了,简直无法用言语形容。

最后,push.followTags这个设置,会在你每次推送时,把本地存在但服务器上没有的所有标签都一并推送过去。我之前就因为这个问题踩过好几次坑——要是你在本地创建了标签,设置这个选项后,就不用担心别人看不到这些标签了。

优化拉取功能

有人觉得保留一些已在服务器上删除的分支和标签的本地历史副本有好处,但我不太认同这种看法。

就我个人而言,Git的默认行为理应尽可能让本地的远程引用与远程服务器上的保持一致,比如自动清理掉已经删除的内容。

所以,我认为这些拉取设置应该成为默认配置:

git config --global fetch.prune true
git config --global fetch.pruneTags true
git config --global fetch.all true

这其实就是确保当服务器上删除了blah分支或标签时,我们本地的origin/blah也会跟着被删除,而且会自动对所有已配置的远程仓库执行这个操作。在我看来,这再合理不过了。 。

为何不尝试一下?

接下来这一批设置通常不会带来任何负面影响,而且偶尔还能派上用场。

我不确定是否非得将它们设为默认值,但我觉得这些设置也不会给任何人造成困扰,反而在很多情况下能提供便利,所以我把它们列入了我的推荐清单。

自动纠正提示

正如我在上一篇文章中详细阐释的,Git具备一项相当实用的功能:当你输入命令时不小心输错,它会推测你的意图并尝试执行。

不过,默认状态下,Git并不会这么做。我个人倾向于让Git进行推测并给出提示。

git config --global help.autocorrect prompt

要是你想深入了解这个设置、其背后的原理以及相关历史,我专门写过一篇文章供你参考。

提交时展示差异

这也是“春季大扫除”列表中的建议之一,我认为主要原因在于,它能在你于编辑器中撰写提交信息时,提供更多可供参考的上下文内容。

默认情况下,执行git commit命令,你会看到这样的信息:

这里仅有已更改文件的列表。如果你将git config --global commit.verbose true设置为true,它就会把完整的git diff输出内容展示出来,方便你在撰写提交信息时作为参考。

git config --global commit.verbose true

现在,当你执行提交操作时,界面会呈现出这样的效果:

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

这个设置仅在你需要反复进行存在冲突的变基操作时才会发挥作用。这种情况并不常见,不过即便开启了该功能却从未使用,也不会产生任何不良影响。

git config --global rerere.enabled true

rerere.enabled选项会让Git记录变基冲突前后的状态,而rerere.autoUpdate则会在再次遇到相同冲突时,自动应用之前的解决方案。我在另一篇文章中对这个功能进行了详细介绍,在此就不再重复赘述了。

全局忽略文件

这可能有点多此一举,毕竟已经有一个包含全局配置的~/.gitconfig文件了,要是能再有一个包含全局忽略值的~/.gitignore文件,那就更好了。以下设置便能实现这一点:

git config --global core.excludesfile ~/.gitignore

实际上,这多少有些冗余,因为Git本身已经会在~/git/ignore~/.config/git/ignore这两个位置查找全局忽略值。但鉴于这些路径不太容易记住,我觉得设置一个更容易猜到的路径还是挺不错的。

更优雅的变基操作

这部分主要探讨的是修复提交以及压缩提交的应用场景。要是你不太清楚这是怎么回事,可以查阅我们之前发布的关于自动压缩的博文。

如果你经常(或者偶尔)需要进行压缩和变基操作,那么这些设置或许能派上用场,而且肯定不会干扰现有的操作流程。

git config --global rebase.autoSquash true
git config --global rebase.autoStash true
git config --global rebase.updateRefs true

说实话,updateRefs这个设置几乎理应成为默认选项。它的作用只是确保在分支进行变基时,分支中的堆叠引用也会随之同步移动。

要是你想深入了解如何运用fixup、autosquash以及updateRefs,最简便的方式或许是观看我在此处讲解的几分钟演讲:

个人偏好设置

接下来这组设置主要取决于个人喜好。大多数人可能并不了解这些设置,然而很多人也许会发现它们十分实用。在我的简要配置里,这些设置都被注释掉了。

优化合并冲突显示

虽然在“春季大扫除”这个主题讨论中有人提出,这个设置可能成为新的默认选项,但我不确定大家是否都能认同。

当在 Git 中遭遇合并冲突时,除了插入表示左右两侧差异的冲突标记外,还能让它显示冲突部分的基础版本。这有时很有帮助,但也有人会觉得多此一举。

git config --global merge.conflictstyle zdiff3

Git 邮件列表里曾探讨过将此设为默认选项,而且 GitButler 实际上就是用 diff3 策略来处理合并冲突标记的。但说实话,并非所有人都喜欢这种方式。

下面是在进行合并或变基操作时,文件中可能出现的简单合并冲突标记示例:

启用 merge.conflictStyle zdiff3 设置后,显示效果如下:

本质上,除了显示 <<<<<<>>>>>> 部分(分别展示你和他人对代码块的修改情况)外,它还会添加一个 ||||||| 代码块,用来显示在你们双方修改之前该部分代码的原始状态。

这种额外的上下文信息(即双方修改前代码的样子)有时非常实用,但通常它只是增加了更多内容,还可能让人看得一头雾水。

实际上,是否需要这些额外信息完全取决于个人偏好。

⚠️ 从很早以前开始,Git 就支持将 diff3 作为处理策略。我这里推荐使用 zdiff3,也就是“ 积极版 diff3”,它的效果稍好一些,但仅在 Git 2.35(2022 年 1 月发布)及之后的版本中可用。如果你使用的是较旧版本的 Git,去掉“z”就可以了。

优化拉取操作

关于合并和变基哪个更好的争论,恐怕永远也不会有统一的答案,不过大多数人都有自己的偏好。但你可能不知道,其实可以设置 git pull 的默认行为,让它只执行其中一种操作。不用每次都输入 git pull --rebase,你可以把它设为默认:

git config --global pull.rebase true

这是个人选择。因为我最近已经转变成只使用变基的人,所以这个设置已经加进我的配置里了。

运行fsmonitor进程

再次说明,此操作主要适用于较大型的代码库。或许你并不希望文件系统监视器在各处运行,但对于大型工作目录而言,它能让git status这类操作的速度大幅提升。

也许它不应成为默认设置,但它不会产生任何负面影响,反而能带来明显的性能提升。或许git clone操作应该询问用户是否要启用它。不管怎样,这是一个可供选择的设置。

git config --global core.fsmonitor true
git config --global core.untrackedCache true

这会为每个代码库运行一个文件系统监视器,它能够监测文件的变更并更新缓存。如此一来,git status就无需逐个遍历每个文件,也无需通过成千上万次的mtime stat调用来检查是否有变更,只需查看一个简单的文件变更日志即可。

⚠️ 请注意,这会为你正在使用的每个仓库都运行一个独立进程,数量可能会很多。由于这些进程主要基于事件运行,所以即使有数百个进程,通常也不会对内存或CPU产生明显影响,但这一点还是值得留意。你也可以省略--global参数,仅在较大的仓库中启用该功能。

结语

希望本文能成为一份有用的参考资料,也许你从中学到了一些新的Git配置技巧。其实,其中一些设置本就应该成为默认设置,这在Git邮件列表社区中甚至都不算有争议的观点。

当然,还有很多其他方法可以提升你的Git使用体验,比如设置别名、使用酷炫的外部分页工具和差异工具等等。但我觉得,还是先专注于这些全局实用且相对简单的原生Git设置为好。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。

文章由技术书栈整理,本文链接:https://study.disign.me/article/202509/22.git-core-devs-configure.md

发布时间: 2025-02-28