Git rebase - 在分叉点模式下提交选择

问题描述 投票:0回答:2

阅读

git rebase
git merge-base
man 文档:

在使用 git checkout -b topic origin/master 创建的主题分支上工作后,远程跟踪分支 origin/master 的历史记录可能已被倒回并重建,从而导致此历史记录 形状:

                        o---B1
                       /
       ---o---o---B2--o---o---o---B (origin/master)
               \
                B3
                 \
                  Derived (topic)

origin/master 曾经指向提交 B3、B2、B1,现在它指向 B,当 origin/master 位于 B3 时,您的主题分支是在它之上启动的。此模式使用 reflog origin/master 找到 B3 作为分叉点,以便主题可以在更新的 origin/master 之上重新基于:

$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic

$fork_point
(如果我理解正确的话)将是提交对象
B3
,因此提交
B3..topic
将重新基于
origin/master
分支。

Q1 为什么省略

B3
提交很有用?
topic
分支的提交构建在
B3
提交之上,因此省略它意味着它的修改将在
origin/master
分支的故事中丢失。重新调整
B3
提交
topic
分支将带来更清晰的历史记录,不是吗?

Q2 有人可以链接/简要描述 git 工作流程中

--fork-point
选项的实际用例吗?

git github version-control
2个回答
17
投票

您是对的,

$fork_point
将是
B3

相信这里的目的是省略

B3
作为“不是你的承诺”。

我认为 Git 人员在这里画的图表不太好。以下是我如何在不进行太多更改的情况下重绘和重写它(尽管我可能只是在每次提交时重新输入字母)。


您首先克隆(或以其他方式更新)一些 (

origin
) 存储库,其图表以提交
B3
结尾,然后创建一个主题分支并进行一些提交:

...--o---F---B3    <-- origin/master
              \
               G   <-- topic

随着时间的推移,加上额外的

git fetch
-es 和
git commit
,你的提交图现在看起来像这样:

...--o---F---B3--B2--B1    <-- origin/master
              \
               G---H---I   <-- topic

但是,突然之间,在另一个

git fetch
之后,你自己的提交图现在看起来像这样:

                 o---B1'       <-- origin/foo
                /
...o---F---B2'-o---o---o---B   <-- origin/master
        \
         B3--G---H---I         <-- topic

也就是说,Git 现在会认为提交 B3 属于您的主题分支,而事实上,您的工作从提交

G
开始。拥有名为
origin
的存储库的人实际上已经声明提交
B3
很糟糕,应该被丢弃。 (他们在
B2
上保留了一份
B2'
作为
master
,在他们的
B1
上保留了
B1'
作为
foo
。)

如果您简单地

git rebase
,您将复制原始提交
B3
到新副本
B3'
(同时也复制
G-H-I
):

                 o---B1'                     <-- origin/foo
                /
...o---F---B2'-o---o---o---B                 <-- origin/master
                            \
                             B3'-G'--H'--I'  <-- topic

但你更喜欢:

                 o---B1'                 <-- origin/foo
                /
...o---F---B2'-o---o---o---B             <-- origin/master
                            \
                             G'--H'--I   <-- topic

要让

git rebase
执行此操作,您必须指示 Git 定位提交
B3
。您对
origin/master
的引用日志包含所有
F
B3
B2
B1
(在至少一个引用日志条目下,包括本例中的
origin/master@{1}
),而您自己的
topic
F
B3
,但也没有
B2
B1
。因此
--fork-point
选择
B3
作为最新(最尖端)的共享提交,而不是
F


这里的关键句子/想法是上游存储库编写者打算完全放弃提交

B3

(你应该如何确定这一点有点神秘。如果需要变基,例如丢弃一个不应该提交的文件,

B2'
B1'
是副本可能并不明显- 并且在
B1
中,这就是为什么
B1
也被丢弃。事实上,现在在
B2'
B3'
中省略了该文件,这使得它们不是补丁等效的,因此不是明显的副本。)

(请注意,您自己的

master
也仍然指向
B3
!)


0
投票

我的回答没有解决原始问题,但提供了一些指导,如何在 B3 被认为是主题分支的一部分的情况下恢复并进行适当的变基(应该变基而不是删除)。

首先,我们假设错误的变基刚刚完成,我们需要从中恢复。我们可以使用以下命令来做到这一点:

$ git reset --hard ORIG_HEAD

现在我们要修复我们的分叉点变基。让我们找到坏的分叉点:

$ git merge-base --fork-point origin/master topic
<B3-full-hash>

或简称:

$ git rev-parse --short $(git merge-base --fork-point origin/master topic)
<B3-short-hash>

现在让我们找到上游分支不需要的引用日志条目:

$ git reflog show origin/master | grep <B3-short-hash>
<B3-short-hash> ... origin/master@{3}: ...
<B3-short-hash> ... origin/master@{7}: ...
...

可能有多个引用错误分叉点的引用日志条目。现在我们应该删除它们。列表中从最低到最高:

...
$ git reflog delete origin/master@{7}
$ git reflog delete origin/master@{3}

一旦完成

--fork-point
将不再能够找到坏的分叉点。我们可以再次重新运行我们的变基:

$ git rebase --fork-point origin/master

如图所示,这并不是那么简单的事情,仍然需要非常小心。因此,在历史上找到适当的基础/上游并运行

git rebase --onto=origin/master HEAD~2
可能会更容易。

© www.soinside.com 2019 - 2024. All rights reserved.