流行的 git 配置选项

流行的 git 配置选项

一系列流行的 Git 配置选项,包括自动合并设置、合并冲突风格、提交整合、自动储藏与应用等。文章详细介绍了每个选项的用途和配置方法,适合那些希望优化 Git 工作流程的开发者阅读。通过这些配置,读者可以提高 Git 的使用效率,更好地管理代码库。
author
Wonderhows February 18, 2024

你好!我一直希望命令行工具能够附带关于其各种选项的流行程度的数据,比如:

  • “基本没人用这个”
  • “80%的人使用这个,可能值得一看”
  • “这个有6个可能的值,但实际上人们只使用这2个”

所以我在 Mastodon 上询问了人们最喜欢的 git 配置选项

你最喜欢设置哪些 git 配置选项?目前我只设置了 git config push.autosetupremote truegit config init.defaultBranch main 在我的 ~/.gitconfig 中,好奇其他人都设置了什么

像往常一样,我收到了很多很棒的回答,并了解了很多我之前从未听说过的非常流行的 git 配置选项。

我将列出这些选项,从(非常大致的)最受欢迎的开始。这里有一个目录:

所有的选项都记录在 man git-config 中,或者这个页面

pull.ff onlypull.rebase true

这两个是最受欢迎的。这两个都有类似的目标:当你在一个分支上运行 git pull 时,避免意外创建合并提交,而上游分支已经发生了分歧。

  • pull.rebase true 相当于每次你运行 git pull 时都运行 git pull --rebase
  • pull.ff only 相当于每次你运行 git pull 时都运行 git pull --ff-only

我很确定同时设置这两个没有意义,因为 --ff-only 会覆盖 --rebase

个人来说,我不使用这些,因为我更喜欢每次都决定如何处理这种情况,而现在 git 在你的分支与上游分支发生分歧时的默认行为是抛出错误并询问你该怎么做(非常类似于 git pull --ff-only 所做的)。

merge.conflictstyle zdiff3

接下来:让合并冲突更易读!merge.conflictstyle zdiff3merge.conflictstyle diff3 都非常受欢迎(“绝对必不可少”)。

主要思想是共识似乎是“diff3 很棒,而 zdiff3(更新的)更好!”。

那么 diff3 是怎么回事呢。好吧,默认情况下在 git 中,合并冲突看起来是这样的:

<<<<<<< HEAD
def parse(input):
    return input.split("\n")
=======
def parse(text):
    return text.split("\n\n")
>>>>>>> somebranch

我应该决定 input.split("\n") 还是 text.split("\n\n") 更好。但如何决定?如果我不记得 \\n 还是 \\n\\n 哪个是对的怎么办?进入 diff3!

以下是设置了 merge.conflictstyle diff3 后相同的合并冲突看起来的样子:

<<<<<<< HEAD
def parse(input):
    return input.split("\n")
||||||| b9447fc
def parse(input):
    return input.split("\n\n")
=======
def parse(text):
    return text.split("\n\n")
>>>>>>> somebranch

这有额外的信息:现在代码的原始版本在中间!所以我们可以看到:

  • 一方将 \\n\\n 改成了 \\n
  • 另一方将 input 改名为 text

所以合并冲突的正确解决方案可能是 return text.split("\\n"),因为这结合了双方的更改。

我还没有使用过 zdiff3,但很多人似乎认为它更好。博文 使用 zdiff3 更好地处理 Git 冲突 有更多关于它的讨论。

rebase.autosquash true

Autosquash 对我来说也是一个新功能。它的目标是使修改旧提交变得更容易。

它的工作方式是这样的:

  • 你有一个提交,你希望它与3个提交前的某个提交合并,比如 add parsing code
  • 你用 git commit --fixup OLD_COMMIT_ID 提交它,这给新提交的提交消息 fixup! add parsing code
  • 现在,当你运行 git rebase --autosquash main 时,它会自动将所有 fixup! 提交与它们的目标合并

rebase.autosquash true 意味着 --autosquash 总是自动传递给 git rebase

rebase.autostash true

这会在 git rebase 之前自动运行 git stash 并在之后运行 git stash pop。它基本上向 git rebase 传递 --autostash

个人来说,我对此有点害怕,因为它可能在 rebase 后导致合并冲突,但我猜这对人们来说并不经常发生,因为它似乎是一个非常受欢迎的配置选项。

push.default simple, push.default current

这些 push.default 选项告诉 git push 自动将当前分支推送到同名的远程分支。

  • push.default simple 是 Git 的默认设置。它只在你的分支已经跟踪了一个远程分支时才有效
  • push.default current 类似,但它总是将本地分支推送到同名的远程分支
  • push.autoSetupRemotepush.default simple 一起使用似乎与 push.default current 做的事情基本相同

current 似乎是一个很好的设置,如果你确定你永远不会意外创建一个与无关远程分支同名的本地分支。很多人有分支命名约定(如 julia/my-change),使这种冲突非常不太可能,或者只是合作者足够少,以至于分支名称冲突可能不会发生。

init.defaultBranch main

在创建新仓库时创建 main 分支而不是 master 分支。

commit.verbose true

这会在你编写提交消息的文本编辑器中添加整个提交差异,以帮助你记住你在做什么。

rerere.enabled true

这启用了 rerere(“复的 决方案”),它记住了你在 git rebase 期间如何解决合并冲突,并在可能的情况下自动为你解决冲突。

help.autocorrect 10

默认情况下 git 的自动更正会尝试检查拼写错误(如 git ocmmit),但不会实际运行更正的命令。

如果你想让它自动运行建议的命令,你可以将 help.autocorrect 设置为 1(在0.1秒后运行)、10(在1秒后运行)、immediate(立即运行)或 prompt(在提示后运行)

“分页器”是 git 用来显示 git diffgit loggit show 等的输出。人们将其设置为:

  • delta(一个具有语法高亮的花哨差异查看工具)
  • less -x5,9(设置制表符,如果你有很多带制表符的文件,这似乎有帮助?)
  • less -F -X(不确定这个,-F 似乎在所有内容都适合一个屏幕时禁用分页器,但我的 git 似乎已经可以做到这一点)
  • cat(完全禁用分页)

我曾经使用 delta,但因为我以某种方式弄乱了我的终端的配色方案,并且无法弄清楚如何修复它,所以我关闭了它。我认为这是一个很棒的工具。

我相信 delta 还建议你设置 interactive.diffFilter delta --color-only,以便在运行 git add -p 时对代码进行语法高亮。

diff.algorithm histogram

Git 的默认 diff 算法经常处理函数重排序的问题很糟糕。例如,看看这个差异:

-.header {
+.footer {
     margin: 0;
 }

-.footer {
+.header {
     margin: 0;
+    color: green;
 }

我发现这很混乱。但是使用 diff.algorithm histogram,差异看起来是这样的,我觉得更清晰:

-.header {
-    margin: 0;
-}
-
 .footer {
     margin: 0;
 }

+.header {
+    margin: 0;
+    color: green;
+}

一些人也使用 patience,但 histogram 似乎更受欢迎。何时使用每种 Git Diff 算法 有更多关于这个的信息。

core.excludesfile:全局 .gitignore

core.excludeFiles = ~/.gitignore 允许你设置一个适用于所有仓库的全局 gitignore 文件,用于诸如 .idea.DS_Store 这类你永远不想提交到任何仓库的内容。它默认为 ~/.config/git/ignore

includeIf:个人和工作的不同 git 配置

很多人说他们使用这个来为个人和工作仓库配置不同的电子邮件地址。你可以这样设置:

[includeIf "gitdir:~/code/<work>/"]
path = "~/code/<work>/.gitconfig"

url."[email protected]:".insteadOf 'https://github.com/'

我经常意外克隆 HTTP 版本的仓库而不是 SSH 版本,然后不得不手动进入 ~/.git/config 并编辑远程 URL。这似乎是一个不错的解决办法:它会将远程仓库中的 https://github.com 替换为 [email protected]:

以下是在 ~/.gitconfig 中的样子,因为它有点复杂:

[url "[email protected]:"]
	insteadOf = "https://github.com/"

有人说他们使用 pushInsteadOf 代替,以便只在 git push 时进行替换,因为他们不想在拉取公共仓库时解锁他们的 SSH 密钥。

还有一些人提到设置 insteadOf = "gh:",这样他们可以通过 git remote add gh:jvns/mysite 来添加远程仓库,减少打字。

fsckobjects:避免数据损坏

有几个人提到了这个。有人解释说:“及早检测数据损坏。很少有关系,但有几次为我的整个团队挽救了局面”。

transfer.fsckobjects = true
fetch.fsckobjects = true
receive.fsckObjects = true

submodule stuff

我从未理解过任何关于子模块的内容,但有几个人说他们喜欢设置:

  • status.submoduleSummary true
  • diff.submodule log
  • submodule.recurse true

我不会尝试解释这些,但这里有 Mastodon 上 @unlambda 的解释

等等

以下是至少有2个人建议的其他所有内容:

  • blame.ignoreRevsFile .git-blame-ignore-revs 允许你指定一个文件,其中包含在 git blame 期间要忽略的提交,这样大型重命名就不会搞乱你的 blame
  • branch.sort -committerdate,使 git branch 按最近使用的分支排序,而不是按字母排序,以便于找到分支。tag.sort taggerdate 对标签也是类似的
  • color.ui false:关闭颜色
  • commit.cleanup scissors:这样你就可以在提交消息中写 #include 而不会因为 # 被视为注释而被删除
  • core.autocrlf false:在 Windows 上,与使用 Unix 的人一起工作时很有用
  • core.editor emacs:使用 emacs(或其他编辑器)编辑提交消息
  • credential.helper osxkeychain:使用 Mac 密钥链进行管理
  • diff.tool difftastic:使用 difftastic(或 meldnvimdiffs)显示差异
  • diff.colorMoved default:使用不同颜色高亮显示在差异中被“移动”的行
  • diff.colorMovedWS allow-indentation-change:设置 diff.colorMoved 时,同时忽略缩进变化
  • diff.context 10:在差异中包含更多上下文
  • fetch.prune truefetch.prunetags - 自动删除已删除的远程跟踪分支
  • gpg.format ssh:允许你使用 SSH 密钥签署提交
  • log.date iso:将日期显示为 2023-05-25 13:54:51 而不是 Thu May 25 13:54:51 2023
  • merge.keepbackup false,以去除 git 在合并冲突期间创建的 .orig 文件
  • merge.tool meld(或 nvimnvimdiff),以便你可以使用 git mergetool 帮助解决合并冲突
  • push.followtags true:与被推送的提交一起推送新标签
  • rebase.missingCommitsCheck error:不允许在 rebase 期间删除提交
  • rebase.updateRefs true:使同时 rebase 多个堆叠分支变得更容易。关于这个的博文在这里

如何设置这些

我通常使用 git config --global NAME VALUE 设置 git 配置选项,例如 git config --global diff.algorithm histogram。我通常全局设置我所有的选项,因为在不同的仓库中有不同的 git 行为让我感到压力。

如果我想删除一个选项,我会手动编辑 ~/.gitconfig,它们看起来像这样:

[diff]
	algorithm = histogram

我在写这篇博文后做的更改

我的 git 配置非常简单,我已经有了:

  • init.defaultBranch main
  • push.autoSetupRemote true
  • merge.tool meld
  • diff.colorMoved default(实际上这对我来说甚至不起作用,但我还没有找到时间去调试)

并且在写这篇博文后我添加了这3个:

  • diff.algorithm histogram
  • branch.sort -committerdate
  • merge.conflictstyle zdiff3

如果制作精心打造的带有多个提交的拉取请求是我现在生活中的一个更大部分,我可能也会设置 rebase.autosquash

我已经学会对设置新的配置选项保持谨慎——我需要很长时间来适应新的行为,如果我一次改变太多东西,我只会感到困惑。branch.sort -committerdate 是我已经在使用的东西(通过别名),而且我相当确信 diff.algorithm histogram 会在我重排函数时使我的差异更易于阅读。

就是这些!

我总是惊讶于只是询问很多人他们喜欢什么东西,然后列出最常被提及的东西是多么有用,就像几年前我整理的这个新型命令行工具列表。拥有一个包含20或30个选项的列表,以供考虑,比逐个浏览所有600多个 git 配置选项要高效得多。

总结这些有点困难,因为 git 的默认选项实际上多年来已经发生了很大的变化,所以人们偶尔会设置一些8年前很重要但今天已成为默认的选项。此外,人们使用的一些实验选项已被删除,并被不同版本替代。

我尽力准确解释目前 git 在 2024 年的工作方式,但我肯定在这里弄错了一些地方,特别是因为我自己大多数选项都不使用。如果你在 Mastodon 上看到错误,请告诉我,我会尽力修正。

我可能以后还会询问关于别名的问题,因为有很多很棒的别名我没有提到,因为这已经变得很长了。

comments powered by Disqus