【问题标题】:Why is "rebase --onto ABC" different than "rebase ABC"?为什么“rebase --onto ABC”与“rebase ABC”不同?
【发布时间】:2017-07-25 19:30:01
【问题描述】:

使用 git 2.11,git rebase 文档说:

当前分支被重置为 ,或者如果 --onto 提供了选项。这与 git reset 具有完全相同的效果 --硬(或)。 ORIG_HEAD 设置为在重置之前指向分支的尖端。

我理解为upstreamnewbase 指向同一个“基本引用”,那么这意味着下面的两个rebase 语法是等价的:

git rebase ABC
git rebase --onto ABC

这是我设置的演示。假设当前分支是FeatureABC,它与远程分支完全同步。

#---create two identical branches, behind current branch by 5 commits
(FeatureABC) git branch Demo1-Rebase-ABC      HEAD~4
(FeatureABC) git branch Demo2-Rebase-onto-ABC HEAD~4

#---Make a new commit in branch Demo1
git checkout Demo1-Rebase-ABC
echo "Demo of: git rebase FeatureABC Demo1-Rebase-ABC" > ./Demo1_BogusFile.txt
git add ./Demo1_BogusFile.txt
git commit -m "Create file Demo1_BogusFile.txt"

git rebase FeatureABC

首先,倒带头在上面重播您的工作
... 应用:创建文件 Demo1_BogusFile.txt

git log --oneline -3 表明分支 Demo1-Rebase-ABC 与 FeatureABC 的 HEAD 同步。并且提交“创建文件 Demo1_BogusFile.txt”被正确应用在它上面。

#---Make a new commit in branch Demo2
git checkout Demo2-Rebase-onto-ABC
echo "Demo of: git rebase --onto FeatureABC Demo2-Rebase-onto-ABC" > ./Demo2_Onto_BogusFile.txt
git add ./Demo2_Onto_BogusFile.txt
git commit -m "Create file Demo2_Onto_BogusFile.txt"

git rebase --onto FeatureABC

当前分支没有跟踪信息。请 指定要针对哪个分支进行变基。请参阅 git-rebase(1) 了解 详情。

git rebase <branch>

如果您想为此分支设置跟踪信息,您可以这样做 与:

git branch --set-upstream-to=origin/<branch> Demo2-Rebase-onto-ABC

我误解了警告信息。认为使用 --onto 时 git 在默认值中感到困惑。所以我只是想通过告诉 git 我想要变基的当前分支来“帮助”

git rebase --onto FeatureABC Demo2-Rebase-onto-ABC

首先,倒带头在上面重播你的工作......

git log --oneline -3 表明分支Demo2-Rebase-onto-ABC 变为相同 而不是FeatureABC。最后一次提交“创建文件Demo2_Onto_BogusFile.txt”已经消失,文件./Demo2_Onto_BogusFile.txt被删除。

问题git rebase --onto FeatureABC Demo2-Rebase-onto-ABC 没有应用在Demo2-Rebase-onto-ABC 分支上所做的新提交的原因是什么?

【问题讨论】:

  • 分支中有什么。.remote 和 branch..merge 演示分支的选项?
  • @oyvind 你能告诉我运行 git 命令来获取这些信息吗?
  • git config --get branch.Demo2-Rebase-onto-ABC.merge
  • git config --get branch.Demo1-Rebase-ABC.merge
  • git config --get branch.Demo2-Rebase-onto-ABC.remote

标签: git git-rebase


【解决方案1】:

它们不一样,--fork-point 选项也会使这变得复杂。我认为这可能会让您感到困扰,尽管仅根据您所描述的内容无法确定,因为您概述的步骤之一只会产生错误。

我从一个合理的猜测开始,但它一个猜测

要查看实际发生的情况,绘制(部分)提交图非常有帮助,特别注意标签,因为您使用的多个名称都指向一个提交。

假设当前分支是FeatureABC,它与远程分支完全同步。

因此我们有这样的东西——但是这样的东西还不够好; 有存储库,所以应该画图;我不得不猜测:

...--o--A--B--C--D--E   <-- FeatureABC (HEAD), origin/FeatureABC

现在你运行:

#---create two identical branches, behind current branch by 5 commits
(FeatureABC) git branch Demo1-Rebase-ABC      HEAD~4
(FeatureABC) git branch Demo2-Rebase-onto-ABC HEAD~4

由于HEAD~4名称提交AHEAD~1DHEAD~2C,等等),我们需要做一些事情来标记这两个新名称指向的事实提交A。不过,我会将名称缩短为 Demo1Demo2。 (此时我已经创建了一个仅包含 oE 提交的存储库,并在此处实际运行 git branch Demo1 HEAD~4; git branch Demo2 HEAD~4。)

...--o--A              <-- Demo1, Demo2
         \
          B--C--D--E   <-- FeatureABC (HEAD), origin/FeatureABC

顺便说一句,git log --all --decorate --oneline --graph(有人说“从狗那里得到帮助”)以这种方式显示了这个测试存储库(在我的例子中没有origin/ 分支):

* c4a0671 (HEAD -> master) E
* a7b8ae4 D
* 3deea72 C
* b11828d B
* ffc29b5 (Demo2, Demo1) A
* 3309a8d initial

接下来,你看看Demo1,移动HEAD

git checkout Demo1-Rebase-ABC
...--o--A              <-- Demo1 (HEAD), Demo2
         \
          B--C--D--E   <-- FeatureABC, origin/FeatureABC

并修改工作树,将修改后的文件添加到索引中,然后提交,以进行新的提交,我将其称为F,它更新了HEAD 分支,因此将Demo1 和@987654355 分开@。我现在将在这里使用我自己的命令及其输出:

$ git checkout Demo1
Switched to branch 'Demo1'
$ echo demo1 > demo1.txt && git add demo1.txt && git commit -m F
[Demo1 89773b6] F
 1 file changed, 1 insertion(+)
 create mode 100644 demo1.txt

绘制图表变得有点困难;我会用一行:

          F            <-- Demo1 (HEAD)
         /
...--o--A              <-- Demo2
         \
          B--C--D--E   <-- FeatureABC, origin/FeatureABC

现在我们开始执行您的第一个git rebase 命令。我必须使用master,当然:

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: F

这适用于当前分支(HEADDemo1)。它会找到在HEAD 上但不在FeatureABC 上的提交(FeatureABC..gitrevisions 语法中)。那是提交F。这些提交被放入到提交列表中也许 复制—git rebase 将检查具有相同git patch-id 的提交并跳过它们,尽管很明显这里没有发生这种情况。所以现在将提交F 复制到新的提交F',具有不同的哈希ID 和不同的基数:

          F              [abandoned]
         /
...--o--A                <-- Demo2
         \
          B--C--D--E     <-- FeatureABC, origin/FeatureABC
                    \
                     F'  <-- Demo1 (HEAD)

(这是实际的git log 输出,显示了副本的新提交哈希。除非我在命令中添加Demo1@{1},否则不会显示原始的,现已废弃的F,我在此处执行此操作。原始是 second F 显示的,即较早的提交:

$ git log --all --decorate --oneline --graph Demo1@{1}
* c1d0896 (HEAD -> Demo1) F
* c4a0671 (master) E
* a7b8ae4 D
* 3deea72 C
* b11828d B
| * 89773b6 F
|/  
* ffc29b5 (Demo2) A
* 3309a8d initial

我更喜欢水平图,但是这个有更多的信息,特别是缩写的哈希 ID。)

Reproducer 失败,我得再猜一次

现在我们尝试使用Demo2 重复此操作,但失败了。这是我的实际命令,剪切和粘贴。第一步工作正常:

$ git checkout Demo2
Switched to branch 'Demo2'
$ echo demo2 > demo2.txt && git add demo2.txt && git commit -m G
[Demo2 ae30665] G
 1 file changed, 1 insertion(+)
 create mode 100644 demo2.txt

不再画原来的F,这是新图。我把G 放在了F 以前的位置,虽然我可以把它画成...--o--A--G

          G              <-- Demo2 (HEAD)
         /
...--o--A
         \
          B--C--D--E     <-- FeatureABC, origin/FeatureABC
                    \
                     F   <-- Demo1

但是,rebase 不起作用。我必须再次使用master 而不是FeatureABC,但这在您的示例中的行为方式相同,因为git branch 命令没有设置上游(“跟踪”)名称:

$ git rebase --onto master
There is no tracking information for the current branch.
Please specify which branch you want to rebase against.
See git-rebase(1) for details.

    git rebase <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=<remote>/<branch> Demo2

git rebase 失败并显示此错误消息的原因是 --onto has absorbed the argument as &lt;newtarget&gt;, leaving us with no &lt;upstream&gt;

如果未指定&lt;upstream&gt;,则将使用branch.&lt;name&gt;.remotebranch.&lt;name&gt;.merge 选项中配置的上游(详见git-config(1)并假定--fork-point 选项。如果您当前不在任何分支上,或者当前分支没有配置上游,rebase 将中止。

这里的粗体字是我的,但我认为它也是关键。我假设你运行了一个git rebase --onto &lt;somename&gt;没有失败。为了让它没有失败,你的分支必须有一个上游集。上游可能 origin/FeatureABC 或类似的,这意味着就 Git 而言,你正在运行:

git rebase --onto FeatureABC --fork-point origin/FeatureABC

不是

git rebase --onto FeatureABC --no-fork-point origin/FeatureABC

有些further reading in the (overly cryptic, in my opinion) git rebase documentation会翻出这句话:

如果在命令行中给出&lt;upstream&gt;--root,则 默认为--no-fork-point,否则默认为 --fork-point.

换句话说:

git rebase FeatureABC

关闭--fork-point 选项,如下所示:

git rebase --onto FeatureABC FeatureABC

但是:

git rebase

或:

git rebase --onto FeatureABC

保留--fork-point 选项on

--fork-point 是关于什么

--fork-point目标 是专门drop 提交,这些提交曾经一度在您的上游,但不再在您的上游。有关示例,请参阅Git rebase - commit select in fork-point modeThe specific mechanism is complicated and relies on the upstream branch's reflog. 由于我没有您的存储库或您的 reflog,因此我无法测试您的具体案例 - 但这是一个原因,并且可能是最可能的原因,因为您的问题中的提示是,提交 影响 rebase tree 结果 会被丢弃。由于与上游提交具有相同的patch ID 而被丢弃的提交是 [edit:] 通常1 不会 影响的提交最后一次复制的提交的最终树:它们只会导致合并冲突和/或强制您使用git rebase --skip 跳过它们(如果包含它们)。


1写完这篇文章后我突然想到有一个重要的例外(这可能与最初的问题无关,但我应该提一下)。将一个特性或主题分支重新定位到一个更主线的分支上,当一个提交首先从特性中挑选出 out 到主线中,然后在主线中 reverted,将造成问题。考虑一下,例如:

...--o--*--P--Q--C'-R--S--X--T   <-- mainline
         \
          A--B--C--D--E          <-- topic

其中C' 是提交C 的副本,X 是提交C 的还原,它不应该被放入mainline。正在做:

git checkout topic
git rebase mainline

将指示 Git 将提交 AE 放入“候选复制”列表中,但还要查看 PT 以查看是否已采用任何提交。提交C 采纳,为C'。如果CC' 具有相同的补丁ID——通常,它们——Git 会将C 从列表中删除为“已复制”。但是,C 在提交 X 中被明确还原

做rebase的人需要注意,如果需要和适当的话,仔细恢复C

这种特殊行为不是git merge 的问题(因为合并忽略中间提交),只有git rebase 有问题。

【讨论】:

  • “我假设你运行了一个没有失败的git rebase --onto &lt;somename&gt;”。哦,这个……我认为这是一个微不足道的细节,哎呀。事实上,我得到了同样的错误“当前分支没有跟踪信息”。所以我跑了git rebase --onto FeatureABC Demo2。错误消失了。不知道为什么,因为我虽然 rebase 默认知道如何在当前分支上操作。我显然做了一个糟糕的 cmd b/c,其效果是它清除了在 Demo2 中所做的新提交,并且也无可挽回地删除了 Demo2.txt 文件。
  • 重新运行我的测试并且可以重现您在执行git rebase --onto master 时描述的错误(当前分支没有跟踪信息)。事实上,当我问这个问题时,我最初是git rebase --onto FeatureABC Demo2。我没有意识到这有很大的不同。最令人费解的是 Demo2 分支中最新提交的删除。而--fork-point 确实是原因。阅读您的答案Git rebase - commit select in fork-point mode 后。我现在明白为什么了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多