-
1. 起步
-
2. Git 基础
-
3. Git 分支
-
4. 服务器上的 Git
- 4.1 协议
- 4.2 在服务器上部署 Git
- 4.3 生成 SSH 公钥
- 4.4 架设服务器
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管服务
- 4.10 小结
-
5. 分布式 Git
-
A1. 附录 A: Git 在其他环境
- A1.1 图形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 小结
-
A2. 附录 B: 在应用程序中嵌入 Git
-
A3. 附录 C: Git 命令
10.8 Git 内部原理 - 环境变量
环境变量
Git 总是运行在 `bash` shell 中,并使用许多 shell 环境变量来决定其行为方式。偶尔,了解这些变量以及如何使用它们来让 Git 按照你希望的方式运行会很有用。这不是 Git 关注的所有环境变量的详尽列表,但我们将涵盖最有用的一些。
全局行为
Git 作为计算机程序的一些通用行为取决于环境变量。
`GIT_EXEC_PATH` 决定 Git 在何处查找其子程序(如 `git-commit`、`git-diff` 等)。你可以通过运行 `git --exec-path` 来检查当前设置。
`HOME` 通常不被认为是可定制的(太多其他东西依赖于它),但它是 Git 查找全局配置文件的地方。如果你想要一个真正便携的 Git 安装,包括全局配置,你可以在便携 Git 的 shell 配置文件中覆盖 `HOME`。
`PREFIX` 类似,但用于系统范围的配置。Git 在 `$PREFIX/etc/gitconfig` 查找此文件。
`GIT_CONFIG_NOSYSTEM` 如果设置,将禁用使用系统范围的配置文件。这在你的系统配置干扰你的命令但你又无法更改或删除它时很有用。
`GIT_PAGER` 控制用于在命令行上显示多页输出的程序。如果未设置此变量,则将使用 `PAGER` 作为备选。
`GIT_EDITOR` 是当用户需要编辑文本时(例如,提交信息)Git 将启动的编辑器。如果未设置,则将使用 `EDITOR`。
仓库位置
Git 使用几个环境变量来确定它如何与当前仓库交互。
`GIT_DIR` 是 `.git` 文件夹的位置。如果未指定此变量,Git 会向上遍历目录树,直到到达 `~` 或 `/`,每一步都查找 `.git` 目录。
`GIT_CEILING_DIRECTORIES` 控制查找 `.git` 目录的行为。如果你访问加载缓慢的目录(例如磁带驱动器上的目录,或通过缓慢的网络连接),你可能希望 Git 比平时更早停止尝试,特别是在构建 shell 提示符时调用 Git 的情况。
`GIT_WORK_TREE` 是非裸仓库工作目录的根目录位置。如果指定了 `--git-dir` 或 `GIT_DIR`,但未指定 `--work-tree`、`GIT_WORK_TREE` 或 `core.worktree` 中的任何一个,则当前工作目录被视为工作树的顶层。
`GIT_INDEX_FILE` 是索引文件的路径(仅适用于非裸仓库)。
`GIT_OBJECT_DIRECTORY` 可用于指定通常位于 `.git/objects` 的目录位置。
`GIT_ALTERNATE_OBJECT_DIRECTORIES` 是一个冒号分隔的列表(格式为 `/dir/one:/dir/two:...`),它告诉 Git 如果对象不在 `GIT_OBJECT_DIRECTORY` 中,则在哪里查找。如果你恰好有很多项目,其中包含大量具有完全相同内容的文件,这可以用于避免存储过多的副本。
路径规格
“路径规格”(pathspec)是指你在 Git 中指定路径的方式,包括使用通配符。这些在 `.gitignore` 文件中使用,也在命令行中使用(`git add *.c`)。
`GIT_GLOB_PATHSPECS` 和 `GIT_NOGLOB_PATHSPECS` 控制路径规格中通配符的默认行为。如果 `GIT_GLOB_PATHSPECS` 设置为 1,通配符字符将作为通配符(这是默认行为);如果 `GIT_NOGLOB_PATHSPECS` 设置为 1,通配符字符将只匹配它们自身,这意味着 `*.c` 只会匹配一个名为“\*.c”的文件,而不是任何名称以 `.c` 结尾的文件。你可以在个别情况下通过以 `:(glob)` 或 `:(literal)` 开头的路径规格来覆盖此行为,例如 `:(glob)\*.c`。
`GIT_LITERAL_PATHSPECS` 禁用上述两种行为;通配符字符将不起作用,并且覆盖前缀也将被禁用。
`GIT_ICASE_PATHSPECS` 将所有路径规格设置为不区分大小写。
提交
Git 提交对象的最终创建通常由 `git-commit-tree` 完成,它将这些环境变量作为其主要信息来源,仅当这些变量不存在时才回退到配置值。
`GIT_AUTHOR_NAME` 是“作者”字段中可读的名称。
`GIT_AUTHOR_EMAIL` 是“作者”字段的电子邮件。
`GIT_AUTHOR_DATE` 是用于“作者”字段的时间戳。
`GIT_COMMITTER_NAME` 设置“提交者”字段的人名。
`GIT_COMMITTER_EMAIL` 是“提交者”字段的电子邮件地址。
`GIT_COMMITTER_DATE` 用于“提交者”字段的时间戳。
`EMAIL` 是在未设置 `user.email` 配置值时的备用电子邮件地址。如果*此*变量也未设置,Git 将回退到系统用户和主机名。
网络
Git 使用 `curl` 库通过 HTTP 执行网络操作,因此 `GIT_CURL_VERBOSE` 告诉 Git 发出该库生成的所有消息。这类似于在命令行上执行 `curl -v`。
`GIT_SSL_NO_VERIFY` 告诉 Git 不验证 SSL 证书。如果你使用自签名证书通过 HTTPS 提供 Git 仓库,或者你正在设置 Git 服务器但尚未安装完整证书,这有时可能是必要的。
如果 HTTP 操作的数据速率低于 `GIT_HTTP_LOW_SPEED_LIMIT` 字节/秒,并且持续时间超过 `GIT_HTTP_LOW_SPEED_TIME` 秒,Git 将中止该操作。这些值会覆盖 `http.lowSpeedLimit` 和 `http.lowSpeedTime` 配置值。
`GIT_HTTP_USER_AGENT` 设置 Git 在通过 HTTP 通信时使用的用户代理字符串。默认值为 `git#2.0.0` 等。
差异和合并
`GIT_DIFF_OPTS` 有点用词不当。唯一有效的值是 `-u
`GIT_EXTERNAL_DIFF` 用作 `diff.external` 配置值的覆盖。如果设置了它,当调用 `git diff` 时,Git 将调用此程序。
`GIT_DIFF_PATH_COUNTER` 和 `GIT_DIFF_PATH_TOTAL` 在由 `GIT_EXTERNAL_DIFF` 或 `diff.external` 指定的程序内部很有用。前者表示一系列中正在进行差异比较的文件是第几个(从 1 开始),后者是批处理中的文件总数。
`GIT_MERGE_VERBOSITY` 控制递归合并策略的输出。允许的值如下:
-
0:不输出任何内容,可能除了一个错误消息。
-
1:只显示冲突。
-
2:也显示文件更改。
-
3:显示文件因未更改而被跳过的情况。
-
4:显示所有正在处理的路径。
-
5 及以上:显示详细的调试信息。
默认值为 2。
调试
想*真正*知道 Git 在做什么吗?Git 嵌入了一套相当完整的跟踪功能,你只需要打开它们。这些变量的可能值如下:
-
“true”、“1”或“2”——跟踪类别被写入 stderr。
-
以 `/` 开头的绝对路径——跟踪输出将写入该文件。
`GIT_TRACE` 控制一般跟踪,这些跟踪不属于任何特定类别。这包括别名扩展和委托给其他子程序。
$ GIT_TRACE=true git lga
20:12:49.877982 git.c:554 trace: exec: 'git-lga'
20:12:49.878369 run-command.c:341 trace: run_command: 'git-lga'
20:12:49.879529 git.c:282 trace: alias expansion: lga => 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.879885 git.c:349 trace: built-in: git 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.899217 run-command.c:341 trace: run_command: 'less'
20:12:49.899675 run-command.c:192 trace: exec: 'less'
`GIT_TRACE_PACK_ACCESS` 控制 packfile 访问的跟踪。第一个字段是正在访问的 packfile,第二个字段是该文件内的偏移量。
$ GIT_TRACE_PACK_ACCESS=true git status
20:10:12.081397 sha1_file.c:2088 .git/objects/pack/pack-c3fa...291e.pack 12
20:10:12.081886 sha1_file.c:2088 .git/objects/pack/pack-c3fa...291e.pack 34662
20:10:12.082115 sha1_file.c:2088 .git/objects/pack/pack-c3fa...291e.pack 35175
# […]
20:10:12.087398 sha1_file.c:2088 .git/objects/pack/pack-e80e...e3d2.pack 56914983
20:10:12.087419 sha1_file.c:2088 .git/objects/pack/pack-e80e...e3d2.pack 14303666
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
`GIT_TRACE_PACKET` 启用网络操作的包级跟踪。
$ GIT_TRACE_PACKET=true git ls-remote origin
20:15:14.867043 pkt-line.c:46 packet: git< # service=git-upload-pack
20:15:14.867071 pkt-line.c:46 packet: git< 0000
20:15:14.867079 pkt-line.c:46 packet: git< 97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git#2.0.4
20:15:14.867088 pkt-line.c:46 packet: git< 0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-show-diff-func-name
20:15:14.867094 pkt-line.c:46 packet: git< 36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config
# […]
`GIT_TRACE_PERFORMANCE` 控制性能数据的日志记录。输出显示每次特定的 `git` 调用需要多长时间。
$ GIT_TRACE_PERFORMANCE=true git gc
20:18:19.499676 trace.c:414 performance: 0.374835000 s: git command: 'git' 'pack-refs' '--all' '--prune'
20:18:19.845585 trace.c:414 performance: 0.343020000 s: git command: 'git' 'reflog' 'expire' '--all'
Counting objects: 170994, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (43413/43413), done.
Writing objects: 100% (170994/170994), done.
Total 170994 (delta 126176), reused 170524 (delta 125706)
20:18:23.567927 trace.c:414 performance: 3.715349000 s: git command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack'
20:18:23.584728 trace.c:414 performance: 0.000910000 s: git command: 'git' 'prune-packed'
20:18:23.605218 trace.c:414 performance: 0.017972000 s: git command: 'git' 'update-server-info'
20:18:23.606342 trace.c:414 performance: 3.756312000 s: git command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Checking connectivity: 170994, done.
20:18:25.225424 trace.c:414 performance: 1.616423000 s: git command: 'git' 'prune' '--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414 performance: 0.001051000 s: git command: 'git' 'rerere' 'gc'
20:18:25.233159 trace.c:414 performance: 6.112217000 s: git command: 'git' 'gc'
`GIT_TRACE_SETUP` 显示关于 Git 正在发现的仓库和它正在交互的环境的信息。
$ GIT_TRACE_SETUP=true git status
20:19:47.086765 trace.c:315 setup: git_dir: .git
20:19:47.087184 trace.c:316 setup: worktree: /Users/ben/src/git
20:19:47.087191 trace.c:317 setup: cwd: /Users/ben/src/git
20:19:47.087194 trace.c:318 setup: prefix: (null)
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
杂项
如果指定了 `GIT_SSH`,它是一个在 Git 尝试连接到 SSH 主机时被调用以代替 `ssh` 的程序。它被调用为 `$GIT_SSH [username@]host [-p
`GIT_SSH_COMMAND` 设置 Git 尝试连接到 SSH 主机时使用的 SSH 命令。该命令由 shell 解释,可以与 `ssh` 一起使用额外的命令行参数,例如 `GIT_SSH_COMMAND="ssh -i ~/.ssh/my_key" git clone git@example.com:my/repo`。
`GIT_ASKPASS` 是 `core.askpass` 配置值的覆盖。这是一个当 Git 需要向用户请求凭据时调用的程序,它可以将文本提示作为命令行参数,并应在 `stdout` 上返回答案(有关此子系统的更多信息,请参阅凭据存储)。
`GIT_NAMESPACE` 控制对命名空间引用(namespaced refs)的访问,等同于 `--namespace` 标志。这主要在服务器端有用,你可能希望在一个仓库中存储同一仓库的多个分支,只保持引用分离。
`GIT_FLUSH` 可用于强制 Git 在向 stdout 增量写入时使用非缓冲 I/O。值为 1 会使 Git 更频繁地刷新,值为 0 会使所有输出都被缓冲。默认值(如果未设置此变量)是根据活动和输出模式选择合适的缓冲方案。
`GIT_REFLOG_ACTION` 允许你指定写入 reflog 的描述性文本。这里有一个例子:
$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'My message'
[master 9e3d55a] My message
$ git reflog -1
9e3d55a HEAD@{0}: my action: My message