为什么"rebase --onto ABC"与"rebase ABC"不同?

Pol*_*ase 2 git git-rebase

使用git 2.11,git rebase文档说:

如果提供了--onto选项,则当前分支将重置为<upstream>或<newbase>.这与git reset --hard(或)具有完全相同的效果.ORIG_HEAD设置为在重置之前指向分支的尖端.

我理解它upstream并且newbase指向相同的"基本引用",这意味着下面的两个rebase语法是等价的:

git rebase ABC
git rebase --onto ABC
Run Code Online (Sandbox Code Playgroud)

这是我设置的演示.让我们假设当前分支是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
Run Code Online (Sandbox Code Playgroud)

首先,倒带头重播你的工作
...应用:创建文件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
Run Code Online (Sandbox Code Playgroud)

当前分支没有跟踪信息.请指定您要反对的分支.有关详细信息,请参阅git-rebase(1).

git rebase <branch>
Run Code Online (Sandbox Code Playgroud)

如果您希望为此分支设置跟踪信息,可以使用以下命令:

git branch --set-upstream-to=origin/<branch> Demo2-Rebase-onto-ABC
Run Code Online (Sandbox Code Playgroud)

我误解了警告信息.当使用--onto时,认为git在默认值中混淆了.所以我只想通过告诉git当前的分支我想要"帮助"

git rebase --onto FeatureABC Demo2-Rebase-onto-ABC
Run Code Online (Sandbox Code Playgroud)

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

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分支机构的新提交的原因是什么?

tor*_*rek 5

它们不一样,这也可能因--fork-point选项而变得复杂.我认为这可能有点像你,虽然不可能确定,只是从你所描述的内容,因为你概述的步骤之一只会产生错误.

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

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

让我们假设当前分支是FeatureABC与远程分支完全同步.

因此我们有这样的东西 - 但是这样的东西不够好; 有存储库,所以应该绘制图形; 我猜:

...--o--A--B--C--D--E   <-- FeatureABC (HEAD), origin/FeatureABC
Run Code Online (Sandbox Code Playgroud)

现在你运行:

#---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
Run Code Online (Sandbox Code Playgroud)

由于HEAD~4名称提交A(HEAD~1D,HEAD~2C等等),我们需要做一些事情来标记这两个新名称指向提交的事实A.我要缩短名字只是Demo1Demo2虽然.(我创建了一个信息库,只有承诺o通过E在这一点上,与实际运行git branch Demo1 HEAD~4; git branch Demo2 HEAD~4在这里.)

...--o--A              <-- Demo1, Demo2
         \
          B--C--D--E   <-- FeatureABC (HEAD), origin/FeatureABC
Run Code Online (Sandbox Code Playgroud)

顺便说一下,git log --all --decorate --oneline --graph("有人把它从A DOG那里获得帮助")以这种方式显示了这个测试库(origin/在我的例子中没有分支):

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

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

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

并修改工作树,将修改后的文件添加到索引,并提交,以进行我将调用的新提交F,更新HEAD分支,从而分离Demo1Demo2.我现在将使用我自己的命令及其输出:

$ 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
Run Code Online (Sandbox Code Playgroud)

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

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

现在我们开始你的第一个git rebase命令.我必须使用master,当然:

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: F
Run Code Online (Sandbox Code Playgroud)

这适用于当前分支(HEADDemo1).它发现HEAD没有打开的提交FeatureABC(FeatureABC..gitrevisions语法中).这是承诺F.这些提交被放入一个可能复制的提交列表中 - git rebase将检查具有相同的提交git patch-id并跳过它们,尽管显然这里没有发生.所以现在将commit F复制到新的commit F',具有不同的hash ID和不同的base:

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

(这是实际的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
Run Code Online (Sandbox Code Playgroud)

我更喜欢水平图,但是这个有更多的信息,特别是缩写的哈希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
Run Code Online (Sandbox Code Playgroud)

不再绘制原始图F,这是新图.我把它放在原GF,虽然我可以把它画成...--o--A--G:

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

然而,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
Run Code Online (Sandbox Code Playgroud)

git rebase失败的原因是这个错误消息--onto已经吸收了这个论点<newtarget>,让我们没有<upstream>:

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

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

git rebase --onto FeatureABC --fork-point origin/FeatureABC
Run Code Online (Sandbox Code Playgroud)

不是:

git rebase --onto FeatureABC --no-fork-point origin/FeatureABC
Run Code Online (Sandbox Code Playgroud)

一些的(过于神秘,在我看来)在进一步阅读的git rebase文档会变成了这样一句话:

如果在命令行中给出了<upstream>或者--root是,则默认为--no-fork-point,否则默认为 --fork-point.

换一种说法:

git rebase FeatureABC
Run Code Online (Sandbox Code Playgroud)

关闭--fork-point选项,一样:

git rebase --onto FeatureABC FeatureABC
Run Code Online (Sandbox Code Playgroud)

但:

git rebase
Run Code Online (Sandbox Code Playgroud)

要么:

git rebase --onto FeatureABC
Run Code Online (Sandbox Code Playgroud)

离开--fork-point选项.

什么--fork-point是关于

目标--fork-point是专门下降曾经是提交,在同一时间,在你的上游,但不再在你的上游.有关示例,请参阅Git rebase - 以fork-point模式提交select. 具体机制很复杂,依赖于上游分支的reflog. 由于我没有您的存储库或您的reflog,我无法测试您的具体情况 - 但这是一个原因,并且可能是在您的问题中给出提示的最可能的原因,一个影响rebase 树结果的提交会放弃了.这是由于具有相同扔下提交补丁ID作为上游犯是那些[ 编辑:]通常1不会影响到最终的树最后复制的承诺:他们只会导致合并冲突和/或强迫你用于git rebase --skip跳过它们,如果它们被包括在内.


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

...--o--*--P--Q--C'-R--S--X--T   <-- mainline
         \
          A--B--C--D--E          <-- topic
Run Code Online (Sandbox Code Playgroud)

其中C'是commit的副本C,并且XC尚未放入的commit的恢复mainline.这样做:

git checkout topic
git rebase mainline
Run Code Online (Sandbox Code Playgroud)

将指示的Git把承诺A通过E进入"考生复制"列表中,还看P通过T,看看是否有已经通过.承诺C 采纳为C'.如果C并且C'具有相同的补丁ID - 通常,它们 -Git将从C列表中删除为"已经复制".但是,在提交C中显式还原X.

C如果需要并且适当,那么谁需要注意,并仔细恢复.

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