简体中文 ▾ 主题 ▾ 最新版本 ▾ CodingGuidelines 最后更新于 2.52.0

此信息专用于 Git 项目

请注意,如果您打算为 Git 项目本身做贡献,此信息才与您相关。它绝不是普通 Git 用户的必读内容。

与其他项目一样,我们也为代码制定了一些指南。对于通用的 Git 开发,一些粗略的规则如下

  • 最重要的一点是,我们从不口口声声说“这是 POSIX 标准;如果你的系统不符合它,我们会心安理得地忽略你的需求”。我们生活在现实世界中。

  • 然而,我们经常会说“让我们避开那种结构,它甚至不在 POSIX 标准中”。

  • 尽管有上述两条规则,我们有时也会说“虽然这不在 POSIX 中,但它(非常方便 | 使代码更具可读性 | 具有其他优良特性),且几乎所有我们关心的平台都支持它,所以让我们使用它”。

    Again, we live in the real world, and it is sometimes a
    judgement call, the decision based more on real world
    constraints people face than what the paper standard says.
  • 在进行实际变更时,作为准备性的清理步骤来修复样式违规是件好事,但除此之外,请避免为了迎合样式而进行无意义的代码改动。

    "Once it _is_ in the tree, it's not really worth the patch noise to
    go and fix it up."
    Cf. https://lore.kernel.org/all/20100126160632.3bdbe172.akpm@linux-foundation.org/
  • 解释变更的提交日志消息与变更本身同样重要。写得清晰的代码和代码内注释解释了代码如何工作以及对周围上下文的假设。日志消息解释了变更想要实现的目标以及为什么变更时必要的(更多内容请参阅随附的 SubmittingPatches 文档)。

让你的代码可读且合乎逻辑,不要试图卖弄技巧。

至于更具体的指南,只需模仿现有代码(无论你为哪个项目做贡献,这都是一条很好的指南)。匹配局部约定总是首选。添加到 Git 套件的新代码应符合现有代码的整体风格。对现有代码的修改应符合周围代码已使用的风格(即使它不符合现有代码的整体风格)。

但如果你必须有一份规则列表,这里有一些针对特定语言的规则。请注意,Documentation/ToolsForGit.adoc 文档收集了一些技巧,帮助你使用外部工具来遵循这些指南。

专门针对 Shell 脚本(未详尽列举)

  • 我们使用制表符(tabs)进行缩进。

  • Case 分支的缩进深度与 case 和 esac 行相同,如下所示

    case "$variable" in
    pattern1)
    	do this
    	;;
    pattern2)
    	do that
    	;;
    esac
  • 重定向操作符书写时,前面应有空格,但后面不应有空格。换句话说,写成 echo test >"$file",而不是 echo test> $fileecho test > $file。请注意,尽管 POSIX 并不要求对变量中的重定向目标加双引号(如上所示),但我们的代码会这样做,因为某些版本的 bash 在没有引号的情况下会发出警告。

    (incorrect)
    cat hello > world < universe
    echo hello >$world
    (correct)
    cat hello >world <universe
    echo hello >"$world"
  • 我们更倾向于使用 $( …​ ) 进行命令替换;与 `` 不同,它可以正确嵌套。这本该是 Bourne shell 从第一天起就采用的写法,但遗憾的是并不是。

  • 如果你想查找某个命令在用户的 $PATH 中是否可用,你应该使用 type <command>,而不是 which <command>which 的输出不是机器可解析的,且其退出码在不同平台上并不可靠。

  • 我们使用符合 POSIX 标准的参数替换,并避免 bash 特有的写法(bashisms);即

  • 我们使用 ${parameter-word} 及其 [-=?+] 变体,以及它们的带冒号的“未设置或为空”形式。

  • 我们使用 ${parameter#word} 及其 [#%] 变体,以及它们的双号“最长匹配”形式。

  • 不使用“子字符串扩展” ${parameter:offset:length}。

  • 不使用 Shell 数组。

  • 不使用模式替换 ${parameter/pattern/string}。

  • 我们使用算术扩展 $…​。

  • 我们不使用进程替换 <(list) 或 >(list)。

  • 不要使用分号将控制结构写在单行上。对于 if 语句,“then”应写在下一行;对于 “while” 和 “for”,“do” 应写在下一行。

    (incorrect)
    if test -f hello; then
    	do this
    fi
    (correct)
    if test -f hello
    then
    	do this
    fi
  • 如果用 && 或 || 或 | 连接的命令序列跨越了多行,请将每个命令放在单独的行中,并将 &&、|| 和 | 运算符放在每行的末尾,而不是开头。这意味着你不需要使用 \ 来连接行,因为上述运算符隐含了序列尚未结束。

    (incorrect)
    grep blob verify_pack_result \
    | awk -f print_1.awk \
    | sort >actual &&
    ...
    (correct)
    grep blob verify_pack_result |
    awk -f print_1.awk |
    sort >actual &&
    ...
  • 我们更倾向于使用 "test" 而不是 "[ …​ ]"。

  • 我们不在 Shell 函数前写多余的单词 "function"。

  • 我们更倾向于在函数名和括号之间留一个空格,而括号内部不留空格。左大括号 "{" 也应放在同一行。

    (incorrect)
    my_function(){
    	...
    (correct)
    my_function () {
    	...
  • 关于 grep 的使用,为了移植性,请坚持使用 BRE 的子集(即:不要使用 \{m,n\}、[::]、[==] 或 [..])。

  • 我们不使用 \{m,n\};

  • 我们不使用 ? 或 +(在 BRE 中分别是 \{0,1\} 和 \{1,\}),但这本是不言而喻的,因为它们是 ERE 元素而非 BRE(注意 \? 和 \+ 甚至不属于 BRE —— 使它们在 BRE 中可用是 GNU 的扩展)。

  • 使用 git-sh-i18n 中的 Git gettext 封装器,使工作界面可翻译。参见 po/README 中的“标记待翻译字符串”。

  • 我们在编写 "test" 命令时不用 "-a" 和 "-o",而是使用 "&&" 或 "||" 来连接多个 "test" 命令,因为 "-a/-o" 的使用通常容易出错。例如

    test -n "$x" -a "$a" = "$b"
    is buggy and breaks when $x is "=", but
    test -n "$x" && test "$a" = "$b"
    does not have such a problem.
  • 尽管 "local" 不属于 POSIX 标准,但我们在测试套件中大量使用它。我们不在脚本化的 Porcelain 命令中使用它,且希望在所有重要的 shell 都支持它之前(值得注意的是,来自 AT&T Research 的 ksh 尚不支持),没有人开始使用 "local"。

  • 某些版本的 shell 无法理解 "export variable=value",因此我们分两行写成 "variable=value" 然后 "export variable"。

  • 某些版本的 dash 在带有 "local"、"export" 和 "readonly" 前缀时,变量赋值存在缺陷,即待赋值的值除非加引号,否则会经过 $IFS 的字段拆分。

    (incorrect)
    local variable=$value
    local variable=$(command args)
    (correct)
    local variable="$value"
    local variable="$(command args)"
  • 常见的结构

    VAR=VAL command args
    to temporarily set and export environment variable VAR only while
    "command args" is running is handy, but this triggers an
    unspecified behaviour according to POSIX when used for a command
    that is not an external command (like shell functions).  Indeed,
    dash 0.5.10.2-6 on Ubuntu 20.04, /bin/sh on FreeBSD 13, and AT&T
    ksh all make a temporary assignment without exporting the variable,
    in such a case.  As it does not work portably across shells, do not
    use this syntax for shell functions.  A common workaround is to do
    an explicit export in a subshell, like so:
    (incorrect)
    VAR=VAL func args
    (correct)
    (
    	VAR=VAL &&
    	export VAR &&
    	func args
    )
    but be careful that the effect "func" makes to the variables in the
    current shell will be lost across the subshell boundary.
  • 在 printf 格式化字符串中使用八进制转义序列(例如 "\302\242"),不要使用十六进制(例如 "\xc2\xa2"),因为十六进制转义序列不可移植。

针对 C 程序

  • 我们使用制表符(tabs)进行缩进,并将制表符解释为占用 8 个空格。

  • 嵌套的 C 预处理器指令在 # 号后按嵌套层级缩进,每层一个空格。

    #if FOO
    # include <foo.h>
    # if BAR
    #  include <bar.h>
    # endif
    #endif
  • 我们尽量保持每行最多 80 个字符。

  • 作为 Git 开发人员,我们假设你拥有相当现代的编译器,并建议你启用 DEVELOPER makefile 选项,以确保你的补丁没有我们关心的所有编译器警告,例如通过 "echo DEVELOPER=1 >>config.mak"。

  • 当使用 DEVELOPER=1 模式时,你可能会看到来自编译器的警告,如 "error: unused parameter foo [-Werror=unused-parameter]",这表示函数忽略了其参数。如果无法移除未使用的参数(例如,因为该函数用作回调且必须符合特定接口),你可以使用 UNUSED(或 MAYBE_UNUSED)关键字对单个参数进行标注,如 "int foo UNUSED"。

  • 我们尝试支持广泛的 C 编译器来编译 Git,包括老旧的编译器。从 Git v2.35.0 开始,Git 要求 C99(我们检查 "STDC_VERSION")。你不应使用来自更新 C 标准的特性,即使你的编译器能识别它们。

    New C99 features have been phased in gradually, if something's new
    in C99 but not used yet don't assume that it's safe to use, some
    compilers we target have only partial support for it. These are
    considered safe to use:
    1. 自 2007 年左右的 2b6854c863a 起,我们一直使用在加载时不可计算的初始值设定项元素。例如

      const char *args[] = { "constant", variable, NULL };
    2. 自 2012 年初的 e1327023ea 起,我们一直使用最后一个元素后跟逗号的枚举定义。这与以逗号结尾的数组初始值设定项一样,可用于减少在末尾添加新标识符时的补丁噪声。

    3. 自 2017 年中期的 cbc0f81d 起,我们一直对结构体使用指定初始值设定项(例如 "struct t v = { .val = a };")。

    4. 自 2017 年中期的 512f41cf 起,我们一直对数组使用指定初始值设定项(例如 "int array[10] = { [5] = 2 }")。

    5. 自 2021 年初的 765dc168882 起,我们一直使用变参宏,主要用于类似 printf 的追踪和调试宏。

    6. 自 2021 年底的 44ba10d6 起,我们开始在 for 循环中声明变量 "for (int i = 0; i < 10; i++)"。

    7. 自 2023 年底的 8277dbe987 起,我们一直使用来自 <stdbool.h> 的 bool 类型。

      C99 features we have test balloons for:
    8. 自 2024 年底的 v2.48.0-rc0~20 起,我们对复合字面量语法进行了测试试用,例如 (struct foo){ .member = value }; 我们希望所关心的平台在使用它们时都没有问题,并计划在 2026 年中期正式采用更广泛的使用。在那之前,请勿增加该语法的使用。

      New C99 features that we cannot use yet:
    9. %z 和 %zu 作为 size_t 的 printf() 参数(%z 用于 POSIX 特有的 ssize_t)。相反,你应该使用 printf("%"PRIuMAX, (uintmax_t)v)。如今我们依赖的 MSVC 版本支持 %z,但 MinGW 使用的 C 库不支持。

    10. 结构体初始化中的速记法如 ".a.b = *c" 已知会使旧版 IBM XLC 报错,请改用 ".a = { .b = *c }"。参见 33665d98 (reftable: make assignments portable to AIX xlc v12.01, 2022-03-28)。

  • 变量必须在块的开头、第一个语句之前声明(即 -Wdeclaration-after-statement)。鼓励在声明结束与块中第一个语句之间留一个空行。

  • 不要显式地将全局变量初始化为 0 或 NULL;相反,让 BSS 段负责零初始化。

  • NULL 指针应写为 NULL,而不是 0。

  • 在声明指针时,星号靠近变量名,即 "char string",而不是 "char string" 或 "char * string"。这使得理解像 "char *string, c;" 这样的代码更容易。

  • 在运算符和关键字周围使用空格,但不要在括号内和函数名周围使用。因此

          while (condition)
    func(bar + 1);
    and not:
          while( condition )
    func (bar+1);
  • 二元运算符(除 "," 外)和三元条件运算符 "?:" 在运算符两侧各有一个空格,以将其与操作数分隔。例如 "A + 1",而不是 "A+1"。

  • 一元运算符(除 "." 和 "→" 外)与操作数之间没有空格。例如 "(char *)ptr",而不是 "(char *) ptr"。

  • 不要显式地将整数值与常量 0 或 \0 比较,或将指针值与常量 NULL 比较。例如,要验证计数数组 <ptr, cnt> 已初始化但没有元素,请写成

    if (!ptr || cnt)
    	BUG("empty array expected");
    and not:
    if (ptr == NULL || cnt != 0);
    	BUG("empty array expected");
  • 我们避免不必要地使用大括号。即

    if (bla) {
    	x = 1;
    }
    is frowned upon. But there are a few exceptions:
  • 当语句延伸超过几行时(例如,带有嵌套条件的 while 循环,或注释)。例如

    while (foo) {
    	if (x)
    		one();
    	else
    		two();
    }
    if (foo) {
    	/*
    	 * This one requires some explanation,
    	 * so we're better off with braces to make
    	 * it obvious that the indentation is correct.
    	 */
    	doit();
    }
  • 当条件语句有多个分支且其中一些需要大括号时,为了保持一致,即使是单行块也要用大括号括起来。例如

    if (foo) {
    	doit();
    } else {
    	one();
    	two();
    	three();
    }
  • 我们尽量避免在 "if" 语句的条件中进行赋值。

  • 尽量使你的代码易于理解。你可以放入注释,但当注释所描述的代码发生变化时,注释总是倾向于变得陈旧。通常,将一个函数拆分为两个会使代码意图更加清晰。

  • 多行注释的定界符应与文本分行显示。例如

    /*
     * A very long
     * multi-line comment.
     */
    Note however that a comment that explains a translatable string to
    translators uses a convention of starting with a magic token
    "TRANSLATORS: ", e.g.
    /*
     * TRANSLATORS: here is a comment that explains the string to
     * be translated, that follows immediately after it.
     */
    _("Here is a translatable string explained by the above.");
  • 双重否定往往比根本没有否定更难理解。

  • 在比较时有两种流派,特别是在循环内部。有些人喜欢把较不稳定的值放在左手边,较稳定的值放在右手边,例如,如果你有一个将变量 i 递减到下限的循环,

    while (i > lower_bound) {
    	do something;
    	i--;
    }
    Other people prefer to have the textual order of values match the
    actual order of values in their comparison, so that they can
    mentally draw a number line from left to right and place these
    values in order, i.e.
    while (lower_bound < i) {
    	do something;
    	i--;
    }
    Both are valid, and we use both.  However, the more "stable" the
    stable side becomes, the more we tend to prefer the former
    (comparison with a constant, "i > 0", is an extreme example).
    Just do not mix styles in the same part of the code and mimic
    existing styles in the neighbourhood.
  • 在将长逻辑行拆分为多行时有两种流派。有些人使用制表符将第二行及后续行向右推得足够远并对齐它们

          if (the_beginning_of_a_very_long_expression_that_has_to ||
    span_more_than_a_single_line_of ||
    the_source_text) {
                  ...
    while other people prefer to align the second and the subsequent
    lines with the column immediately inside the opening parenthesis,
    with tabs and spaces, following our "tabstop is always a multiple
    of 8" convention:
       if (the_beginning_of_a_very_long_expression_that_has_to ||
    span_more_than_a_single_line_of ||
    the_source_text) {
               ...
    Both are valid, and we use both.  Again, just do not mix styles in
    the same part of the code and mimic existing styles in the
    neighbourhood.
  • 拆分长逻辑行时,有些人会在二元运算符前换行,这样当你把头逆时针转动 90 度时,结果看起来像一棵解析树

       if (the_beginning_of_a_very_long_expression_that_has_to
    || span_more_than_a_single_line_of_the_source_text) {
    while other people prefer to leave the operator at the end of the
    line:
       if (the_beginning_of_a_very_long_expression_that_has_to ||
    span_more_than_a_single_line_of_the_source_text) {
    Both are valid, but we tend to use the latter more, unless the
    expression gets fairly complex, in which case the former tends to
    be easier to read.  Again, just do not mix styles in the same part
    of the code and mimic existing styles in the neighbourhood.
  • 在拆分长逻辑行时,在其他条件相同的情况下,优先在解析树中较高层级的运算符后进行拆分。也就是说,这样更好

    if (a_very_long_variable * that_is_used_in +
        a_very_long_expression) {
    	...
    than
    if (a_very_long_variable *
        that_is_used_in + a_very_long_expression) {
    	...
  • 一些聪明的技巧,比如在算术结构中使用 !! 运算符,可能会让其他人感到非常困惑。除非有令人信服的理由使用它们,否则请避免使用。

  • 使用 API。不,真的。我们有 strbuf(可变长度字符串)、带 ALLOC_GROW() 宏的多个数组、用于排序字符串列表的 string_list、名为 "struct decorate" 的哈希映射(映射结构体对象)等等。

  • 当你设计一个 API 时,请在向调用者公开 API 的头文件中记录其函数和结构。参考 "strbuf.h" 中的内容作为适当语调和详细程度的模型。

  • C 文件中第一个 #include,除了平台特定的 compat/ 实现和 sha1dc/ 外,必须是 <git-compat-util.h>。该头文件将其他头文件和源文件与平台差异隔离开来,例如必须以何种顺序包含哪些系统头文件,以及必须定义哪些 C 预处理器功能宏来触发我们对系统的某些预期特性。一个推论是,C 文件本身不应直接包含系统头文件。

    There are some exceptions, because certain group of files that
    implement an API all have to include the same header file that
    defines the API and it is convenient to include <git-compat-util.h>
    there.  Namely:
  • 在 "builtin/" 目录中包含 "builtin.h" 以获取 cmd_foo() 原型定义的内置命令实现,

  • 在 "t/helper/" 目录中包含 "t/helper/test-tool.h" 以获取 cmd__foo() 原型定义的测试辅助程序,

  • 在 "xdiff/" 目录中包含 "xdiff/xinclude.h" 以获取 xdiff 机制内部实现的 xdiff 实现,

  • 在 "t/unit-tests/" 目录中包含 "t/unit-tests/test-lib.h" 以获得单元测试框架的单元测试程序,以及

  • 在 "reftable/" 目录中包含 "reftable/system.h" 以获取 reftable 内部实现的实现 reftable 的源文件,

    are allowed to assume that they do not have to include
    <git-compat-util.h> themselves, as it is included as the first
    '#include' in these header files.  These headers must be the first
    header file to be "#include"d in them, though.
  • C 文件必须直接包含声明其使用的函数和类型的头文件,除非这些函数和类型是通过前述规则要求包含的头文件之一提供的。

  • 如果你正计划创建一个新命令,考虑先用 shell 或 perl 编写,以便语义变更可以被轻松修改和讨论。许多 Git 命令都是这样开始的,还有一些目前仍是脚本。

  • 避免在 Git 中引入新的依赖。这意味着你通常应避开 Git 核心命令集中尚未使用的脚本语言(除非你的命令与其明显分离,例如将随机 SCM-X 仓库转换为 Git 的导入器)。

  • 当我们向函数传递 <string, length> 对时,应尝试按此顺序传递。

  • 使用 Git 的 gettext 封装器使界面可翻译。参见 po/README 中的“标记待翻译字符串”。

  • 局部于给定源文件的变量和函数应标记为 "static"。对其他源文件可见的变量必须在头文件中用 "extern" 声明。但是,函数声明不应使用 "extern",因为这已经是默认设置。

  • 你可以使用快捷方式 GIT_DEBUGGER 围绕你的程序启动 gdb。运行 GIT_DEBUGGER=1 ./bin-wrappers/git foo 来直接使用 gdb,或运行 GIT_DEBUGGER="<debugger> <debugger-args>" ./bin-wrappers/git foo 来使用你自己的调试器和参数。示例:GIT_DEBUGGER="ddd --gdb" ./bin-wrappers/git log (见 bin-wrappers/wrap-for-bin.sh。)

  • 子系统 S 处理的主要数据结构被称为 struct S。对 struct S 进行操作的函数命名为 S_<verb>(),并且通常应接收一个指向 struct S 的指针作为第一个参数。例如

    struct strbuf;
    void strbuf_add(struct strbuf *buf, ...);
    void strbuf_reset(struct strbuf *buf);
    is preferred over:
    struct strbuf;
    void add_string(struct strbuf *buf, ...);
    void reset_strbuf(struct strbuf *buf);
  • 对于在结构体 S 上执行特定任务的函数,有几个通用的习惯用法名称

  • S_init() 初始化一个结构体,而不分配结构体本身。

  • S_release() 释放结构体的内容,而不为立即重用而重新初始化结构体,也不释放结构体本身。

  • S_clear() 等同于 S_release() 后跟 S_init(),使得结构体在清除后可直接使用。当提供 S_clear() 时,S_init() 不应分配需要再次释放的资源。

  • S_free() 释放结构体的内容并释放结构体本身。

  • 函数名称应清晰且具有描述性,准确反映其目的或行为。不增加有意义上下文的任意后缀可能会导致混淆,特别是对于代码库的新手。

    Historically, the '_1' suffix has been used in situations where:
  • 一个函数处理一组需要类似处理的元素中的一个。

  • 递归函数已与其设置阶段分离。

    The '_1' suffix can be used as a concise way to indicate these specific
    cases. However, it is recommended to find a more descriptive name wherever
    possible to improve the readability and maintainability of the code.
  • 位域定义时冒号周围不应有空格。例如

    unsigned my_field:1;
    unsigned other_field:1;
    unsigned field_with_longer_name:1;

针对 Perl 程序

  • 上述大部分 C 语言指南均适用。

  • 我们尝试支持 Perl 5.8.1 及更高版本 ("use Perl 5.008001")。

  • 强烈建议使用 use strict 和 use warnings。

  • 除非使用语句修饰符能使结果更容易理解,否则不要过度使用它们。

    1. 执行某事 …​ do_this() unless (condition);

    2. 执行其他事 …​

      is more readable than:
    3. 执行某事 …​ unless (condition) { do_this(); }

    4. 执行其他事 …​

      *only* when the condition is so rare that do_this() will be almost
      always called.
  • 我们尽量避免在 "if ()" 条件内部进行赋值。

  • 如果需要相关功能,请学习并使用 Git.pm。

针对 Python 脚本

  • 我们遵循 PEP-8 (https://peps.pythonlang.cn/pep-0008/)。

  • 作为最低要求,我们的目标是兼容 Python 2.7。

  • 在所需库不限制我们使用 Python 2 的情况下,我们也尝试兼容 Python 3.1 及更高版本。

程序输出

We make a distinction between a Git command's primary output and
output which is merely chatty feedback (for instance, status
messages, running transcript, or progress display), as well as error
messages. Roughly speaking, a Git command's primary output is that
which one might want to capture to a file or send down a pipe; its
chatty output should not interfere with these use-cases.
As such, primary output should be sent to the standard output stream
(stdout), and chatty output should be sent to the standard error
stream (stderr). Examples of commands which produce primary output
include `git log`, `git show`, and `git branch --list` which generate
output on the stdout stream.
Not all Git commands have primary output; this is often true of
commands whose main function is to perform an action. Some action
commands are silent, whereas others are chatty. An example of a
chatty action commands is `git clone` with its "Cloning into
'<path>'..." and "Checking connectivity..." status messages which it
sends to the stderr stream.
Error messages from Git commands should always be sent to the stderr
stream.

错误消息

  • 不要在单句错误消息的末尾加句号。

  • 不要仅仅因为是消息中的第一个词就将其大写("unable to open %s",而非 "Unable to open %s")。但 "SHA-3 not supported" 是可以的,因为第一个词大写的原因不是因为它在句首,而是因为该词即使出现在句中也会大写。

  • 先说明错误是什么("cannot open %s",而非 "%s: cannot open")。

  • 将错误的主体括在一对单引号内,例如 die(_("unable to open %s'"), path)

  • 除非有令人信服的理由不这样做,否则来自 porcelain 命令的错误消息应标记为待翻译,例如 die(_("bad revision %s"), revision)

  • 来自 plumbing 命令的错误消息有时是供机器使用的,不应标记为待翻译,例如 die("bad revision %s", revision)

  • BUG("message") 用于向开发人员传达特定错误,因此不应翻译。

外部可见名称

  • 对于配置变量名称,遵循现有约定

    1. 小节(section)名称指示受影响的子系统。

    2. 子小节(subsection)名称(如果有)指示为无限集合中的哪一个设置值。

    3. 变量名称描述了调整此开关的效果。

      The section and variable names that consist of multiple words are
      formed by concatenating the words without punctuation marks (e.g. `-`),
      and are broken using bumpyCaps in documentation as a hint to the
      reader.
      When choosing the variable namespace, do not use variable name for
      specifying possibly unbounded set of things, most notably anything
      an end user can freely come up with (e.g. branch names).  Instead,
      use subsection names or variable values, like the existing variable
      branch.<name>.description does.

编写文档

Most (if not all) of the documentation pages are written in the
AsciiDoc format in *.adoc files (e.g. Documentation/git.adoc), and
processed into HTML and manpages (e.g. git.html and git.1 in the
same directory).
The documentation liberally mixes US and UK English (en_US/UK)
norms for spelling and grammar, which is somewhat unfortunate.
In an ideal world, it would have been better if it consistently
used only one and not the other, and we would have picked en_US
(if you wish to correct the English of some of the existing
documentation, please see the documentation-related advice in the
Documentation/SubmittingPatches file).
In order to ensure the documentation is inclusive, avoid assuming
that an unspecified example person is male or female, and think
twice before using "he", "him", "she", or "her".  Here are some
tips to avoid use of gendered pronouns:
  • 更倾向于简洁、客观地描述抽象功能。例如

    --short

    以短格式输出。

    and avoid something like these overly verbose alternatives:
    --short

    使用此选项以短格式输出。

    --short

    你可以使用此选项获得短格式输出。

    --short

    偏好较短输出的用户可以……

    --short

    如果某人及/或程序想要更短的输出,他/她/他们/它能够……

    This practice often eliminates the need to involve human actors in
    your description, but it is a good practice regardless of the
    avoidance of gendered pronouns.
  • 当坚持这种风格变得尴尬时,在指代假设的用户时优先使用 "you",在讨论程序如何对用户做出反应时可能使用 "we"。例如

    You can use this option instead of `--xyz`, but we might remove
    support for it in future versions.
    while keeping in mind that you can probably be less verbose, e.g.
    Use this instead of `--xyz`. This option might be removed in future
    versions.
  • 如果你仍需指代第三人称单数的示例人物,可以使用 "singular they" 来避免 "he/she/him/her",例如

    A contributor asks their upstream to pull from them.
    Note that this sounds ungrammatical and unnatural to those who
    learned that "they" is only used for third-person plural, e.g.
    those who learn English as a second language in some parts of the
    world.
    Every user-visible change should be reflected in the documentation.
    The same general rule as for code applies -- imitate the existing
    conventions.

标记

Literal parts (e.g. use of command-line options, command names,
branch names, URLs, pathnames (files and directories), configuration and
environment variables) must be typeset as verbatim (i.e. wrapped with
backticks):
  `--pretty=oneline`
  `git rev-list`
  `remote.pushDefault`
  `http://git.example.com`
  `.git/config`
  `GIT_DIR`
  `HEAD`
  `umask`(2)
An environment variable must be prefixed with "$" only when referring to its
value and not when referring to the variable itself, in this case there is
nothing to add except the backticks:
  `GIT_DIR` is specified
  `$GIT_DIR/hooks/pre-receive`
Word phrases enclosed in `backtick characters` are rendered literally
and will not be further expanded. The use of `backticks` to achieve the
previous rule means that literal examples should not use AsciiDoc
escapes.
  Correct:
     `--pretty=oneline`
  Incorrect:
     `\--pretty=oneline`
Placeholders are spelled in lowercase and enclosed in
angle brackets surrounded by underscores:
  _<file>_
  _<commit>_
If a placeholder has multiple words, they are separated by dashes:
  _<new-branch-name>_
  _<template-directory>_
When needed, use a distinctive identifier for placeholders, usually
made of a qualification and a type:
  _<git-dir>_
  _<key-id>_

字符也由下划线包围:LF, CR, CR/LF, NUL, EOF

Git's Asciidoc processor has been tailored to treat backticked text
as complex synopsis. When literal and placeholders are mixed, you can
use the backtick notation which will take care of correctly typesetting
the content.
  `--jobs <n>`
  `--sort=<key>`
  `<directory>/.git`
  `remote.<name>.mirror`
  `ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>`

作为副作用,反引号括起来的占位符会被正确排版,但不推荐这种风格。

When documenting multiple related `git config` variables, place them on
a separate line instead of separating them by commas.  For example, do
not write this:
  `core.var1`, `core.var2`::
Description common to `core.var1` and `core.var2`.

相反,应这样写:core.var1:: core.var2:: core.var1core.var2 共同的描述。

大纲语法

The synopsis (a paragraph with [synopsis] attribute) is automatically
formatted by the toolchain and does not need typesetting.
A few commented examples follow to provide reference when writing or
modifying command usage strings and synopsis sections in the manual
pages:
Possibility of multiple occurrences is indicated by three dots:
  <file>...
  (One or more of <file>.)
Optional parts are enclosed in square brackets:
  [<file>...]
  (Zero or more of <file>.)
An optional parameter needs to be typeset with unconstrained pairs
  [<repository>]
--exec-path[=<path>]
(Option with an optional argument.  Note that the "=" is inside the
brackets.)
[<patch>...]
(Zero or more of <patch>.  Note that the dots are inside, not
outside the brackets.)
Multiple alternatives are indicated with vertical bars:
  [-q | --quiet]
  [--utf8 | --no-utf8]
Use spacing around "|" token(s), but not immediately after opening or
before closing a [] or () pair:
  Do: [-q | --quiet]
  Don't: [-q|--quiet]
Don't use spacing around "|" tokens when they're used to separate the
alternate arguments of an option:
   Do: --track[=(direct|inherit)]
   Don't: --track[=(direct | inherit)]
Parentheses are used for grouping:
  [(<rev>|<range>)...]
  (Any number of either <rev> or <range>.  Parens are needed to make
  it clear that "..." pertains to both <rev> and <range>.)
[(-p <parent>)...]
(Any number of option -p, each with one <parent> argument.)
git remote set-head <name> (-a|-d|<branch>)
(One and only one of "-a", "-d" or "<branch>" _must_ (no square
brackets) be provided.)
And a somewhat more contrived example:
  --diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]
  Here "=" is outside the brackets, because "--diff-filter=" is a
  valid usage.  "*" has its own pair of brackets, because it can
  (optionally) be specified only when one or more of the letters is
  also provided.
A note on notation:
 Use 'git' (all lowercase) when talking about commands i.e. something
 the user would type into a shell and use 'Git' (uppercase first letter)
 when talking about the version control system and its properties.
If some place in the documentation needs to typeset a command usage
example with inline substitutions, it is fine to use +monospaced and
inline substituted text+ instead of `monospaced literal text`, and with
the former, the part that should not get substituted must be
quoted/escaped.