Git 中文参考(四)(9)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Git 中文参考(四)

Git 中文参考(四)(8)https://developer.aliyun.com/article/1565836


行为差异

后端的行为有一些微妙的差异。

空提交

无论提交是否为空(没有相对于其父开始的更改)或结束为空(所有更改已在其他提交中上游应用),am 后端将丢弃任何“空”提交。

默认情况下,交互式后端会丢弃提交,该提交开始为空,如果命中达到空的提交,则会暂停。交互式后端存在--keep-empty选项,允许它保持空的提交。

目录重命名检测

在合并和交互式后端中启用了目录重命名启发式扫描。由于缺少准确的树信息,在后端禁用目录重命名检测。

合并战略

合并机制(git mergegit pull命令)允许使用-s选项选择后端 _ 合并策略 _。一些策略也可以采用自己的选项,可以通过向git merge和/或git pull提供-X参数来传递。

resolve 

这只能使用 3 向合并算法解析两个头(即当前分支和您从中拉出的另一个分支)。它试图仔细检测纵横交错的合并模糊,并且通常被认为是安全和快速的。

recursive 

这只能使用 3 向合并算法解析两个磁头。当有多个可用于 3 向合并的共同祖先时,它会创建共同祖先的合并树,并将其用作 3  向合并的参考树。据报道,这会导致更少的合并冲突,而不会因为从 Linux 2.6  内核开发历史记录中进行的实际合并提交所做的测试而导致错误。此外,这可以检测和处理涉及重命名的合并,但目前无法使用检测到的副本。这是拉动或合并一个分支时的默认合并策略。

_ 递归 _ 策略可以采用以下选项:

ours 

这个选项通过支持 _ 我们的 _ 版本来强制冲突的帅哥干净地自动解决。来自与我们方不冲突的其他树的更改将反映到合并结果中。对于二进制文件,整个内容都来自我们这边。

这不应该与 _ 我们的 _ 合并策略混淆,后者甚至不会查看其他树包含的内容。它丢弃了另一棵树所做的一切,声明 _ 我们的 _ 历史记录中包含了所有发生的事情。

theirs 

这与 _ 我们的 _ 相反;请注意,与 _ 我们的 _ 不同,没有 _ 他们的 _ 合并策略来混淆这个合并选项。

patience 

使用此选项, merge-recursive 花费一点额外的时间来避免由于不重要的匹配行(例如,来自不同函数的大括号)而有时发生的错误。当要合并的分支发生疯狂分歧时使用此选项。另见 git-diff [1] --patience

diff-algorithm=[patience|minimal|histogram|myers] 

告诉 merge-recursive 使用不同的 diff 算法,这有助于避免由于不重要的匹配行(例如来自不同函数的大括号)而发生的错误。另见 git-diff [1] --diff-algorithm

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配置变量。

no-renames 

关闭重命名检测。这会覆盖merge.renames配置变量。另见 git-diff [1] --no-renames

find-renames[=<n>] 

打开重命名检测,可选择设置相似性阈值。这是默认值。这会覆盖 merge.renames 配置变量。另见 git-diff [1] --find-renames

rename-threshold=<n> 

已弃用find-renames=的同义词。

subtree[=<path>] 

此选项是 _ 子树 _ 策略的更高级形式,其中策略猜测两个树在合并时必须如何移位以相互匹配。相反,指定的路径是前缀(或从头开始剥离),以使两个树的形状匹配。

octopus 

这解决了具有两个以上磁头的情况,但拒绝执行需要手动解决的复杂合并。它主要用于将主题分支头捆绑在一起。这是拉动或合并多个分支时的默认合并策略。

ours 

这会解析任意数量的头,但合并的结果树始终是当前分支头的树,实际上忽略了所有其他分支的所有更改。它旨在用于取代侧枝的旧发展历史。请注意,这与 _ 递归 _ 合并策略的-Xours 选项不同。

subtree 

这是一种修改后的递归策略。当合并树 A 和 B 时,如果 B 对应于 A 的子树,则首先调整 B 以匹配 A 的树结构,而不是读取相同级别的树。这种调整也是对共同的祖先树进行的。

使用三向合并的策略(包括默认的 _ 递归  _),如果在两个分支上进行了更改,但稍后在其中一个分支上进行了更改,则该更改将出现在合并结果中;有些人发现这种行为令人困惑。之所以会发生这种情况,是因为在执行合并时只考虑头和合并基础,而不是单个提交。因此,合并算法将恢复的更改视为完全没有更改,而是替换更改的版本。

笔记

您应该了解在共享的存储库中使用 git rebase 的含义。另请参阅下面的从上游回收中恢复。

当运行 git-rebase 命令时,它将首先执行“pre-rebase”挂钩(如果存在)。您可以使用此挂钩进行健全性检查,如果不合适则拒绝该挂钩。有关示例,请参阅模板 pre-rebase hook 脚本。

完成后,< branch>将是现在的分支。

交互模式

以交互方式重新绑定意味着您有机会编辑已重新生成的提交。您可以重新排序提交,并可以删除它们(清除坏的或其他不需要的补丁)。

交互模式适用于此类工作流程:

  1. 有个好主意
  2. 破解代码
  3. 准备一系列提交
  4. 提交

其中第 2 点由几个实例组成

a)经常使用

  1. 完成值得承诺的事情
  2. 承诺

b)独立修正

  1. 意识到某些东西不起作用
  2. 修复它
  3. 提交它

有时在 b.2 中修复了这个问题。不能修改为它修复的不太完美的提交,因为该提交深深埋藏在补丁系列中。这正是交互式 rebase 的用途:在大量的“a”和“b”之后使用它,通过重新排列和编辑提交,并将多个提交压缩成一个。

使用您要保留的最后一次提交启动它:

git rebase -i <after-this-commit>

编辑器将被激活当前分支中的所有提交(忽略合并提交),这些提交在给定的提交之后。您可以将此列表中的提交重新排序到您的内容,然后您可以删除它们。该列表看起来或多或少像这样:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

在线描述纯粹是为了您的乐趣; git rebase 不会查看它们但是在提交名称(本例中为“deadbee”和“fa1afe1”),所以不要删除或编辑名称。

通过使用命令“edit”替换命令“pick”,您可以告诉 git rebase 在应用该提交后停止,以便您可以编辑文件和/或提交消息,修改提交,并继续变基。

要中断 rebase(就像“编辑”命令一样,但不首先选择任何提交),使用“break”命令。

如果您只想编辑提交的提交消息,请使用命令“reword”替换命令“pick”。

要删除提交,请将命令“pick”替换为“drop”,或者只删除匹配的行。

如果要将两个或多个提交折叠成一个,请使用“squash”或“fixup”替换第二个和后续提交的命令“pick”。如果提交具有不同的作者,则折叠的提交将归因于第一次提交的作者。折叠提交的建议提交消息是第一次提交的提交消息和具有“squash”命令的提交消息的串联,但是省略了使用“fixup”命令提交的提交消息。

git rebase 将在“pick”替换为“edit”或命令由于合并错误而失败时停止。完成编辑和/或解决冲突后,您可以继续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 -p --onto Q O

重新排序和编辑提交通常会创建未经测试的中间步骤。您可能希望通过运行测试来检查历史编辑没有破坏任何内容,或者至少使用“exec”命令(快捷键“x”)在历史记录的中间点重新编译。您可以通过创建像这样的待办事项列表来实现:

pick deadbee Implement feature XXX
fixup f1a5c00 Fix to feature XXX
exec make
pick c0ffeee The oneline of the next commit
edit deadbab The oneline of the commit after
exec cd subdir; make test
...

当命令失败时(即退出非 0 状态),交互式 rebase 将停止,以便您有机会解决问题。您可以继续git rebase --continue

“exec”命令在 shell 中启动命令(在$SHELL中指定的命令,或者如果未设置$SHELL则在默认 shell 中启动),因此您可以使用 shell 功能(如“cd”,“>”, “;”…)。该命令从工作树的根目录运行。

$ git rebase -i --exec "make test"

此命令允许您检查中间提交是否可编译。待办事项清单变得像这样:

pick 5928aea one
exec make test
pick 04d0fda two
exec make test
pick ba46169 three
exec make test
pick f4593f9 four
exec make test

分裂委员会

在交互模式下,您可以使用“编辑”操作标记提交。但是,这并不一定意味着 git rebase 希望此编辑的结果恰好是一次提交。实际上,您可以撤消提交,也可以添加其他提交。这可以用于将提交拆分为两个:

  • 使用git rebase -i ^启动交互式 rebase,其中< commit>是您要拆分的提交。实际上,只要包含该提交,任何提交范围都可以。
  • 使用“编辑”操作标记要拆分的提交。
  • 编辑提交时,执行git reset HEAD^。结果是 HEAD 被一个重绕,索引也随之而来。但是,工作树保持不变。
  • 现在将更改添加到您希望在第一次提交中拥有的索引。您可以使用git add(可能是交互式)或 git gui (或两者)来做到这一点。
  • 使用现在适当的提交消息提交 now-current 索引。
  • 重复最后两步,直到工作树干净。
  • 使用git rebase --continue继续变基。

如果您不完全确定中间修订版是否一致(它们是编译的,通过测试套件等),您应该使用 git stash 来隐藏每次提交,测试后尚未提交的更改,如果需要修复,则修改提交。

从 UPSTREAM REBASE 恢复

重新定位(或任何其他形式的重写)其他人基于其工作的分支是一个坏主意:它下游的任何人都被迫手动修复其历史记录。本节介绍如何从下游的角度进行修复。然而,真正的解决方法是首先避免重新定位上游。

为了说明,假设您处于某人开发 _ 子系统 _ 分支的情况,并且您正在处理依赖于此 _ 子系统 _ 的 _ 主题 _。您最终可能会得到如下历史记录:

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

这样的副本通常是不受欢迎的,因为它们使历史变得混乱,使得更难以遵循。为了清理,您需要将 _ 主题 _ 上的提交移植到新的 _ 子系统 _ 提示,即 rebase _ 主题 。这会产生涟漪效应: 主题 _ 下游的任何人也被迫改变,依此类推!

有两种修复方法,将在以下小节中讨论:

Easy case: The changes are literally the same. 

如果 _ 子系统 _ rebase 是一个简单的 rebase 并且没有冲突,就会发生这种情况。

Hard case: The changes are not the same. 

如果 _ 子系统 _ rebase 发生冲突,或使用--interactive省略,编辑,压缩或修复提交,则会发生这种情况;或者如果上游使用commit --amendresetfilter-branch中的一个。

容易的情况

仅在 _ 子系统 _ 上的更改(基于差异内容的修补程序 ID)在 rebase _ 子系统 _ 之前和之后的字面上相同时才有效。

在这种情况下,修复很容易,因为 git rebase 知道跳过已经存在于新上游的更改。所以,如果你说(假设你在 _ 话题 _)

$ git rebase subsystem

你将最终得到固定的历史

o---o---o---o---o---o---o---o  master
         \
          o'--o'--o'--o'--o'  subsystem
               \
                *---*---*  topic

艰难的案例

如果 _ 子系统 _ 更改与 rebase 之前的更改不完全相符,事情会变得更复杂。

| 注意 | 虽然即使在困难的情况下,“简单案件恢复”有时似乎也是成功的,但它可能会产生意想不到的后果。例如,通过git rebase --interactive删除的提交将复活! |

我的想法是手动告诉 git rebase “旧的 _ 子系统 _ 结束,你的 _ 主题 _ 开始了”,也就是说,他们之间的旧合并基础是什么。您必须找到一种方法来命名旧 _ 子系统 _ 的最后一次提交,例如:

  • 使用 _ 子系统 _ reflog:在 git fetch 之后,_ 子系统 _ 的旧提示位于subsystem@{1}。随后的提取将增加数量。 (参见 git-reflog [1] 。)
  • 相对于 _ 主题 _ 的提示:知道你的 _ 主题 _ 有三次提交,_ 子系统 _ 的旧提示必须是topic~3

然后,您可以通过说(对于 reflog 案例,假设您已经在 _ 主题 _ 上)将旧的subsystem..topic移植到新的提示:

$ git rebase --onto subsystem subsystem@{1}

“硬案例”恢复的连锁反应特别糟糕: __ 主题 _ 下游的所有人 _ 现在也必须执行“硬案例”恢复!

重新合并

交互式 rebase 命令最初设计用于处理单个补丁系列。因此,从 todo 列表中排除合并提交是有意义的,因为开发人员可能在处理分支时合并当时的master,只是最终将所有提交重新绑定到master上(跳过合并提交) )。

但是,开发人员可能想要重新创建合并提交的正当理由是:在处理多个相互关联的分支时保留分支结构(或“提交拓扑”)。

在下面的示例中,开发人员处理主题分支,该分支重构按钮的定义方式,以及使用该重构实现“报告错误”按钮的另一个主题分支。 git log --graph --format=%s -5的输出可能如下所示:

*   Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one

开发人员可能希望在保留分支拓扑的同时将这些提交重新绑定到较新的master,例如,当第一个主题分支预期比第二个主题分支更早地集成到master中时,比如解决与更改为使其成为master的 DownloadButton 类。

可以使用--rebase-merges选项执行此 rebase。它将生成一个如下所示的待办事项列表:

label onto
# Branch: refactor-button
reset onto
pick 123456 Extract a generic Button class from the DownloadButton one
pick 654321 Use the Button class for all buttons
label refactor-button
# Branch: report-a-bug
reset refactor-button # Use the Button class for all buttons
pick abcdef Add the feedback button
label report-a-bug
reset onto
merge -C a1b2c3 refactor-button # Merge 'refactor-button'
merge -C 6f5e4d report-a-bug # Merge 'report-a-bug'

与常规交互式 rebase 相比,除pick之外还有labelresetmerge命令。

执行该命令时,label命令将标签与当前 HEAD 相关联。这些标签创建为 worktree-local refs(refs/rewritten/),将在 rebase 完成时删除。这样,链接到同一存储库的多个工作树中的 rebase 操作不会相互干扰。如果label命令失败,则立即重新安排,并提供有用的消息如何继续。

reset命令将 HEAD,索引和工作树重置为指定的修订版。它类似于exec git reset --hard ,但拒绝覆盖未跟踪的文件。如果reset命令失败,则会立即重新安排,并提供一条有用的消息,说明如何编辑待办事项列表(这通常在手动将reset命令插入待办事项列表并包含拼写错误时发生)。

merge命令会将指定的修订版合并到当时的 HEAD 中。使用-C ,将使用指定合并提交的提交消息。当-C更改为小写-c时,成功合并后将在编辑器中打开该消息,以便用户可以编辑该消息。

如果merge命令因合并冲突以外的任何原因而失败(即合并操作甚至没有开始),则立即重新安排。

此时,merge命令将始终使用recursive合并策略进行常规合并,而octopus用于章鱼合并,无法选择不同的合并策略。要解决这个问题,可以使用exec命令显式调用git merge,使用标签是 worktree-local refs 的事实(例如,ref refs/rewritten/onto将对应于标签onto)。

注意:第一个命令(label onto)标记提交重新定位的修订版本;名称onto只是一个约定,作为--onto选项的点头。

也可以通过添加merge 形式的命令从头开始引入全新的合并提交。此表单将生成暂定的提交消息,并始终打开编辑器以允许用户编辑它。这可能是有用的,例如当一个主题分支最终解决一个以上的问题,并希望分成两个甚至更多的主题分支。考虑这个待办事项列表:

pick 192837 Switch from GNU Makefiles to CMake
pick 5a6c7e Document the switch to CMake
pick 918273 Fix detection of OpenSSL in CMake
pick afbecd http: add support for TLS v1.3
pick fdbaec Fix detection of cURL in CMake on Windows

此列表中与 CMake 无关的一个提交很可能是通过修复切换到 CMake 引入的所有错误来实现的,但它解决了一个不同的问题。要将此分支拆分为两个主题分支,可以像下面这样编辑待办事项列表:

label onto
pick afbecd http: add support for TLS v1.3
label tlsv1.3
reset onto
pick 192837 Switch from GNU Makefiles to CMake
pick 918273 Fix detection of OpenSSL in CMake
pick fdbaec Fix detection of cURL in CMake on Windows
pick 5a6c7e Document the switch to CMake
label cmake
reset onto
merge tlsv1.3
merge cmake

BUGS

--preserve-merges --interactive提供的待办事项列表不代表修订图的拓扑结构。编辑提交和重写他们的提交消息应该可以正常工作,但尝试重新提交提交往往会产生违反直觉的结果。在这种情况下使用--rebase-merges

例如,尝试重新排列

1 --- 2 --- 3 --- 4 --- 5

1 --- 2 --- 4 --- 3 --- 5

通过移动“选择 4”线将导致以下历史记录:

3
       /
1 --- 2 --- 4 --- 5

GIT

部分 git [1] 套件

相关文章
|
2月前
|
监控 程序员 开发工具
如何规范Git提交-参考阿里云开发者社区
这篇文章分享了如何规范Git提交,介绍了commit message的格式规范,并通过webhook监控机制来确保代码提交的规范性,从而提高研发效率和代码维护质量。
|
3月前
|
存储 缓存 网络安全
Git 中文参考(一)(8)
Git 中文参考(一)
39 2
|
3月前
|
存储 网络安全 开发工具
Git 中文参考(一)(7)
Git 中文参考(一)
30 2
|
3月前
|
存储 算法 Java
Git 中文参考(一)(6)
Git 中文参考(一)
32 2
|
3月前
|
存储 Shell 开发工具
Git 中文参考(一)(5)
Git 中文参考(一)
24 2
|
3月前
|
存储 开发工具 git
Git 中文参考(一)(4)
Git 中文参考(一)
29 2
|
3月前
|
存储 安全 开发工具
Git 中文参考(一)(3)
Git 中文参考(一)
18 2
|
3月前
|
存储 Shell 开发工具
Git 中文参考(一)(2)
Git 中文参考(一)
26 2
|
3月前
|
存储 人工智能 开发工具
Git 中文参考(五)(9)
Git 中文参考(五)
133 2
|
3月前
|
存储 Linux 开发工具
Git 中文参考(五)(8)
Git 中文参考(五)
23 2

相关实验场景

更多