`git rebase --fork-point master`的含义是什么?

5

我的使用场景是在发布之前,在功能分支中更改提交,例如修改提交消息,压缩一些提交等。 我不想将提交移动到新的基础上。

为此,我通常会像这样做:

git rebase -i HEAD~4

在我的特性分支中手动计算提交次数,结果为“4”。

我想知道 Git 是否有像“开始交互式重置我的特性分支中的所有提交,但不要移动它们到较新的master——只需保持原地”这样的命令。我找到了git rebase--fork-point选项并尝试了以下命令:

git rebase -i --fork-point master

然而,这没有任何显著影响,行为与git rebase -i master相同。

相反,这才是我需要的:

git rebase -i $(git merge-base --fork-point master)

我阅读了git rebase文档中关于--fork-point的说明,但不太理解为什么它没有产生我预期的结果。请有人能够解释一下吗?

4个回答

3
由于 --fork-point 与决定新提交的基础无关[1],所以它没有带来您期望的结果。因此,默认情况下,新提交将基于上游 (master 在这种情况下),--fork-point 不会影响到这一点。
(作为参考,--fork-point 的作用是使用reflogs来细化“猜测”哪些提交应该被重写的计算。但据我经验,这往往不是非常有用的。)
您有两个选择:将合并基础用作上游 - 正如您描述的那样 - 或使用 --onto 选项显式设置新的基础(在本例中将其设置为与原始基础匹配)。
[1] - 请记住,即使在概念上您正在编辑提交,但实际上rebase总是编写新提交 - 除非它什么都不做。因此,当它“编辑”一个提交时,它实际上创建了类似于旧提交但已编辑的新提交。

3
我期望下面更简单的调用能够满足您的需求。
git rebase -i $(git merge-base HEAD master)
git merge-base --fork-point 的文档显示该选项在复杂历史情况下非常有用。您的问题并未表明您一直在进行大量的历史重写,因此在您的情况下使用 --fork-point 可能过于繁琐。

Discussion on fork-point mode

After working on the topic branch created with

git switch -c topic origin/master

the history of remote-tracking branch origin/master may have been rewound and rebuilt, leading to a history of this shape:

                 o---B2
                /
---o---o---B1--o---o---o---B (origin/master)
        \
         B0
          \
           D0---D1---D (topic)

where origin/master used to point at commits B0, B1, B2 and now it points at B, and your topic branch was started on top of it back when origin/master was at B0, and you built three commits, D0, D1, and D, on top of it. Imagine that you now want to rebase the work you did on the topic on top of the updated origin/master.

In such a case, git merge-base origin/master topic would return the parent of B0 in the above picture, but B0^..D is not the range of commits you would want to replay on top of B (it includes B0, which is not what you wrote; it is a commit the other side discarded when it moved its tip from B0 to B1).

git merge-base --fork-point origin/master topic is designed to help in such a case. It takes not only B but also B0, B1, and B2 (i.e. old tips of the remote-tracking branches your repository’s reflog knows about) into account to see on which commit your topic branch was built and finds B0, allowing you to replay only the commits on your topic, excluding the commits the other side later discarded.

git rebase --fork-point文档git rebase --fork-pointgit merge-base --fork-point联系起来。

When --fork-point is active, forkpoint will be used instead of upstream to calculate the set of commits to rebase, where forkpoint is the result of

git merge-base --fork-point <upstream> <branch>

command. (See git-merge-base.) …


谢谢,"关于分叉点模式的讨论"部分解释得很清楚。仅仅通过阅读git rebase文档,我并没有意识到它的作用。 - Borek Bernard

1
我相信这可能是您正在寻找的内容:

# uses "graph" to determine topological "fork point"
❯ git rebase --interactive --no-fork-point UPSTREAMREFNAME FEATURE --keep-base

# uses reflog to determine historical "fork point"
❯ git rebase --interactive --fork-point UPSTREAMREFNAME FEATURE --keep-base

They can be simplified to:

[HEAD -> feature] ❯ git rebase -i UPSTREAMREFNAME
[HEAD -> feature] ❯ git rebase -i --fork-point UPSTREAMREFNAME
详细说明:

  • UPSTREAMREFNAME FEATURE用于计算要重新基于的提交范围。

    • 如果指定了--fork-point,生成的提交范围等同于$(git merge-base --fork-point UPSTREAMREFNAME FEATURE)..FEATURE。 "分叉点"是根据reflog确定的,在UPSTREAMREFNAME的生命周期内,FEATUREUPSTREAMREFNAME分支引出/分叉时最近一次调用/命令的确切哈希值。

      • 生成的提交范围表示:所有FEATURE的祖先提交,一直回到[在reflog中]从指定的主干/上游分支UPSTREAMREFNAME分叉的地方。
    • 如果指定了--no-fork-point,生成的提交范围等同于UPSTREAMREFNAME..FEATURE。 "分叉点"是基于历史图的拓扑(排列)确定的。这意味着"分叉点"将是UPSTREAMREFNAMEFEATURE共享的最早提交,即它们在图中相交的最早点。

      • 生成的提交范围表示:所有从FEATURE可达的提交[即遍历历史图],但不包括从UPSTREAMREFNAME可达的提交。
    • 重要提示:如果省略了FEATURE,它将默认为HEAD,这意味着,如果您在功能分支上检出[任何位置],则不必指定FEATURE,它将正常工作,否则您必须指定它,否则可能会得到意外结果。

    • UPSTREAMREFNAME,也称为<upstream>git-rebase(1)文档中,必须是引用的名称(例如分支、标签)

    • FEATURE,也称为<branch>topicgit-rebase(1)文档中,技术上是一个"提交-ish"参数,这意味着它可以是任何(任何符号)解析为提交对象名称(哈希ID)的东西。

  • --keep-base指定重新创建的提交范围所基于的提交基础。

    • 提交基础计算为UPSTREAMREFNAMEFEATURE的合并基础,即等同于--onto $(git merge-base UPSTREAMREFNAME FEATURE)

参考文献:

  • git-rebase(1)
  • git-merge-base(1):讨论了可以找到两个或多个提交的合并基础的[管道]命令,定义和说明了“分叉点”等内容。
  • gitrevisions(7):详细讨论了“提交-ish”符号。
  • git-rev-parse(1):讨论了[管道]命令,可以将符号解析为对象名称等内容。

1

Git 2.24 将引入一个新选项, --keep-base:

"git rebase --keep-base " 尝试找到正在被 rebase 的主题的原始基础,并在该相同基础之上进行 rebase,这在运行 "git rebase -i"(及其有限变体 "git rebase -x")时非常有用。

听起来这可能是 OP 中使用情况的解决方案,但我还没有尝试过。


你试过了吗? - iconoclast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接