使用 rebase 拉取特定的提交
Pull with rebase up to a specific commit
这是 的变体,带有 rebase 扭曲。
我想做一个 git pull --rebase
但只到特定的提交。这不是拉取特定的提交,而是拉取 upto 特定的提交。远程主机如下所示。
A<-B<-C<-D<-E<-F<-HEAD (Remote master HEAD)
假设我的本地特征分支 HEAD 指向 G,G 指向 D:
A<-B<-C<-D<-G<-HEAD (Current local feature branch HEAD).
我想通过变基提升到 E,这样我的分支最终看起来像:
A<-B<-C<-D<-E<-G<-HEAD (local feature branch end goal).
不过,这只是特例。我想选择任何符合条件的提交哈希,而不仅仅是上面示例中的倒数第二个。
当然,我希望提交 E 的散列在操作结束时与远程主机匹配。我强调这一点,因为某些类型的交互式 rebase 编辑会导致 属性 消失。
我该怎么办?
从远程获取更改:
git fetch origin
变基到 master 的远程版本,忽略一些提交:
git rebase origin/master~<n>
其中 <n>
是您要忽略的 master
顶端的提交数。
如果您有要变基的提交的 ID,则可以改用它:
git rebase <commit-id>
尝试交互式变基:
git rebase -i e3f8704
e3f8704 是您的提交哈希码。
TL;DR
是正确的:您必须将 git pull
分成两个独立的组成命令:git fetch
后跟 git rebase
。不过,它可能值得更多解释。
长
让我重画一下你的图表,让它们看起来(我认为无论如何)更清晰一点。不过,我打算用更简单的连接破折号替换内部 backwards-pointing 箭头,因为我需要画一些 "arrows" 指向 up-and-left 或 down-and-left,而这不会在这里工作得不好。 (我的系统上有 arrow-drawing 个字符并不总是显示在其他系统的其他 Web 浏览器中。)
在遥控器上我们有:
A--B--C--D--E--F <-- master
也就是说,有一个提交链,带有一些大而难看的哈希 ID,为方便起见,我们用字母替换了这些 ID,该链在提交 F
处结束。 他们的 Git 的名称master
包含提交F
的哈希ID。 (名称 master
可能是也可能不是远程上的当前 b运行ch:这对我们的目的无关紧要,因此我们不需要绘制特殊名称 HEAD
在这里。)
同时我们在本地有这个:
A--B--C--D--G <-- feature (HEAD)
即,我们和他们通过 D
共享提交 A
,包括他们的链接,我们的 Git 的名称 feature
包含提交的哈希 ID G
指向 D
.
I want to pull up to E with a rebase so that my branch ends up looking like:
A--B--C--D--E--G <-- feature (HEAD)
However, this is just a special case. I want to pick any eligible commit hash, not just the second to last one as in the example above.
你需要做的是避免 git pull
命令。
git pull
所做的是运行两个more-basicGit命令:第一个git fetch
,然后一个您选择的第二个命令。第二个命令通常是 git merge
但如果你使用 --rebase
或其他各种配置方法,你可以用 运行 git rebase
代替。你不能做的是将正确的参数传递给git rebase
,其中"right arguments"我的意思是那些解决有问题。
我们先运行git fetch
。这让我们的 Git 调用了他们的 Git。他们的 Git 告诉我们的 Git 它的各种 b运行ch 和标签以及其他类似的名称,包括他们的 master
标识提交 F
的事实。我们的 Git 检查存储库并发现我们 没有 提交 F
,所以我们的 Git 要求获取它。他们的 Git 然后也提供提交 E
— 发送者 必须 提供我们需要的一切,我们需要 E
来持有 F
——而我们的 Git 也要求这样做。他们提供 D
,但我们已经有了,所以我们告诉他们就此打住。
他们现在构建了一个 so-called thin pack,其中包含我们需要将提交 E
和 F
添加到我们的存储库的内容。这是你在 运行 git fetch
或 运行s git fetch
的任何命令时看到的 "counting objects and "compressing objects" 内容。他们向我们发送了薄包;我们的 Git 接受了那个精简包并对其进行了修复,以便它可以使用,现在我们拥有了他们拥有的提交,而我们没有,我们需要完成 git fetch
-ing.
如果我们不需要其他任何东西,我们的 Git 对他们的 Git 说 'kthanksbye 并继续更新我们的 remote-tracking 名字。在我们的 Git 中,我们有名字 origin/master
等等:这些是 我们的 Git 记得什么 他们的 Git 说 他们的 哈希 ID 是,对于 他们的 b运行ch 名字,上次我们谈过跟他们。只要我们有 他们 b运行 们记住的提交,我们的 Git 就可以相应地更新我们的 remote-tracking 名称,所以它确实如此。这给我们留下了:
A--B--C--D--G <-- feature (HEAD)
\
E--F <-- origin/master
(有那个 up-and-left 指向箭头,从 E
到 D
,没有使用箭头字符绘制。)
我们现在准备 运行 git rebase
。
如果我们 运行 git rebase
像 git pull
那样
如果我们 运行 git rebase origin/master
—git pull
实际上使用了 `git rebase 但这做同样的事情—Git 将:
- 列出我们当前
HEAD
可访问的提交:G
、D
、C
,等等;
- 列出可从
origin/master
访问的提交:F
、E
、D
、C
等;
- 从第一个列表中删除第二个列表中的任何内容;
- 删除任何不应复制的额外提交;1
- 以正确的顺序排列列表(与 Git 的内部反向顺序相反);和
- 开始复制这些提交,一个接一个,就好像
git cherry-pick
.2
由于此列表仅包含提交 G
,这是我们将复制的一个提交。但是:这个副本去了哪里?
常规 git rebase
放置副本,或者如果有多个提交要复制,则复制复数,紧跟在命令行上指定的提交之后 。由于 git rebase
as 运行 by git pull
名称提交 F
——我们的 origin/master
指向的提交,在 git fetch
更新了我们的 origin/master
来匹配 origin
的 master
——我们会得到:
A--B--C--D--G
\
E--F <-- origin/master
\
G'
作为结果。 (我删除了一些名字,因为对于这个 m换句话说,这些名字并不是很有趣,git rebase
也会摆弄它们;我们只是还没有画那部分。)
如果有更多的提交,例如 G-H-I
,我们最终会在此处的底行得到 G'-H'-I'
。在所有情况下,原始 提交,pre-copying,仍然存在。此时,git rebase
通过 移动我们的 HEAD
所附加的名称 以指向最终复制的提交来完成其工作:3
A--B--C--D--G [was `feature`, now abandoned]
\
E--F <-- origin/master
\
G' <-- feature (HEAD)
1根据 git rebase
的参数,这通常包括 所有合并提交 ,加上 git patch-id
计算相同的补丁 ID。 patch-ID 计算部分描述起来有点棘手:它涉及使用 git rev-list --left-right
和对称差分 triple-dot 运算符。对于许多变基,这些都不重要,这就是为什么我只有这个脚注。
2某些类型的 git rebase
字面上 运行 git cherry-pick
。其他的——包括默认的和 git pull
的 运行——使用一种更快但更廉价的机制,涉及 git format-patch
和 git am
,可能会错过重命名操作。您可以通过添加 -m
或进行交互式变基或添加其他选项来强制变基使用较慢但 more-accurate cherry-pick 的方法。不过很少有真正需要这样做的。
3从技术上讲,Git 运行 每个复制操作都有一个 分离的 HEAD,其中HEAD
复制完成后直接指向副本。但是当然 git rebase
开始 通过保存附件的事实——HEAD
附加到 feature
的事实——这样当 rebase 完成时, Git 知道 (1) 移动 feature
和 (2) re-attach HEAD
.
您想改为:指定副本的去向
如果您 运行 git rebase
自己,您 可以选择 git rebase
调用 upstream。当 git pull
执行此操作时,它会向 git rebase
提供更新后的 origin/master
指向的哈希 ID。如果你这样做:
git rebase origin/master
你给它起名字 origin/master
,它解析为相同的哈希 ID,你得到我们看到的结果。
但是如果你手动做运行,你可以输入哈希ID,或者任何其他命名你想要的承诺。这告诉 git rebase
副本去哪里。
在这种情况下,那么,如果您以任何方式命名提交 E
– 原始哈希 ID,或 origin/master^
,或 origin/master~
都可以工作 – 您的 git rebase
会将 G
复制到 E
:
之后的 G'
A--B--C--D--G [was `feature`, now abandoned]
\
E--F <-- origin/master
\
G' <-- feature (HEAD)
你得到了想要的结果。
现在还有一个控制旋钮供您使用
当您手动 运行 git rebase
时,无需 git pull
为您完成,您就多了一个选择。再次查看上面的 bullet-point 步骤列表,其中 git rebase
确定要复制的提交。如果你 运行:
git rebase <upstream>
Git 列出提交,如同通过:4
git log <upstream>..HEAD
(如the git rebase
documentation所示;根据需要添加--fork-point
,见脚注4)
然后它复制列出的提交,使用 upstream
作为复制的目标。但是如果你有,例如:
...--B--C--D--E--F <-- branch (HEAD)
\
G--H--I <-- origin/master
其中提交 D
是您所做的紧急 hack 修复,因此可以编写提交 E
和 F
,同时有人将真正的修复写为提交 G
, H
, and/or I
?
虽然 git rebase
试图聪明地忽略已经在上游的提交——例如,如果提交 G
匹配提交 D
,git rebase
知道不copy D
——这并不是在所有情况下都有效。特别是,它通常 不会 删除实际上只是禁用或删除功能的紧急情况 "fix",而不是真正修复功能中的错误。
您可以使用 git rebase -i
来处理这个问题,但在 git rebase -i
之前很久就有 git rebase --onto
。使用 --onto
,您可以从 upstream-limiting 参数中 拆分 target-selection。
也就是说,在此图中,我们想要的结果是仅复制 提交 E
和 F
,留下 D
——我们的紧急修复不太正确——落后了。要告诉 Git 这个,我们使用 git rebase --onto
:
git rebase --onto origin/master <hash-of-D>
或:
git rebase --onto origin/master branch~2
我们的 upstream
参数现在命名为提交 D
。这是要复制的提交 not(也不是任何较早的提交)。
如果我们 运行 a git rebase
像这样但是没有 --onto
参数,Git (a) 不会复制 D
但是 (b ) 会将 E
和 F
的副本放在 D
之后。结果是我们不想要的(画出来看看)。但是当我们添加 --onto origin/master
时,它告诉 rebase 在提交 I
之后放置副本。结果是:
...--B--C--D--E--F [abandoned]
\
G--H--I <-- origin/master
\
E'-F' <-- branch (HEAD)
提交 D-E-F
全部被删除,以支持新的和改进的 E'-F'
提交。我们不必手动删除 D
,因为我们的 git rebase
参数为我们。用不可见的废弃提交重新绘制链给我们:
...--B--C--G--H--I <-- origin/master
\
E'-F' <-- branch (HEAD)
如果除了我们没有人知道提交 E
和 F
,我们可以假装 我们只写了新的副本,而不是比原来的:没有人(除了我们)会知道。5
4自己试试吧!您将获得一个哈希 ID 列表,每行一个。它们以 Git 的首选顺序出现——向后——这不适合 git rebase
,并且它们 不会 忽略 git rebase
将省略。尽管如此,rebase 实际上 确实 在内部使用 git rev-list
,只是它添加了很多选项:--no-merges
删除合并提交,--topo-order --reverse
到得到正确的顺序。最后,如脚注 1 中所述,排除与上游端的提交具有相同 patch-IDs 的提交有点神奇。这涉及使用 three-dot 语法,<upstream>...HEAD
,并添加 --right-only --cherry-pick
。当 rebase 是一个 shell 脚本时,这很容易找到;现在已经用 C 代码重写了,更难理解了。
当 fork-point 选项生效时,此处的 <upstream>
参数将被 git merge-base --fork-point
的结果替换,它使用您的 origin/master
reflog 来猜测是否某些应省略提交。参见,例如, and .
我仍然有点不相信 fork-point 模式是正确的默认模式(有时会令人惊讶)并且我不确定新的 Git 2.24 --keep-base
选项是否使用fork-point 类型合并库,或真正的合并库。但请注意,如果你使用任何不是 name 的变基——例如,如果你的变基 upstream
参数是一个哈希 ID —禁用 fork-point 模式,因为 fork-point 基数是通过扫描 reflog 计算的,只有 names 有 reflogs.
5我们可能会忘记。谁能记住原始哈希 ID?
结论
Git 实际上就是 提交 。 B运行ch 名称,当你使用它们时——以及当 Git 使用它们时——只是为了帮助你在某些 b[=525 中找到 last 提交=]通道。提交将永远冻结,并且(大部分)永久冻结(如果您无法 找到 它们,从 b运行ch 或其他名称,它们最终会消失)。
B运行ch names move。 B运行ch 名称让我们和 Git 找到提交。它们以可预测的方式移动,通过 添加 提交到 b运行ch。一些操作,例如 git rebase
或 git reset
,以突然的方式移动它们,并且可能以 "less natural" 的方式移动它们,而不仅仅是前进以合并更多提交。
git rebase
是关于 复制 提交。我们制作 new-and-improved 个副本,使用不同的哈希 ID,并使 b运行ch 名称指向最后一个 copied 提交。原件无法更改,但如果您移动 b运行ch name,任何未保存原件哈希 ID 的人将无法 找到原件
git fetch
关于两件事:从另一个 Git 获取新提交和 更新 remote-tracking 名称如 origin/master
基于其他 Git 中的内容。如果我们 did 得到新的提交,此时我们只需要记住这些 remote-tracking 名称,所以我们通常需要第二个命令。
git pull
是为了方便:它 运行 是 git fetch
,然后它 运行 是第二个命令,通常是 git merge
.
有时,这不方便。实际上,我发现它带来的不便多于它带来的便利。在那种情况下,不要使用它。
这是
我想做一个 git pull --rebase
但只到特定的提交。这不是拉取特定的提交,而是拉取 upto 特定的提交。远程主机如下所示。
A<-B<-C<-D<-E<-F<-HEAD (Remote master HEAD)
假设我的本地特征分支 HEAD 指向 G,G 指向 D:
A<-B<-C<-D<-G<-HEAD (Current local feature branch HEAD).
我想通过变基提升到 E,这样我的分支最终看起来像:
A<-B<-C<-D<-E<-G<-HEAD (local feature branch end goal).
不过,这只是特例。我想选择任何符合条件的提交哈希,而不仅仅是上面示例中的倒数第二个。
当然,我希望提交 E 的散列在操作结束时与远程主机匹配。我强调这一点,因为某些类型的交互式 rebase 编辑会导致 属性 消失。
我该怎么办?
从远程获取更改:
git fetch origin
变基到 master 的远程版本,忽略一些提交:
git rebase origin/master~<n>
其中 <n>
是您要忽略的 master
顶端的提交数。
如果您有要变基的提交的 ID,则可以改用它:
git rebase <commit-id>
尝试交互式变基:
git rebase -i e3f8704
e3f8704 是您的提交哈希码。
TL;DR
git pull
分成两个独立的组成命令:git fetch
后跟 git rebase
。不过,它可能值得更多解释。
长
让我重画一下你的图表,让它们看起来(我认为无论如何)更清晰一点。不过,我打算用更简单的连接破折号替换内部 backwards-pointing 箭头,因为我需要画一些 "arrows" 指向 up-and-left 或 down-and-left,而这不会在这里工作得不好。 (我的系统上有 arrow-drawing 个字符并不总是显示在其他系统的其他 Web 浏览器中。)
在遥控器上我们有:
A--B--C--D--E--F <-- master
也就是说,有一个提交链,带有一些大而难看的哈希 ID,为方便起见,我们用字母替换了这些 ID,该链在提交 F
处结束。 他们的 Git 的名称master
包含提交F
的哈希ID。 (名称 master
可能是也可能不是远程上的当前 b运行ch:这对我们的目的无关紧要,因此我们不需要绘制特殊名称 HEAD
在这里。)
同时我们在本地有这个:
A--B--C--D--G <-- feature (HEAD)
即,我们和他们通过 D
共享提交 A
,包括他们的链接,我们的 Git 的名称 feature
包含提交的哈希 ID G
指向 D
.
I want to pull up to E with a rebase so that my branch ends up looking like:
A--B--C--D--E--G <-- feature (HEAD)
However, this is just a special case. I want to pick any eligible commit hash, not just the second to last one as in the example above.
你需要做的是避免 git pull
命令。
git pull
所做的是运行两个more-basicGit命令:第一个git fetch
,然后一个您选择的第二个命令。第二个命令通常是 git merge
但如果你使用 --rebase
或其他各种配置方法,你可以用 运行 git rebase
代替。你不能做的是将正确的参数传递给git rebase
,其中"right arguments"我的意思是那些解决有问题。
我们先运行git fetch
。这让我们的 Git 调用了他们的 Git。他们的 Git 告诉我们的 Git 它的各种 b运行ch 和标签以及其他类似的名称,包括他们的 master
标识提交 F
的事实。我们的 Git 检查存储库并发现我们 没有 提交 F
,所以我们的 Git 要求获取它。他们的 Git 然后也提供提交 E
— 发送者 必须 提供我们需要的一切,我们需要 E
来持有 F
——而我们的 Git 也要求这样做。他们提供 D
,但我们已经有了,所以我们告诉他们就此打住。
他们现在构建了一个 so-called thin pack,其中包含我们需要将提交 E
和 F
添加到我们的存储库的内容。这是你在 运行 git fetch
或 运行s git fetch
的任何命令时看到的 "counting objects and "compressing objects" 内容。他们向我们发送了薄包;我们的 Git 接受了那个精简包并对其进行了修复,以便它可以使用,现在我们拥有了他们拥有的提交,而我们没有,我们需要完成 git fetch
-ing.
如果我们不需要其他任何东西,我们的 Git 对他们的 Git 说 'kthanksbye 并继续更新我们的 remote-tracking 名字。在我们的 Git 中,我们有名字 origin/master
等等:这些是 我们的 Git 记得什么 他们的 Git 说 他们的 哈希 ID 是,对于 他们的 b运行ch 名字,上次我们谈过跟他们。只要我们有 他们 b运行 们记住的提交,我们的 Git 就可以相应地更新我们的 remote-tracking 名称,所以它确实如此。这给我们留下了:
A--B--C--D--G <-- feature (HEAD)
\
E--F <-- origin/master
(有那个 up-and-left 指向箭头,从 E
到 D
,没有使用箭头字符绘制。)
我们现在准备 运行 git rebase
。
如果我们 运行 git rebase
像 git pull
那样
如果我们 运行 git rebase origin/master
—git pull
实际上使用了 `git rebase 但这做同样的事情—Git 将:
- 列出我们当前
HEAD
可访问的提交:G
、D
、C
,等等; - 列出可从
origin/master
访问的提交:F
、E
、D
、C
等; - 从第一个列表中删除第二个列表中的任何内容;
- 删除任何不应复制的额外提交;1
- 以正确的顺序排列列表(与 Git 的内部反向顺序相反);和
- 开始复制这些提交,一个接一个,就好像
git cherry-pick
.2
由于此列表仅包含提交 G
,这是我们将复制的一个提交。但是:这个副本去了哪里?
常规 git rebase
放置副本,或者如果有多个提交要复制,则复制复数,紧跟在命令行上指定的提交之后 。由于 git rebase
as 运行 by git pull
名称提交 F
——我们的 origin/master
指向的提交,在 git fetch
更新了我们的 origin/master
来匹配 origin
的 master
——我们会得到:
A--B--C--D--G
\
E--F <-- origin/master
\
G'
作为结果。 (我删除了一些名字,因为对于这个 m换句话说,这些名字并不是很有趣,git rebase
也会摆弄它们;我们只是还没有画那部分。)
如果有更多的提交,例如 G-H-I
,我们最终会在此处的底行得到 G'-H'-I'
。在所有情况下,原始 提交,pre-copying,仍然存在。此时,git rebase
通过 移动我们的 HEAD
所附加的名称 以指向最终复制的提交来完成其工作:3
A--B--C--D--G [was `feature`, now abandoned]
\
E--F <-- origin/master
\
G' <-- feature (HEAD)
1根据 git rebase
的参数,这通常包括 所有合并提交 ,加上 git patch-id
计算相同的补丁 ID。 patch-ID 计算部分描述起来有点棘手:它涉及使用 git rev-list --left-right
和对称差分 triple-dot 运算符。对于许多变基,这些都不重要,这就是为什么我只有这个脚注。
2某些类型的 git rebase
字面上 运行 git cherry-pick
。其他的——包括默认的和 git pull
的 运行——使用一种更快但更廉价的机制,涉及 git format-patch
和 git am
,可能会错过重命名操作。您可以通过添加 -m
或进行交互式变基或添加其他选项来强制变基使用较慢但 more-accurate cherry-pick 的方法。不过很少有真正需要这样做的。
3从技术上讲,Git 运行 每个复制操作都有一个 分离的 HEAD,其中HEAD
复制完成后直接指向副本。但是当然 git rebase
开始 通过保存附件的事实——HEAD
附加到 feature
的事实——这样当 rebase 完成时, Git 知道 (1) 移动 feature
和 (2) re-attach HEAD
.
您想改为:指定副本的去向
如果您 运行 git rebase
自己,您 可以选择 git rebase
调用 upstream。当 git pull
执行此操作时,它会向 git rebase
提供更新后的 origin/master
指向的哈希 ID。如果你这样做:
git rebase origin/master
你给它起名字 origin/master
,它解析为相同的哈希 ID,你得到我们看到的结果。
但是如果你手动做运行,你可以输入哈希ID,或者任何其他命名你想要的承诺。这告诉 git rebase
副本去哪里。
在这种情况下,那么,如果您以任何方式命名提交 E
– 原始哈希 ID,或 origin/master^
,或 origin/master~
都可以工作 – 您的 git rebase
会将 G
复制到 E
:
G'
A--B--C--D--G [was `feature`, now abandoned]
\
E--F <-- origin/master
\
G' <-- feature (HEAD)
你得到了想要的结果。
现在还有一个控制旋钮供您使用
当您手动 运行 git rebase
时,无需 git pull
为您完成,您就多了一个选择。再次查看上面的 bullet-point 步骤列表,其中 git rebase
确定要复制的提交。如果你 运行:
git rebase <upstream>
Git 列出提交,如同通过:4
git log <upstream>..HEAD
(如the git rebase
documentation所示;根据需要添加--fork-point
,见脚注4)
然后它复制列出的提交,使用 upstream
作为复制的目标。但是如果你有,例如:
...--B--C--D--E--F <-- branch (HEAD)
\
G--H--I <-- origin/master
其中提交 D
是您所做的紧急 hack 修复,因此可以编写提交 E
和 F
,同时有人将真正的修复写为提交 G
, H
, and/or I
?
虽然 git rebase
试图聪明地忽略已经在上游的提交——例如,如果提交 G
匹配提交 D
,git rebase
知道不copy D
——这并不是在所有情况下都有效。特别是,它通常 不会 删除实际上只是禁用或删除功能的紧急情况 "fix",而不是真正修复功能中的错误。
您可以使用 git rebase -i
来处理这个问题,但在 git rebase -i
之前很久就有 git rebase --onto
。使用 --onto
,您可以从 upstream-limiting 参数中 拆分 target-selection。
也就是说,在此图中,我们想要的结果是仅复制 提交 E
和 F
,留下 D
——我们的紧急修复不太正确——落后了。要告诉 Git 这个,我们使用 git rebase --onto
:
git rebase --onto origin/master <hash-of-D>
或:
git rebase --onto origin/master branch~2
我们的 upstream
参数现在命名为提交 D
。这是要复制的提交 not(也不是任何较早的提交)。
如果我们 运行 a git rebase
像这样但是没有 --onto
参数,Git (a) 不会复制 D
但是 (b ) 会将 E
和 F
的副本放在 D
之后。结果是我们不想要的(画出来看看)。但是当我们添加 --onto origin/master
时,它告诉 rebase 在提交 I
之后放置副本。结果是:
...--B--C--D--E--F [abandoned]
\
G--H--I <-- origin/master
\
E'-F' <-- branch (HEAD)
提交 D-E-F
全部被删除,以支持新的和改进的 E'-F'
提交。我们不必手动删除 D
,因为我们的 git rebase
参数为我们。用不可见的废弃提交重新绘制链给我们:
...--B--C--G--H--I <-- origin/master
\
E'-F' <-- branch (HEAD)
如果除了我们没有人知道提交 E
和 F
,我们可以假装 我们只写了新的副本,而不是比原来的:没有人(除了我们)会知道。5
4自己试试吧!您将获得一个哈希 ID 列表,每行一个。它们以 Git 的首选顺序出现——向后——这不适合 git rebase
,并且它们 不会 忽略 git rebase
将省略。尽管如此,rebase 实际上 确实 在内部使用 git rev-list
,只是它添加了很多选项:--no-merges
删除合并提交,--topo-order --reverse
到得到正确的顺序。最后,如脚注 1 中所述,排除与上游端的提交具有相同 patch-IDs 的提交有点神奇。这涉及使用 three-dot 语法,<upstream>...HEAD
,并添加 --right-only --cherry-pick
。当 rebase 是一个 shell 脚本时,这很容易找到;现在已经用 C 代码重写了,更难理解了。
当 fork-point 选项生效时,此处的 <upstream>
参数将被 git merge-base --fork-point
的结果替换,它使用您的 origin/master
reflog 来猜测是否某些应省略提交。参见,例如,
我仍然有点不相信 fork-point 模式是正确的默认模式(有时会令人惊讶)并且我不确定新的 Git 2.24 --keep-base
选项是否使用fork-point 类型合并库,或真正的合并库。但请注意,如果你使用任何不是 name 的变基——例如,如果你的变基 upstream
参数是一个哈希 ID —禁用 fork-point 模式,因为 fork-point 基数是通过扫描 reflog 计算的,只有 names 有 reflogs.
5我们可能会忘记。谁能记住原始哈希 ID?
结论
Git 实际上就是 提交 。 B运行ch 名称,当你使用它们时——以及当 Git 使用它们时——只是为了帮助你在某些 b[=525 中找到 last 提交=]通道。提交将永远冻结,并且(大部分)永久冻结(如果您无法 找到 它们,从 b运行ch 或其他名称,它们最终会消失)。
B运行ch names move。 B运行ch 名称让我们和 Git 找到提交。它们以可预测的方式移动,通过 添加 提交到 b运行ch。一些操作,例如
git rebase
或git reset
,以突然的方式移动它们,并且可能以 "less natural" 的方式移动它们,而不仅仅是前进以合并更多提交。git rebase
是关于 复制 提交。我们制作 new-and-improved 个副本,使用不同的哈希 ID,并使 b运行ch 名称指向最后一个 copied 提交。原件无法更改,但如果您移动 b运行ch name,任何未保存原件哈希 ID 的人将无法 找到原件git fetch
关于两件事:从另一个 Git 获取新提交和 更新 remote-tracking 名称如origin/master
基于其他 Git 中的内容。如果我们 did 得到新的提交,此时我们只需要记住这些 remote-tracking 名称,所以我们通常需要第二个命令。git pull
是为了方便:它 运行 是git fetch
,然后它 运行 是第二个命令,通常是git merge
.有时,这不方便。实际上,我发现它带来的不便多于它带来的便利。在那种情况下,不要使用它。