为什么" rebase - tenc"不同于" rebase ABC"?

时间:2017-03-06 03:15:37

标签: git git-rebase

使用git 2.11,git rebase文档说:

  

当前分支重置为< upstream>或< newbase>如果 -   选项已提供。这与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在默认值中混淆了。所以我只想&#34;帮助&#34;通过告诉git当前分支我想要改变

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

首先,倒带头重播你的作品......

git log --oneline -3表示分支Demo2-Rebase-onto-ABC变得相同而不是FeatureABC。最后一次提交&#34;创建文件Demo2_Onto_BogusFile.txt&#34;已消失,文件./Demo2_Onto_BogusFile.txt已删除。

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

1 个答案:

答案 0 :(得分:5)

它们不一样,--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(&#34;得到A DOG&#34的帮助;正如有人说的那样)以这种方式显示此测试存储库(在我的情况下没有origin/分支):< / p>

* 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分开1}}和Demo2。我现在在这里使用我自己的命令及其输出:

$ 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上的提交(gitrevisions语法中的FeatureABC..)。那个提交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输出,显示了副本的新提交哈希。除非我添加F,否则原始的,现在已弃用的Demo1@{1}不会显示这个命令,我在这里做的。原来是显示的第二个 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。)

生产者失败了,我不得不再次猜测

现在我们尝试用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命令没有设置上游(&#34;跟踪&# 34;)名称:

$ 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 <newtarget>, leaving us with no <upstream>

  

如果未指定<upstream>,将使用branch.<name>.remotebranch.<name>.merge选项中配置的上游(有关详细信息,请参阅git-config(1)和{{1假设选项。如果您当前不在任何分支上,或者当前分支没有配置上游,则rebase将中止。

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

origin/FeatureABC

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

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

  

如果在命令行上给出了git rebase --onto FeatureABC --no-fork-point origin/FeatureABC <upstream>,那么    默认值为--root,否则默认值为    --no-fork-point

换句话说:

--fork-point

关闭 git rebase FeatureABC 选项,如下所示:

--fork-point

但:

git rebase --onto FeatureABC FeatureABC

或:

git rebase

git rebase --onto FeatureABC 选项留在

--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 树结果的提交将被删除。由于与上游提交具有相同patch ID而被删除的提交是[编辑:]经常 1 不影响最后复制的提交的最后一个树:它们只会导致合并冲突和/或强制您使用--fork-point跳过它们,如果它们被包含在内。

1 在写完之后我发现有一个重要的例外(这可能与原始问题无关,但我应该提及)。将功能或主题分支重新分配到更多主线分支上,当首次将功能 out 提取到主线中,然后在主线中还原时,将导致问题。考虑一下,例如:

git rebase --skip

其中...--o--*--P--Q--C'-R--S--X--T <-- mainline \ A--B--C--D--E <-- topic 是提交C'的副本,而C是提交X的还原,尚未放入C。这样做的:

mainline

将指示Git将git checkout topic git rebase mainline 通过A提交到&#34;候选人中以复制&#34;列表,但也请查看EP以查看是否已采用任何内容。提交T ,为C。如果C'C通常具有相同的修补程序ID,则 -Git将从列表中删除C',因为&#34;已经复制&#34 ;。但是,CC已在提交X中明确还原

如果需要并且适当的话,任何人都需要注意,并仔细恢复C

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