Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
-
2.54.0
2026-04-20
-
2.53.0
2026-02-02
-
2.52.0
2025-11-17
- 2.50.1 → 2.51.2 no changes
-
2.50.0
2025-06-16
- 2.49.1 no changes
-
2.49.0
2025-03-14
- 2.46.2 → 2.48.2 no changes
-
2.46.1
2024-09-13
- 2.45.1 → 2.46.0 no changes
-
2.45.0
2024-04-29
- 2.44.1 → 2.44.4 no changes
-
2.44.0
2024-02-23
- 2.43.3 → 2.43.7 no changes
-
2.43.2
2024-02-13
-
2.43.1
2024-02-09
-
2.43.0
2023-11-20
- 2.42.2 → 2.42.4 no changes
-
2.42.1
2023-11-02
- 2.41.1 → 2.42.0 no changes
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 no changes
-
2.40.0
2023-03-12
- 2.39.4 → 2.39.5 no changes
-
2.39.3
2023-04-17
- 2.39.1 → 2.39.2 no changes
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 no changes
-
2.38.0
2022-10-02
- 2.37.3 → 2.37.7 no changes
-
2.37.2
2022-08-11
- 2.36.3 → 2.37.1 no changes
-
2.36.2
2022-06-23
- 2.35.1 → 2.36.1 no changes
-
2.35.0
2022-01-24
- 2.34.1 → 2.34.8 no changes
-
2.34.0
2021-11-15
- 2.33.2 → 2.33.8 no changes
-
2.33.1
2021-10-12
- 2.32.1 → 2.33.0 no changes
-
2.32.0
2021-06-06
- 2.31.1 → 2.31.8 no changes
-
2.31.0
2021-03-15
- 2.30.1 → 2.30.9 no changes
-
2.30.0
2020-12-27
- 2.29.1 → 2.29.3 no changes
-
2.29.0
2020-10-19
- 2.28.1 no changes
-
2.28.0
2020-07-27
- 2.27.1 no changes
-
2.27.0
2020-06-01
- 2.26.1 → 2.26.3 no changes
-
2.26.0
2020-03-22
- 2.25.1 → 2.25.5 no changes
-
2.25.0
2020-01-13
- 2.24.1 → 2.24.4 no changes
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 no changes
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 no changes
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 no changes
-
2.21.0
2019-02-24
- 2.20.1 → 2.20.5 no changes
-
2.20.0
2018-12-09
- 2.19.3 → 2.19.6 no changes
-
2.19.2
2018-11-21
- 2.19.1 no changes
-
2.19.0
2018-09-10
- 2.18.1 → 2.18.5 no changes
-
2.18.0
2018-06-21
- 2.17.1 → 2.17.6 no changes
-
2.17.0
2018-04-02
-
2.16.6
2019-12-06
-
2.15.4
2019-12-06
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
-
2.12.5
2017-09-22
- 2.10.5 → 2.11.4 no changes
-
2.9.5
2017-07-30
-
2.8.6
2017-07-30
- 2.7.6 no changes
-
2.6.7
2017-05-05
- 2.5.6 no changes
-
2.4.12
2017-05-05
-
2.3.10
2015-09-28
-
2.2.3
2015-09-04
-
2.1.4
2014-12-17
-
2.0.5
2014-12-17
概述
git rebase [-i | --interactive] [<选项>] [--exec <命令>] [--onto <新基础> | --keep-base] [<上游仓库> [<分支>]] git rebase [-i | --interactive] [<选项>] [--exec <命令>] [--onto <新基础>] --root [<分支>] git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
描述
将一系列提交移植到不同的起点上。你也可以用 git rebase 对提交重新排序或合并:参见下文 INTERACTIVE MODE 了解如何操作。
例如,假设你在如下历史中的 topic 分支上工作,并希望“追上” master 分支上的工作。
A---B---C topic
/
D---E---F---G master
你希望将 topic 自从从 master 分叉以来所做的提交(即 A、B、C)移植到当前 master 之上。你可以在检出 topic 分支时运行 git rebase master 来实现。如果你在另一个分支上想对 topic 进行 rebase,git rebase master topic 相当于 git checkout topic && git rebase master 的快捷写法。
A'--B'--C' topic
/
D---E---F---G master
如果在此过程中出现合并冲突,git rebase 会停在第一个有问题的提交处并留下冲突标记。此时你可以选择以下操作之一:
-
如果出现冲突,
gitrebase会在第一个有问题的提交处停止,并在树中留下冲突标记。 你可以用gitdiff找到这些标记 (<<<<<<),并进行编辑以解决冲突。 每编辑一个文件,都需要告诉 Git 冲突已被解决,通常可以用git rebase --continue
-
停止
gitrebase并将分支恢复到原始状态:git rebase --abort
-
跳过引发合并冲突的提交:
$ git rebase -i Y Z
如果未指定 <upstream>,将使用 branch.<name>.remote 和 branch.<name>.merge 选项中配置的上游(详见 git-config[1]),并假定使用 `--fork-point`选项。 如果您当前不在任何分支上,或者当前分支没有配置上游,变基操作会中止。
下面是对 git rebase <upstream> 所做事情的简化描述:
-
列出当前分支自从从 <upstream> 分叉以来、且在 <upstream> 中没有等价提交的所有提交。
-
以类似
gitcheckout--detach<upstream> 的方式检出 <upstream>。 -
按顺序逐个重放这些提交。这类似于对每个提交运行一次
gitcherry-pick<commit>。关于如何处理合并,参见 REBASING MERGES。 -
以类似
gitcheckout-B<branch> 的方式更新你的分支,使其指向最终提交。
|
Note
|
如果在重置过程中使用了其他写入伪引用的命令(例如 git reset),就不能保证 ORIG_HEAD 在重置结束时仍然指向前一个分支的分支提示。不过,使用当前分支的 引用日志(即 @{1},参见 gitrevisions[7])可以访问前一个分支的分支提示。
|
使用 --onto 移植主题分支
下面是如何使用 rebase --onto 将基于一个分支的特性分支移植到另一个分支,以假装特性分支是从后一个分支分叉而来。
首先,我们假设 topic 基于 next 分支。 例如,topic 中开发的功能依赖于 next 中的某些功能。
o---o---o---o---o master
\
o---o---o---o---o next
\
o---o---o topic
我们想让 topic 从分支 master 中分叉出来;例如,因为 topic 所依赖的功能已经合并到了更稳定的分支 master 中。我们希望我们的提交树看起来像这样 :
o---o---o---o---o master
| \
| o'--o'--o' topic
\
o---o---o---o---o next
我们可以使用以下命令来获取 :
git rebase --onto master next topic
--onto 选项的另一个示例是重新基点分支的一部分。 如果我们有以下情况:
H---I---J topicB
/
E---F---G topicA
/
A---B---C---D master
那么命令
git rebase --onto master topicA topicB
将导致 :
H'--I'--J' topicB
/
| E---F---G topicA
|/
A---B---C---D master
这在主题 B 不依赖于主题 A 的情况下非常有用。
也可以用变基删除一系列提交。 如果我们遇到以下情况 :
E---F---G---H---I---J topicA
那么命令
git rebase --onto topicA~5 topicA~3 topicA
将导致删除 F 和 G 项:
E---H'---I'---J' topicA
如果 F 和 G 在某些方面有缺陷,或者不应该是 topicA 的一部分,这一点就很有用。 请注意,--onto 参数和 <upstream> 参数可以是任何有效的提交。
模式选项
本节中的选项不能与任何其他选项一起使用,包括不能相互使用:
- --continue
-
解决合并冲突后,重新启动重新分区进程。
- --skip
-
跳过当前补丁,重新启动重新分区进程。
- --abort
-
终止变基操作并将 HEAD 重置为原始分支。如果在启动变基操作时提供了 <分支>,那么
HEAD将被重置为 <分支>。否则,HEAD将被重置为启动变基操作时的位置。 - --quit
-
放弃变基操作,但
HEAD不会重置回原始分支。索引和工作区也会因此保持不变。如果使用--autostash创建了临时贮藏条目,它将被保存到贮藏列表中。 - --edit-todo
-
在交互式变基过程中编辑待办事项列表。
- --show-current-patch
-
在交互式变基或因冲突而停止变基时显示当前补丁。相当于
gitshowREBASE_HEAD。
选项
示例参见上文“使用 --onto 移植主题分支”。
- --keep-base
-
将创建新提交的起点设为 <upstream> 和 <branch> 的合并库。运行
gitrebase--keep-base<upstream> <branch> 相当于运行gitrebase--reapply-cherry-picks--no-fork-point--onto<upstream>...<branch> <upstream> <branch> 。该选项适用于在上游分支上开发功能的情况。在开发功能的过程中,上游分支可能会前进,这时最好的办法可能不是继续在上游分支上重新加载,而是保持基本提交不变。由于基本提交保持不变,该选项意味着
--reapply-cherry-picks,以避免丢失提交。虽然该选项和
--fork-point都能找到 <upstream> 和 <branch> 之间的合并基数,但该选项使用合并基数作为创建新提交的_起点_,而 `--fork-point`则使用合并基数来确定将被重定向的_提交集_。另请参阅下面的不兼容选项。
- <上游仓库>
-
要与之比较的上游分支。 可以是任何有效的提交,而不仅仅是现有的分支名称。默认为当前分支配置的上游分支。
- <分支>
-
工作分支;默认为
HEAD。 - --apply
-
使用应用策略来变基(内部调用
git-am)。 一旦合并后端处理了应用后端所做的一切,这个选项将来可能就不再适用了。另请参阅下面的不兼容选项。
- --empty=(drop|keep|stop)
-
重新应用任何上游提交中所有干净的拣选,而不是先发制人地丢弃它们。(如果这些提交在重排后成为空提交,因为它们包含了上游修改的子集,则对它们的行为由
--empty标志控制。)需要注意的是,开始时为空的提交会被保留(除非指定了
--no-keep-empty),而干净的 cherry-picks 提交(由gitlog--cherry-mark...)会被检测到并作为第一步被丢弃(除非通过了 --reapply-cherry-picks`或 `--keep-base)。另请参阅下面的不兼容选项。
- --no-keep-empty
- --keep-empty
-
不在结果中保留重置前开始为空的提交(即不改变父提交的任何内容)。 默认情况下保留开始时为空的提交,因为创建此类提交需要向
gitcommit传递--allow-empty覆盖标志,表明用户非常有意地创建此类提交,因此希望保留它。使用这个标签的情况可能很少,因为你只需启动交互式变基,并删除与你不想要的提交对应的行,就能删除开始时为空的提交。 该标签是一种方便的快捷方式,比如当外部工具生成许多空提交,而你希望将它们全部删除时。
如果提交开始时不是空的,但重定向后变成空的,参阅
--empty标志。另请参阅下面的不兼容选项。
- --reapply-cherry-picks
- --no-reapply-cherry-picks
-
重新应用任何上游提交中所有干净的拣选,而不是先发制人地丢弃它们。(如果这些提交在重排后成为空提交,因为它们包含了上游修改的子集,则对它们的行为由
--empty标志控制。)如果没有
--keep-base(或给出了--no-reapply-cherry-picks),这些提交将被自动放弃。 由于这需要读取所有上游提交,对于需要读取大量上游提交的仓库来说,代价可能会很高。使用 merge 后端时,每次丢弃提交都会发出警告(除非给出--quiet)。除非将advice.skippedCherryPicks设为 false,否则也会发出警告(参见 git-config[1])。--reapply-cherry-picks允许变基操作放弃读取所有上游提交,从而可能提高性能。另请参阅下面的不兼容选项。
- --allow-empty-message
-
无操作。 过去,重写带空信息的提交会失败,而该选项会覆盖这一行为,允许重写带空信息的提交。 现在,带空信息的提交不会导致重定向失败。
另请参阅下面的不兼容选项。
- -m
- --merge
-
使用合并策略重定向(默认)。
请注意,变基合并是通过在 <上游> 分支上重放工作分支的每次提交来实现的。 因此,当发生合并冲突时,被报告为 ours 的一方是迄今为止以 <上游> 为起点的重定向系列,而 theirs 则是工作分支。 换句话说,双方是对调的。
另请参阅下面的不兼容选项。
- -s <策略>
- --strategy=<策略>
-
使用给定的合并策略,而不是默认的
ort。暗指--merge。由于
gitrebase会使用给定的策略在 <上游> 分支之上重复工作分支的每次提交,因此使用ours策略只会清空 <分支> 中的所有补丁,这没有什么意义。另请参阅下面的不兼容选项。
- -X <策略选项>
- --strategy-option=<策略选项>
-
将 <策略选项> 传递给合并策略。 这意味着
--merge,如果没有指定策略,则是--sort。 请注意 ours 和 theirs 的颠倒,就像上面的 `-m`选项一样。另请参阅下面的不兼容选项。
-
--rerere-autoupdate -
--no-rerere-autoupdate -
在 rerere 机制重用当前冲突的记录解析来更新工作区中的文件后,允许它也用解析的结果来更新索引。 --no-rerere-autoupdate`是一个很好的方法,在用单独的 `git add 提交结果到索引之前,可以反复检查
rerere所做的事情,并抓住潜在的错误合并。
- -S[<keyid>]
- --gpg-sign[=<键 ID>]
- --no-gpg-sign
-
GPG 签名提交。
keyid参数是可选的,默认为提交者身份;如果指定了,则必须与选项相连,不加空格。--no-gpg-sign用于还原commit.gpgSign配置变量和先前的--gpg-sign。 - -q
- --quiet
-
静默。暗含
--no-stat选项。 - -v
- --verbose
-
详尽输出。暗含
--stat选项。 - --stat
-
是否显示自上次 rebase 以来上游发生了哪些变化的 diffstat。默认值为 false。
- -n
- --no-stat
-
不要将差异状态作为变基过程的一部分。
- --no-verify
-
该选项会绕过 pre-rebase 钩子。 另请参阅 githooks[5]。
- --verify
-
允许运行 pre-rebase 钩子,这是默认选项。 该选项可用于覆盖
--no-verify。 另请参见 githooks[5]。 - -C<n>
-
确保每次更改前后至少有 <n> 行周围上下文匹配。 如果周围的上下文行数较少,则必须全部匹配。 默认情况下,不会忽略任何上下文。 暗指
--apply。另请参阅下面的不兼容选项。
- --no-ff
- --force-rebase
- -f
-
单独重放所有重定向的提交,而不是快进不变的提交。 这样就能确保重建分支的整个历史都是由新提交组成的。
在还原主题分支合并后,你可能会发现这很有帮助,因为该选项会用新提交的内容重新创建主题分支,这样就可以成功地重新合并,而无需 “恢复原状”(详见如何还原故障合并)。
- --fork-point
- --no-fork-point
-
在计算哪些提交由 <分支> 引入时,使用引用日志在 <上游仓库> 和 <分支> 之间找到更好的共同祖先。
当启用
--fork-point时,将使用 fork_point 而不是 <上游仓库> 来计算要重置的提交集,其中 fork_point 是gitmerge-base--fork-point<上游仓库> <分支> 命令的结果(参见 git-merge-base[1])。 如果 fork_point 最终为空,<上游仓库> 将作为备用。如果在命令行中提供了 <上游仓库> ` 或 `--keep-base 参数,则默认为
--no-fork-point,否则默认为--fork-point。另请参阅 git-config[1] 中的rebase.forkpoint。如果你的分支基于 <上游仓库>,但 <上游仓库> 被回退了,而你的分支包含了被删除的提交,那么可以使用
--keep-base选项来从你的分支中删除那些提交。另请参阅下面的不兼容选项。
- --ignore-whitespace
-
在尝试协调差异时空格的差异。目前,每个后端都实现了对此行为的近似处理:
- --whitespace=<选项>
-
这个标志被传递给应用补丁的
gitapply程序(参阅 git-apply[1])。它隐含了--apply。另请参阅下面的不兼容选项。
- --committer-date-is-author-date
-
不使用当前时间作为提交者日期,而是使用被重定向的提交的作者日期作为提交者日期。该选项暗含
--force-rebase选项。Warning历史遍历机制假设提交时间戳是非递减的。你应当考虑是否确实需要使用此选项。此后,你应仅在这种情况下使用它:当你要 rebase 的基准提交(以提交日期计)比你要应用的最旧提交(以作者日期计)还要更早时,用它来覆盖提交者日期。 - --ignore-date
- --reset-author-date
-
不使用原始提交的作者日期,而使用当前时间作为重建提交的作者日期。 此选项暗含
--force-rebase选项。另请参阅下面的不兼容选项。
- --signoff
-
在所有重写的提交中添加
Signed-off-by尾注。请注意,如果给定了--interactive,则只有标记为被选中、编辑或重写的提交才会添加尾注。另请参阅下面的不兼容选项。
- 尾注
-
将给定的尾注附加到每个变基的提交消息中,通过 git-interpret-trailers[1] 处理。此选项隐含
--force-rebase。另请参阅下面的不兼容选项。
- -i
- --interactive
-
列出即将重写的提交列表。 让用户在重写前编辑该列表。 这种模式也可用于拆分提交(见下文的拆分提交)。
提交列表格式可通过设置配置选项 rebase.instructionFormat 进行更改。 自定义的指令格式会自动在格式前加上长提交哈希值。
另请参阅下面的不兼容选项。
- -r
- --rebase-merges[=(rebase-cousins|no-rebase-cousins)]
- --no-rebase-merges
-
默认情况下,变基操作会简单地从待办事项列表中删除合并提交,并将被重置的提交放入一个单一的线性分支中。 使用
--rebase-merges后,变基操作会通过重新创建合并提交,尝试保留要被重置的提交中的分支结构。在这些合并提交中,任何已解决的合并冲突或手动修正都必须手动解决/重新应用。--no-rebase-merges可以用来抵消rebase.rebaseMerges配置选项和之前的 `--rebase-merges 选项。重定向合并时,有两种模式:
rebase-cousins和no-rebase-cousins。如果未指定模式,则默认为no-rebase-cousins。在no-rebase-cousins模式下,没有 <上游仓库> 作为直接祖先的提交将保留其原始分支点,也就是说,被 git-log[1] 的--ancestry-path选项排除在外的提交将默认保留其原始祖先。在rebase-cousins模式下,此类提交会被重定向到 <上游仓库>(或是`<onto>`,如果指定了)。目前只能使用
ort合并策略重新创建合并提交;只有通过明确的execgitmerge-s<strategy> [...] 命令才能使用不同的合并策略。另请参阅下面的重置合并和不兼容选项。
- -x <命令>
- --exec <命令>
-
在最终历史记录中创建提交的每一行后添加 "exec <命令>"。<命令> 将被解释为一个或多个 shell 命令。任何失败的命令都会中断重置,退出代码为 1。
您可以通过使用一个包含多个命令的
--exec实例来执行多个命令:git rebase -i --exec "cmd1 && cmd2 && ..."
或给出多个
--exec:git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
如果使用了
--autosquash,则不会为中间提交附加exec行,而只会出现在每个 squash/fixup 系列的末尾。它在内部使用
--interactive机制,但也可以在没有显式--interactive的情况下运行。另请参阅下面的不兼容选项。
- --root
-
重置从 <分支> 到的所有提交,而不是用 <上游分支> 来限制它们。 这样就可以重定向分支上的根提交。
另请参阅下面的不兼容选项。
- --autosquash
- --no-autosquash
-
自动将带有特殊格式信息的提交压制到正在重建的前提交中。如果提交信息以 "squash!"、"fixup!" 或 "amend!" 开头,则主题行的其余部分将作为提交说明符,如果与主题行或该提交的哈希值相匹配,则与之前的提交相匹配。如果没有完全匹配的提交,则会考虑与提交主题开头的指定符匹配。
在 rebase todo 列表中,squash、fixup 和 amend 提交的操作将分别从
pick改为squash、fixup或fixup-C,而且它们会被移到所修改的提交之后。在继续之前,可以使用--interactive选项查看和编辑待办事项列表。建议使用 git-commit[1] 的
--squash、--fixup、--fixup=amend:或--fixup=reword:选项来创建带有压扁标记的提交。将配置变量
rebase.autoSquash设为 true,可启用交互式变基默认自动清空功能。可以使用 `--no-autosquash`选项来覆盖该设置。另请参阅下面的不兼容选项。
- --autostash
- --no-autostash
-
在操作开始前自动创建临时贮藏条目,并在操作结束后应用它。 这意味着你可以在脏工作区上运行变基操作。 不过,请谨慎使用:成功重储后的最终贮藏应用可能会导致非实质性冲突。
- --reschedule-failed-exec
- --no-reschedule-failed-exec
-
自动重新安排执行失败的
exec命令。这只有在交互模式下(或提供了--exec选项时)才有意义。一旦启动变基程序,该选项就会生效。它会在整个变基过程和中保留,依次基于初始
gitrebase所提供的命令行选项、rebase.rescheduleFailedExec配置(参见 git-config[1] 或下文的“配置”),或者默认为 false。为整个 rebase 记录该选项是为了方便起见。否则,当调用
gitrebase--continue时,在开始时显式的--no-reschedule-failed-exec会被rebase.rescheduleFailedExec=true配置覆盖。目前,不能向gitrebase--continue传递--[no-]reschedule-failed-exec。 - --update-refs
- --no-update-refs
-
自动强制更新任何指向正在重定向的提交的分支。任何在工作区中检出的分支都不会以这种方式更新。
如果设置了配置变量
rebase.updateRefs, 则可使用此选项覆盖并禁用此设置。另请参阅下面的不兼容选项。
不兼容选项
下列选项:
-
--apply
-
--whitespace
-
-C
与下列选项不兼容:
-
--merge
-
--strategy
-
--strategy-option
-
--autosquash
-
--rebase-merges
-
--interactive
-
--exec
-
--no-keep-empty
-
--empty=
-
--[no-]reapply-cherry-picks when used without --keep-base
-
--update-refs
-
--root when used without --onto
-
--trailer
此外,以下几对选项是不兼容的:
-
--keep-base and --onto
-
--keep-base and --root
-
--fork-point and --root
行为差异
git rebase 有两个主要的后台:‘应用’ 和 ‘合并’(‘应用’ 后台曾被称为 am 后台,但这个名字看起来像动词而非名词,因此引起了混淆)。 此外,‘合并’ 后台曾被称为交互式后台,但现在也用于非交互式情况。 两者都是根据各自的底层功能重新命名的)。这两个后台在行为方式上有一些微妙的区别:
空提交
不幸的是,‘应用’ 后台会丢弃故意为空的提交,即开始时为空的提交,不过这种情况在实践中并不多见。 它还会丢弃变为空的提交,而且没有控制这种行为的选项。
默认情况下,‘合并’ 后台会保留故意为空的提交(不过,如果使用 -i 选项,这些提交会在待办事项列表编辑器中标记为空,或者使用 --no-keep-empty 自动删除)。
与应用后端类似,合并后端默认情况下也会丢弃变为空的提交,除非指定了 -i 或 --interactive 选项(在这种情况下,合并会停止并询问用户该怎么做)。 合并后端还有一个 --empty=(drop|keep|ask) 选项,用于改变处理变为空的提交的行为。
目录重命名检测
由于缺乏准确的目录树信息(利用补丁中的有限信息构建假祖先),‘应用’ 后台禁用了目录重命名检测。 禁用目录重命名检测意味着,如果历史记录的一方重命名了一个目录,而另一方在旧目录中添加了新文件,那么新文件就会被留在旧目录中,而不会在重新编排时发出任何警告,提醒您可能需要将这些文件移到新目录中。
目录重命名检测与 ‘合并’ 后台协同工作,在这种情况下会向你发出警告。
上下文
‘应用’ 后台的工作方式是创建一系列补丁(在内部调用 format-patch),然后依次应用这些补丁(在内部调用 am)。 补丁由多个块组成,每个块包含行号、上下文区域和实际更改。 行号的获取必须谨慎,因为另一方很可能在文件中插入或删除了更早的行。 上下文区域的目的是帮助找到如何调整行号,以便将更改应用到正确的行上。 但是,如果代码的多个区域有相同的上下文行,就可能选错。 在现实世界中,这种情况曾导致提交被错误地重新应用,而没有报告任何冲突。 将 diff.context 设置为更大的值可能会避免此类问题,但会增加发生虚假冲突的几率(因为需要更多行匹配的上下文才能应用)。
‘合并’ 后台使用每个相关文件的完整副本,从而避免了此类问题。
给冲突标记贴标签
当出现内容冲突时,合并机制会尝试在每一方的冲突标记上标注内容来源的提交。 由于 ‘应用’ 后台丢弃了关于重建的提交及其父提交的原始信息(而是根据生成的补丁中的有限信息生成新的假提交),因此无法识别这些提交,而只能使用提交摘要。 此外,当 merge.conflictStyle 设置为 diff3 或 zdiff3 时,‘应用’ 后端将使用 "constructed merge base"(构建的合并基础)来标注来自合并基础的内容,因此不会提供任何关于合并基础提交的信息。
‘合并’ 后台使用历史上双方的完整提交,因此没有这些限制。
钩子
传统上,‘应用’ 后台并不调用提交后(post-commit)钩子,而 ‘合并’ 后台却调用了。 虽然 ‘合并’ 后台已取消了其输出,但两者都调用了检出后(post-checkout)钩子。 此外,这两个后端都只调用了变基操作的起点提交,而不是中间提交或最终提交的检出后(post-checkout)钩子。 在每种情况下,调用这些钩子都是偶然的,而不是设计出来的(两个后台最初都是以 shell 脚本的形式实现的,碰巧调用了其他会调用钩子的命令,如 git checkout 或 git commit)。 这两个后台应该具有相同的行为,但目前还不完全清楚哪一个才是正确的。 我们将来可能会让变基操作停止调用这些钩子。
可中断性
如果用户在错误的时间按下 Ctrl-C 试图终止重置,重置就会进入无法通过后续的 git rebase --abort 终止的状态。 ‘合并’ 后台似乎不存在同样的缺陷。 (详见 https://lore.kernel.org/git/20200207132152.GC2868@szeder.dev/)
合并战略
合并机制( git merge 和 git pull 命令)允许用 -s 选项来选择后端’合并策略'。 一些策略也可以采取自己的选项,可以通过给 git merge 和/或 git pull 的 -X<选项> 参数来传递。
-
ort -
这是拉取或合并一个分支时的默认合并策略。 这个策略只能使用三方合并算法解决两个头。 当有一个以上的共同祖先可用于三方合并时,它会创建一个共同祖先的合并树,并将其作为三方合并的参考树。 据报道,通过对Linux 2.6内核开发历史中的实际合并提交的测试,这导致了较少的合并冲突,而不会引起错误的合并。 此外,这个策略可以检测并处理涉及重命名的合并。 它并不使用检测到的副本。 这个算法的名字是一个缩写("Ostensibly Recursive’s Twin"),来自于它是作为以前的默认算法`recursive`的替代而编写的。
当路径是一个子模块时,如果合并一侧使用的子模块提交是另一侧使用的子模块提交的后代,Git 会尝试快进到该后代。否则,Git 会将该情况视为冲突;若存在,会建议一个同时为冲突双方提交后代的子模块提交作为解决方案。
ort策略可以采取以下选项:-
ours -
这个选项通过倾向于 "我们" 的版本,迫使冲突的猎物被自动解决。 另一棵目录树上与我们这边不冲突的变化会反映在合并结果中。 对于一个二进制文件,整个内容都来自我们这边。
这不应该与 "我们的" 合并策略相混淆,后者甚至根本不看另一棵目录树包含了什么。 它抛弃了其他树所做的一切,宣布 "我们的" 历史包含了其中所发生的一切。
-
theirs -
这与 "我们的" 相反;注意,与 "我们的" 不同,没有 "他们的" 合并策略来混淆这个合并选项。
-
ignore-space-change -
ignore-all-space -
ignore-space-at-eol -
ignore-cr-at-eol -
为了进行三方合并,将具有指定类型的空白变化的行视为没有变化。 但混合了其他改动的行的空白改动不会被忽略。 参见git-diff[1]
-b,-w,--ignore-space-at-eol, 和--ignore-cr-at-eol。-
如果 "他们的" 版本只在一行中引入了空白的变化,则使用 "我们的" 版本;
-
如果 "我们的" 版本引入了空白的变化,但 "他们的" 版本包括一个实质性的变化,则使用 "他们的" 版本;
-
否则,合并将以常规方式进行。
-
-
renormalize -
在解决三方合并时,这将对一个文件的所有三个阶段运行虚拟检出和检入。 这个选项是为了在合并具有不同清洁过滤器或行末规范化规则的分支时使用。 详情见 gitattributes[5] 中的 "合并具有不同检入/检出属性的分支"。
-
no-renormalize -
禁用
renormalize选项。 这覆盖了merge.renormalize配置变量。 - --find-renames[=<n>]
-
开启重名检测,可选择设置相似度阈值。 这是默认的。这覆盖了
merge.renames配置变量。 参见git-diff[1]--find-renames。 - rename-threshold=<n>
-
废弃的,
find-renames=<n> 的同义词。 -
no-renames -
关闭重名检测。这覆盖了
merge.renames的配置变量。 参见git-diff[1]--no-renames。 -
histogram -
废弃的,
diff-algorithm=patience的同义词。 -
patience -
废弃的,
diff-algorithm=patience的同义词。 - diff-algorithm=[histogram|minimal|myers|patience]
-
在合并时使用不同的差异算法,这可以帮助避免由于不重要的匹配行(比如不同函数的大括号)而发生的错误合并。 参见git-diff[1]
--diff-algorithm。 注意,ort特定diff-algorithm=histogram,而`recursive`默认为`diff.algorithm`配置设置。 - subtree[=<路径>]
-
这个选项是 子树 策略的更高级形式,该策略对两棵树在合并时必须如何移位以相互匹配进行猜测。 相反,指定的路径是前缀(或从开始剥离),以使两棵树的形状相匹配。
-
-
recursive -
它现在是
ort的同义词。它在 v2.49.0 之前是一个替代实现,但从 v2.50.0 起被重定向为表示ort。此前的 recursive 策略曾在 Git v0.99.9k 至 v2.33.0 期间作为合并两个 head 的默认策略。 -
resolve -
这只能用三方合并算法解决两个头(即当前分支和你拉来的另一个分支)。 它试图仔细检测纵横交错的合并歧义。 它不处理重名。
-
octopus -
这可以解决有两个以上头的情况,但拒绝做复杂的合并,需要手动解决。 它主要是用于将主题分支头捆绑在一起。 当拉动或合并一个以上的分支时,这是默认的合并策略。
-
ours -
这可以解决任何数量的头,但合并的结果总是当前分支头的树,有效地忽略了所有其他分支的变化。 它是用来取代侧边分支的旧开发历史的。 注意,这与 recursive 合并策略的-Xours选项不同。
-
subtree -
这是一个修正的
ort策略。当合并树A和B时,如果B对应于A的子树,B首先被调整为与A的树结构相匹配,而不是在同一级别读取树。这种调整也是针对共同祖先树进行的。
对于使用三方合并的策略(包括默认的 ort 策略),如果在两个分支上都做了修改,但后来在其中一个分支上被撤销,那么这个修改就会出现在合并后的结果中;有些人觉得这种行为令人困惑。 出现这种情况是因为在执行合并时只考虑头部和合并基数,而不是单个提交。 因此,合并算法认为被恢复的修改根本就没有变化,而是用被修改的版本来代替。
注释
您应该了解在共享的仓库中使用 git rebase 的影响。 另请参阅下面的从上游重建中恢复。
在运行变基命令时,如果存在 pre-rebase (变基前)钩子,它会首先执行该钩子。 您可以使用此钩子进行正确性检查,并在不合适时拒绝重置。 有关示例,请参阅模板 pre-rebase(变基前) 钩子脚本。
完成后,<分支> 将成为当前分支。
交互模式
交互式重定向意味着你有机会编辑被重定向的提交。 你可以重新排列提交的顺序,也可以删除它们(剔除坏的或不需要的补丁)。
互动模式就是为这种工作流程设计的:
-
灵机一动
-
敲代码
-
编写提交系列
-
提交
其中第 2 点由以下几个实例组成
a) 常规使用
-
完成值得提交的事情
-
提交
b) 独立修复
-
发现有什么东西没有用
-
解决这个问题
-
提交
有时,b.2.中修正的内容无法修正到它所修正的并不完美的提交中,因为该提交深埋在一系列补丁中。 这正是交互式变基的用途:在大量的 "a" 和 "b" 之后使用它,重新排列和编辑提交,将多个提交合并为一个提交。
从您希望保留原样的最后一次提交开始:
git rebase -i <本次提交后>
编辑器会弹出当前分支的所有提交(忽略合并提交),这些提交都在给定提交之后。 你可以随心所欲地调整列表中提交的顺序,也可以删除它们。 列表大致如下:
选择 deadbee ,本次提交的上线 选中 fa1afe1 ,下一次提交的上线 ...
上线描述纯粹是为了方便您查看;git rebase 不会查看这些描述,只会查看提交名称(本例中为 "deadbee" 和 "fa1afe1"),因此请勿删除或编辑这些名称。
用 "edit" 命令替换 "pick" 命令后,你可以告诉 git rebase 在应用该提交后停止,这样你就可以编辑文件和/或提交信息,修改提交,然后继续重置。
要中断重置(就像 "edit" 命令一样,但不会先选择任何提交),请使用 "break "命令。
如果只想编辑提交信息,请用 "reword" 命令替换 "pick" 命令。
要放弃提交,请用 "drop" 替换 "pick" 命令,或直接删除匹配的行。
如果要将两个或更多提交折叠为一个提交,请用 "squash" 或 "fixup" 代替命令 "pick" 来处理第二个及后续提交。 如果提交的作者不同,折叠后的提交将归属于第一个提交的作者。 除非使用了 "fixup -c" 命令,否则折叠提交的建议提交信息是第一个提交信息与 "squash" 命令确定的提交信息的合并,省略了 "fixup" 命令确定的提交信息。 在这种情况下,建议的提交信息只是 "fixup -c" 提交的信息,而且会打开一个编辑器允许你编辑信息。 "fixup -c" 提交的内容(补丁)仍然包含在折叠提交中。如果有多个 "fixup -c" 提交,则使用最后一个提交的信息。 您也可以使用 "fixup -C" 获得与 "fixup -c" 相同的效果,但不需要打开编辑器。
当 "pick" 命令被替换为 "编辑" 命令或命令因合并错误而失败时,git rebase 将停止。完成编辑和/或解决冲突后,可以使用 git rebase --continue 继续。
例如,如果您想重新排列最近 5 次提交的顺序,让原来的 HEAD~4 变成新的 HEAD。要做到这一点,可以这样调用 git rebase:
$ git rebase -i HEAD~5
并将第一个补丁移到列表末尾。
例如,如果您有这样的历史记录,您可能需要重新创建合并提交:
X
\
A---M---B
/
---o---O---P---Q
假设要将从 "A" 开始的侧分支重置为 "Q"。确保当前的 HEAD 是 "B",然后调用
$ git rebase -i -r --onto Q O
重新排序和编辑提交通常会产生未经测试的中间步骤。 您可能想通过运行测试来检查您的历史编辑是否破坏了任何东西,或者至少使用 "exec" 命令(快捷键 "x")在历史的中间点重新编译。 为此,您可以创建类似这样的待办事项列表:
选择 deadbee 执行功能 XXX 修复 f1a5c00 修复功能 XXX 执行 make 选取 c0ffeee 下一次提交的上线 编辑 deadbab 之后提交的上线 exec cd subdir; make test ...
当命令失败(即以非 0 状态退出)时,交互式变基操作就会停止,以便您有机会解决问题。您可以使用 git rebase --continue 继续。
"exec" 命令在 shell(默认的 shell,通常是/bin/sh)中执行命令,因此可以使用 shell 功能(如 "cd"、">"、";"……)。命令从工作区树的根目录运行。
$ git rebase -i --exec "make test"
该命令用于检查中间提交是否可编译。 待办事项列表就会变成这样:
选择 5928aea one exec make test 选 04d0fda 二 exec make test 选择 ba46169 三 执行制作测试 选择 f4593F9 四 exec make test
拆分提交
在交互模式下,可以用 "edit"(编辑)来标记提交。 不过,这并不一定意味着 git rebase 希望编辑的结果是一个提交。 事实上,你可以撤销提交,也可以添加其他提交。 这可以用来将一个提交一分为二:
-
使用
gitrebase-i<提交>^开始交互式变基,其中 `<提交>`是要分割的提交。 事实上,只要包含该提交,任何提交范围都可以。 -
用 "edit" 操作标记要分割的提交。
-
在编辑该提交时,执行
gitresetHEAD^。 其效果是将HEAD重绕一圈,索引也跟着重绕一圈。 但工作区保持不变。 -
现在,将您希望在第一次提交中的改动添加到索引中。 你可以使用
gitadd(可能是交互式的)或gitgui(或两者)来完成。 -
以任何合适的提交信息提交当前索引。
-
重复最后两个步骤,直到工作区干净为止。
-
使用
gitrebase--continue继续变基。
如果不能绝对确定中间修订是一致的(编译、通过 testsuite 等),则应使用 git stash 在每次提交、测试之后,将尚未提交的改动保存起来,并在必要时修改提交。
从上有仓库变基中恢复
变基(或以任何其他形式改写)他人基于其工作的分支是个坏主意:其下游的任何人都不得不手动修正自己的历史。 本节将从下游的角度解释如何进行修复。 不过,真正的修复方法是首先避免重置上游分支。
举例说明,假设有人开发了一个 ‘子系统’ 分支,而你正在开发一个依赖于该 ‘子系统’ 的 ‘主题’。 你可能会有如下的历史记录:
o---o---o---o---o---o---o---o master \ o---o---o---o---o subsystem \ *---*---* topic
如果 ‘子系统’ 针对 master 进行重定向,会出现以下情况:
o---o---o---o---o---o---o---o master \ \ o---o---o---o---o o'--o'--o'--o'--o' subsystem \ *---*---* topic
如果现在像往常一样继续开发,并最终将 ‘主题’ 合并到 ‘子系统’,那么 ‘子系统’ 中的提交将永远重复:
o---o---o---o---o---o---o---o master \ \ o---o---o---o---o o'--o'--o'--o'--o'--M subsystem \ / *---*---*-..........-*--* topic
这种重复通常是不受欢迎的,因为它们会使历史记录变得杂乱无章,难以跟踪。 要清理这些重复提交,就需要将 ‘主题’ 上的提交移植到新的 ‘子系统’ tip 上,即重置 ‘主题’。 这就会产生连锁反应:‘主题’ 的任何下游提交都会被迫重置,依此类推!
有两种修复方法,将在下面的小节中讨论:
- 简单的例子: 变化完全相同。
-
如果 ‘子系统’ 变基是简单的重置,没有冲突,就会出现这种情况。
- 较难的例子: 变化不一样。
-
如果 ‘子系统’ 变基有冲突,或者使用了
--interactive来省略、编辑、压制或修复提交,或者上游使用了commit--amend,reset或完整历史重写命令(如filter-repo),就会发生这种情况。
简单案例
只有当 ‘子系统’ 上的更改(基于差异内容的补丁 ID)在 ‘子系统’ 变基前后完全相同时才有效。
在这种情况下,修复就很简单了,因为 git rebase 知道跳过新上游中已经存在的改动(除非给出 --reapply-cherry-picks 选项)。所以,如果你说(假设你在 ‘主题’ 分支上)
$ git rebase subsystem
您将获得固定的历史记录
o---o---o---o---o---o---o---o master \ o'--o'--o'--o'--o' subsystem \ *---*---* topic
困难的例子
如果 ‘子系统’ 的变化与重置前的变化不完全一致,情况就会变得更加复杂。
|
Note
|
虽然 ‘简单恢复案例’ 有时看似成功
即使在疑难案件中,也可能产生意想不到的后果。
例如,通过 git rebase
--interactive 删除的提交将被恢复!
|
我们的想法是手动告诉 git rebase “旧的 ‘子系统’ 分支在哪里结束,而您的 ‘主题’ 分支在哪里开始”,也就是说,它们之间的旧合并基础是什么。 例如,你必须找到一种方法来命名旧 ‘子系统’ 分支的最后一次提交:
-
使用 ‘子系统’ 引用日志:在
gitfetch之后,‘子系统’ 的旧 tip 位于subsystem@{1}。 随后的获取将增加这个数字。 (参见 git-reflog[1]) -
与 ‘主题’ 分支的 tip 有关:由于 ‘topic’ 分支有三次提交,所以 ‘子系统’ 分支的旧提示必须是
topic~3。
然后,您可以将旧的 subsystem..topic(子系统..主题)移植到新的提示中,方法是(对于引用日志的情况,假设您已经在 ‘主题’ 分支中):
$ git rebase --onto subsystem subsystem@{1}
“困难例子” 恢复的连锁反应尤其糟糕:‘主题’ 下游的 ‘每个人’ 现在也必须执行 “困难例子” 恢复!
变基合并
交互式变基命令最初是为处理单个补丁系列而设计的。因此,将合并提交排除在待办事项列表之外是有道理的,因为开发人员在分支上工作时,可能已经合并了当时的 master,只是最终将所有提交重置到了 `master`上(跳过了合并提交)。
不过,开发人员想要重新创建合并提交也有合理的原因:在多个相互关联的分支上工作时,为了保持分支结构(或 “提交拓扑”)。
在下面的示例中,开发人员在一个重构了按钮定义方式的特性分支上工作,并在另一个特性分支上使用重构实现了 “报告错误” 按钮。git log --graph --format=%s -5 的输出可能是这样的:
* 合并分支 'report-a-bug' |\ | * 添加反馈按钮 * | 合并分支 'refactor-button' |\ \ | |/ | * 为所有的按钮使用 Button 类 | * 从 DownloadButton 类中提取一个通用 Button 类
开发人员可能希望在保留分支拓扑的同时,将这些提交重定向到更新的 master 分支,例如,当第一个特性分支比第二个分支更早集成到 master 分支时,开发人员可能希望解决与 “下载按钮” 类的合并冲突,因为 “下载按钮” 类已经集成到了 master 分支。
可以使用 --rebase-merges 选项进行重置。 它将生成如下的待办事项列表:
标签上的 # 分支:重构按钮 重置到 选 123456 从下载按钮类中提取一个通用按钮类 选取 654321 对所有按钮使用按钮类 label refactor-button(重构按钮) # 分支:报告一个错误 reset refactor-button (重构按钮)# 所有按钮都使用按钮类 pick abcdef 添加反馈按钮 label report-a-bug(报告一个错误) 重置到 merge -C a1b2c3 refactor-button # 合并 “重构按钮” merge -C 6f5e4d report-a-bug # 合并 “报告一个错误”
与常规的交互式变基不同,除了 pick(选取)命令外,还有 label(标签)、reset(重置) 和 merge(合并) 命令。
label 命令会在执行该命令时将一个标签与当前 HEAD 关联。这些标签被创建为工作区本地引用(refs/rewritten/<label>),并将在重置完成后被删除。这样,链接到同一仓库的多个工作区中的重置操作就不会相互干扰。如果 label 命令失败,会立即重新安排,并给出如何继续的提示信息。
reset 命令会将 HEAD、索引和工作区重置为指定的版本。它类似于 exec git reset --hard <label>,但拒绝覆盖未跟踪的文件。如果 reset 命令失败,会立即重新安排,并附带如何编辑待办事项列表的提示信息(这种情况通常发生在 reset 命令被手动插入待办事项列表且包含错字的情况下)。
merge(合并)命令会将指定的版本合并到当时的 HEAD 中。使用 -C <源提交> 时,将使用指定合并提交的提交信息。如果将 -C 改为小写的 -c,合并成功后,提交信息将在编辑器中打开,以便用户编辑信息。
如果 merge(合并)命令因合并冲突以外的任何原因失败(即合并操作甚至没有开始),则会立即重新安排。
默认情况下,merge(合并)命令将对常规合并使用 ort ` 合并策略,对多路合并使用 `octopus 合并策略。 我们可以在调用变基命令时使用 --strategy 参数为所有合并指定一个默认策略,也可以在交互式命令列表中使用 exec 命令显式地调用 git merge 并加上 --strategy 参数来覆盖特定的合并策略。 需要注意的是,像这样显式调用 git merge 时,可以利用标签是工作区本地引用(例如,引用 refs/rewritten/onto 将对应标签 onto)这一事实来引用要合并的分支。
注意:第一条命令(label onto)会标注提交所基于的修订版本;onto ` 只是一个约定俗成的名称,是对 `--onto 选项的一种提示。
也可以通过添加 merge <合并起点> 命令,从头开始引入全新的合并提交。这种形式会生成暂定提交信息,并始终打开编辑器让用户编辑。例如,当一个特性分支要解决的问题不止一个,需要拆分成两个甚至更多特性分支时,这个命令就很有用。请看这个待办事项列表:
pick 192837 从 GNU Makefiles 切换到 CMake pick 5a6c7e 记录切换到 CMake 的过程 pick 918273 修复 CMake 中的 OpenSSL 检测问题 pick afbecd http:添加对 TLS v1.3 的支持 pick fdbaec 在 Windows 上修复 CMake 对 cURL 的检测
该列表中与 CMake 无关的一个提交很可能是为了修复所有因改用 CMake 而引入的错误,但它解决的是另一个问题。要把这个分支分成两个主题分支,可以这样编辑待办事项列表:
标签上的 选择 afbecd http:添加对 TLS v1.3 的支持 label tlsv1.3 reset onto pick 192837 从 GNU Makefiles 切换到 CMake pick 918273 修复 CMake 中的 OpenSSL 检测问题 pick fdbaec 在 Windows 上修复 CMake 对 cURL 的检测 pick 5a6c7e 记录切换到 CMake 的过程 label cmake reset onto merge tlsv1.3 merge cmake
配置
本节中这一行以下的内容都是从 git-config[1] 文档中摘录的。其内容与那里的内容相同:
- rebase.backend
-
rebase 默认使用的后端。可选值为
apply或merge。将来如果 merge 后端获得 apply 后端剩余的全部能力,该设置可能会变得无用。 - rebase.stat
-
显示上次变基后上游变化的差异状态。差异状态也由配置选项 rebase.stat 控制。
- rebase.autoSquash
-
如果设为 true,则在交互模式下默认启用 git-rebase[1] 的
--autosquash选项。可用--no-autosquash覆盖。 - rebase.autoStash
-
当设为 true 时,会在操作开始前自动创建一个临时 stash 条目,并在操作结束后重新应用它。这意味着你可以在脏工作区上运行 rebase。不过请谨慎使用:成功 rebase 之后最后一次应用 stash 可能会导致并不简单的冲突。该选项可由 git-rebase[1] 的
--no-autostash和--autostash选项覆盖。默认值为 false。 - rebase.updateRefs
-
如果设为 true,则默认启用
--update-refs选项。 - rebase.missingCommitsCheck
-
如果设为 "warn",当某些提交被移除时(例如删除了一行),
gitrebase-i会打印警告,但 rebase 仍会继续。如果设为 "error",则会打印前述警告并停止 rebase,此时可使用gitrebase--edit-todo来纠正错误。如果设为 "ignore",则不做检查。若要在不产生警告或错误的情况下丢弃某个提交,请在 todo 列表中使用drop命令。默认值为 "ignore"。 - rebase.instructionFormat
-
一个按 git-log[1] 所规定的格式字符串,用于交互式 rebase 期间的 todo 列表。该格式会自动在前面附加提交哈希。
- rebase.abbreviateCommands
-
如果设为 true,
gitrebase会在 todo 列表中使用缩写命令名,结果类似于:p deadbee 本次提交的一行说明 p fa1afe1 下一次提交的一行说明 ...
而不是:
pick deadbee 本次提交的一行说明 pick fa1afe1 下一次提交的一行说明 ...
默认值为 false。
- rebase.rescheduleFailedExec
-
自动重新安排执行失败的
exec命令。这只有在交互模式下(或提供了--exec选项时)才有意义。其效果与指定--reschedule-failed-exec选项相同。 - rebase.forkPoint
-
如果设为 false,则默认启用
--no-fork-point选项。 - rebase.rebaseMerges
-
是否以及如何默认设置
--rebase-merges选项。可以是rebase-cousins、no-rebase-cousins,或布尔值。设为 true 或no-rebase-cousins等同于--rebase-merges=no-rebase-cousins;设为rebase-cousins等同于--rebase-merges=rebase-cousins;设为 false 等同于--no-rebase-merges。在命令行上传递--rebase-merges(无论是否带参数)都会覆盖任何rebase.rebaseMerges配置。 - rebase.maxLabelLength
-
根据提交主题生成标签名时,会将名称截断到此长度。默认情况下,名称会被截断到略小于
NAME_MAX的长度(以便例如为相应的松散 ref 写入.lock文件)。
GIT
属于 git[1] 文档