bigywater.tech
Git · 73

config 的优先级:system、global、local、worktree、include

user.name 在好几个地方都设了,到底哪个生效?include 和 includeIf 怎么用?多值的键怎么叠加?worktree 级别的配置是什么?这篇用 --show-origin --show-scope 把每个值的来源和顺序都列出来。

后读覆盖先读
system → global → local → worktree → -c/环境变量,生效值总是最后一个
includeIf gitdir:
路径匹配才引入的配置,常用来给公司和个人目录配不同的 user.email
多值叠加
remote.origin.fetch 这类多值键在各层累加,而不是被覆盖

层级

实测 · 本机执行输出
  $ git config --show-origin --show-scope --get-all user.name
    system	file:/work/_cfg/system.conf	系统层
    global	file:/work/_cfg/global.conf	全局层
    local	file:.git/config	仓库层
  $ git config user.name
    仓库层
  (--get-all 按读取顺序列出所有值,最后一个生效;顺序是 system → global → local)

git 依次读 system、global(~/.gitconfig 与 XDG)、local(.git/config)、worktree(config.worktree),再是环境变量与命令行 -c。同名的单值键,后读的覆盖先读的;--show-origin --show-scope 显示每个值的来源。

命令行与环境

实测 · 本机执行输出
  $ git -c user.name=命令行 config user.name
    命令行
  $ git config user.name
    环境变量
  $ git -c user.name=命令行 config --show-scope --get-all user.name
    system	系统层
    global	全局层
    local	仓库层
    command	环境变量
    command	命令行

git -c k=v 和 GIT_CONFIG_COUNT/KEY_n/VALUE_n 都属于 command 层,在所有文件之后读,命令行最后。

worktree 层

实测 · 本机执行输出
  $ git config --show-scope --show-origin --get-all user.name
    system	file:/work/_cfg/system.conf	系统层
    global	file:/work/_cfg/global.conf	全局层
    local	file:/work/l69/.git/config	仓库层
    worktree	file:/work/l69/.git/worktrees/l69wt/config.worktree	工作树层
  $ git config --show-scope --get-all user.name
    system	系统层
    global	全局层
    local	仓库层
  同一个仓库的另一个工作树(主工作树)看不到“工作树层”的值

设置 extensions.worktreeConfig=true 后,git config --worktree 把值写进该工作树自己的 config.worktree,优先级高于 local,其它工作树看不到。

include

实测 · 本机执行输出
  $ git config --show-origin --get-all user.name
    file:/work/_cfg/system.conf	系统层
    file:/work/_cfg/global.conf	全局层
    file:/work/_cfg/extra.conf	include 进来的
    file:.git/config	仓库层
  $ git config --show-origin --get-all user.email
    file:/work/_cfg/extra.conf	inc@example.com
    file:/work/_cfg/global.conf	全局 include 之后
  includeIf "gitdir:":仓库路径匹配时才引入——可以给公司目录配一套身份
  [l69(路径不匹配)] user.name = 仓库层 ; user.email = me@home.example
  [l69work(匹配 gitdir:…/l69w*/)] user.name = 工作身份 ; user.email = me@corp.example

[include] path 把另一个文件的内容插入到那个位置,所以位置决定覆盖关系;[includeIf "gitdir:…"] 仅当仓库路径匹配时才引入,适合按目录切换身份。

多值键

实测 · 本机执行输出
  $ git config --show-scope --get-all remote.origin.fetch
    global	+refs/heads/global/*:refs/remotes/origin/global/*
    local	+refs/heads/*:refs/remotes/origin/*
  $ git config --get remote.origin.fetch
    +refs/heads/*:refs/remotes/origin/*
  git config --unset remote.origin.fetch(写操作默认只改 local 文件)之后:
    $ git config --show-scope --get-all remote.origin.fetch
      global	+refs/heads/global/*:refs/remotes/origin/global/*

多值的键(如 remote.origin.fetch)在各层累加;--get-all 全部列出,--get 取最后一个。写操作默认只改 local 文件。

global 的两个位置

实测 · 本机执行输出
  只有 $XDG_CONFIG_HOME/git/config(没有 ~/.gitconfig):
    global	file:<cfg>/xdg/git/config	core.pager=xdg-pager
    global	file:<cfg>/xdg/git/config	core.editor=xdg-editor
  两个都有(~/.gitconfig 在后,覆盖前者):
    global	file:<cfg>/xdg/git/config	core.pager=xdg-pager
    global	file:<cfg>/xdg/git/config	core.editor=xdg-editor
    global	file:<cfg>/.gitconfig	core.pager=home-pager
    global	file:<cfg>/.gitconfig	core.editor=home-editor
  git config --global 写入的是 ~/.gitconfig(已存在时优先),不是 XDG 那个: True / False

$XDG_CONFIG_HOME/git/config 和 ~/.gitconfig 都被读,后者在后;git config --global 写入已存在的 ~/.gitconfig。

分步演示

配置的优先级
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / git 2.54.0(Apple Git-157);每个实验在临时目录里新建仓库,HOME 和全局配置指向实验专用的空目录(不读用户自己的 git 配置),提交的作者与时间固定以便复现;需要网络协议的实验用本机的 file:// 或 git daemon 回环端口(9800 以上),不碰任何远程仓库;计时用 time.perf_counter,数字每次运行会有小幅抖动。为了不读真实的系统和用户配置,实验用 GIT_CONFIG_SYSTEM、GIT_CONFIG_GLOBAL 指向实验专用的文件(第六节改用 HOME 和 XDG_CONFIG_HOME 指到实验目录);路径在输出里简化
    • 没有验证:真实的系统配置文件位置(/etc/gitconfig 或安装前缀下的 etc/gitconfig,这台机器没有 /etc/gitconfig);includeIf 的 onbranch:、hasconfig:remote.*.url: 条件;git config -f 指定文件;git config --blob;core.sshCommand 等具体配置项的含义;配置里的路径展开(~)
    京ICP备2026067502号-1京公网安备11010502063487号