git rebase 忽略了哪些提交?

Which commits does git rebase omit?

git 文档说明如下:

The commits that were previously saved into the temporary area are then reapplied to the current branch, one by one, in order. Note that any commits in HEAD which introduce the same textual changes as a commit in HEAD..upstream are omitted (i.e., a patch already accepted upstream with a different commit message or timestamp will be skipped).

这让我有点困惑。这是否仅仅意味着被重新定位的分支中的任何提交都不会从要复制的提交集中忽略被重新定位的分支中的任何内容?

如果是:

Which seemed a bit confounding to me. Does this simply mean that any commit in the branch being rebased that doesn't change anything in the branch being rebased onto is omitted from the set of commits to be copied ?

是的,主要是因为在正常情况下,除非明确告知,否则 Git 永远不会记录空提交。相反,您在这里得到的是 git status.

返回的消息“您的工作目录是干净的”

what if new_base is specified ? does this change the set of commits from HEAD..upstream to HEAD..new_base ?

我相信这确实是他们所说的“上游”。

Why use a range ? why not just say "any commits in HEAD which introduce the same textual changes as a commit in upstream are omitted" ?

因为这就是 Git 实际上区分两个分支的方式。这个范围的底部提交是你的两个分支都开始分叉的地方。

Does this simply mean that any commit in the branch being rebased that doesn't change anything in the branch being rebased onto is omitted from the set of commits to be copied ?

没有。言归正传,您可以看到 git rebase 认为

的候选人是什么
git rev-list --reverse --no-merges @{upstream}..

及其检查的提交,以避免重新应用 already-applied 提交,

git rev-list --reverse --no-merges ..@{upstream}

检查使用git patch-id。要查看 git 在看什么,

git rev-list --reverse --first-parent --no-merges @{upstream}.. \
| git diff-tree --patch --stdin \
| git patch-id

git rev-list --reverse --no-merges ..@{upstream} \
| git diff-tree --patch --stdin
| git patch-id

除了序列在 --right-only 的内部,git format-patch --right-only @{u}... rebase 真正运行是为了获取它的信息。

除了 ,它详细介绍了 git rev-list 使用 --no-mergesgit patch-id 的技巧,我将添加以下注释:

    如果使用 --rebase-merges.,
  • --no-merges 会被抑制
  • 使用 --fork-point——这有时是默认的——rebase 将忽略 列在 <em>upstream[ 中的提交=127=]..HEAD 基于 in reflogs for 上游的数据。

后者多年来经历了多次变化。起初,fork-point 模式仅在 git pull 脚本中实现。然后它被移动到 git rebase 适当的位置,并调整了实现,现在你可以 运行 git merge-base --fork-point 找到 fork-point 提交。

使用“分叉点”旨在帮助处理 上游 rebase。也就是说,假设您在 origin 上克隆了 Git 存储库。您已将提交发送给控制该存储库的任何人。他们可能会也可能不会接受你的一些承诺。他们可能会也可能不会从其他用户那里获得一些其他提交。但是,在某些时候,他们 运行 git rebase --interactive 自己和 从他们的提交集中删除 一些提交他们在某个时候,你在某个时候重新基于

让我们画一个示例情况。他们是这样开始的:

...--o--o--*   <-- main

您克隆了存储库并创建了您自己的三个提交,我们将其称为 E-F-G,原因不明:

...--o--o--*   <-- main, origin/main
            \
             E--F--G   <-- feature-X

他们选择了四个新提交,none 与你的匹配,所以当你 运行 git fetch 你得到:

             A--B--C--D   <-- origin/feature-X
            /
...--o--o--*   <-- origin/main
            \
             E--F--G   <-- feature-X

然后您将您的 feature-X 重新定位在他们的 feature-X(您的 origin/feature-X)之上以获得:

                        E'-F'-G'  <-- feature-X
                       /
             A--B--C--D   <-- origin/feature-X
            /
...--o--o--*   <-- origin/main
            \
             E--F--G   [abandoned]

然后他们决定提交 C 错误的 所以他们重写了他们的 feature-X 以删除 C 并替换他们的 D' 新提交 D'。当你 运行 git fetch,你得到:

                  C--D--E'-F'-G'  <-- feature-X
                 /
             A--B--D'  <-- origin/feature-X
            /
...--o--o--*   <-- origin/main
            \
             E--F--G   [abandoned]

然后他们决定他们非常喜欢您的提交 GG'(无论哪个),以至于他们将其合并到 他们的 feature-X, 所以如果你再次 git fetch 你会得到:

                  C--D--E'-F'-G'  <-- feature-X
                 /
             A--B--D'-G"  <-- origin/feature-X
            /
...--o--o--*   <-- origin/main
            \
             E--F--G   [abandoned]

他们的 G" 是他们对您的 GG' 的副本:它引入了与您的提交相同的 更改 G' 对你的提交做了 F',但行号不匹配。

理想情况下您希望git rebase以某种方式自动确定他们的提交CD,现在看起来像是 你的 提交,是 他们的 提交,并被删除以支持他们的 D',并且他们的承诺 G" 与您的 G' “一样好”。所以你会希望 git rebase 产生这个:

                  C--D--E'-F'-G'  [abandoned]
                 /
             A--B--D'-G"  <-- origin/feature-X
            /          \
...--o--o--*            E"-F"  <-- feature-X
            \
             E--F--G   [abandoned]

也就是说,您希望 git rebase 能够:

  • 复制提交C,即使你有一个而他们没有;
  • 复制提交D',并且
  • 复制提交G'.

git rebase 使用的 patch-ID 技巧可以应付 D'G' 这里但不会正确省略 C。 fork-point代码正确省略C提供你的origin/feature-Xb运行ch reflog 中包含正确的信息。只要所有这些 activity 都发生在过去 90 天左右的时间内,这通常是正确的。

有关 --fork-point 选项的更多信息,请参阅 and (of course) the git rebase documentation