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

标签 git git-rebase

使用 git 2.11,git rebase文档说:

The current branch is reset to <upstream>, or <newbase> if the --onto option was supplied. This has the exact same effect as git reset --hard (or ). ORIG_HEAD is set to point at the tip of the branch before the reset.



我理解的好像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

First, rewinding head to replay your work on top of it
... Applying: Create file 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

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=origin/<branch> Demo2-Rebase-onto-ABC


我误解了警告信息。认为 git 在使用 --onto 时在默认值中被混淆了。所以我只想通过告诉 git 我要重新设置的当前分支来“帮助”
git rebase --onto FeatureABC Demo2-Rebase-onto-ABC

First, rewinding head to replay your work on top of it...


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 所做的新提交分支?

最佳答案

它们不一样,这可能会因 --fork-point 而变得复杂。选项。我认为这可能是您的问题,尽管无法确定,仅从您所描述的内容来看,因为您概述的步骤之一只会产生错误。

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

要查看真正发生的事情,绘制(部分)提交图非常有帮助,特别注意标记,因为您使用了多个名称,所有名称都指向单个提交。

Let's assume the current branch is FeatureABC it is perfectly in sync with the remote branch.



因此,我们有这样的东西——但这样的东西还不够好;您有存储库,因此您应该绘制图形;我不得不猜测:
...--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名称提交 A ( HEAD~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分支并因此分隔 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

绘制图形变得有点困难;我将使用一行:
          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 输出,显示副本的新提交哈希。原始的,现在已放弃的 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 在您的示例中的行为方式相同命令未设置上游(“跟踪”)名称:
$ 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> :

If <upstream> is not specified, the upstream configured in branch.<name>.remote and branch.<name>.merge options will be used (see git-config(1) for details) and the --fork-point option is assumed. If you are currently not on any branch or if the current branch does not have a configured upstream, the rebase will abort.



这里的粗体是我的,但我认为它也是关键。我假设您运行了 git rebase --onto <somename>那没有失败。为了它没有失败,你的分支必须有一个上游集。那个上游可能是 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会出现这句话:

If either <upstream> or --root is given on the command line, then the default is --no-fork-point, otherwise the default is --fork-point.



换句话说:
git rebase FeatureABC

关闭 --fork-point选项,如:
git rebase --onto FeatureABC FeatureABC

但:
git rebase

或者:
git rebase --onto FeatureABC

离开 --fork-point选项。

什么 --fork-point是关于
--fork-point的目标是专门删除曾经在您的上游但不再在您的上游的提交。见 Git rebase - commit select in fork-point mode举个例子。 The specific mechanism is complicated and relies on the upstream branch's reflog.由于我没有您的存储库或您的 reflog,因此我无法测试您的具体情况 - 但这是一个原因,并且可能是考虑到您问题中的提示的最可能的原因,即会影响 rebase 树结果的提交会掉线。由于具有相同的 patch ID 而丢弃的提交作为上游提交的是 [ 编辑 :] 经常 1 不会影响上次复制提交的最终树:它们只会导致 merge 冲突和/或迫使您使用 git rebase --skip跳过它们,如果它们被包括在内。

1写完这篇文章后,我想到有一个重要的异常(exception)(这可能与最初的问题无关,但我应该提到)。将一个功能或主题分支重新定位到更主线的分支上,当提交首先从功能中挑选出来进入主线,然后在主线中恢复时,会导致问题。考虑,例如:
...--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 提交提交 A通过 E进入“要复制的候选人”名单,还要看P通过 T看看是否已经采用了。提交 C被采用,为 C' .如 CC'具有相同的补丁 ID——通常,它们会——Git 将丢弃 C从列表中作为“已复制”。然而,C已在提交 X 中明确还原.

谁做rebase需要注意,小心恢复C如果需要和适当。

这种特殊行为对于 git merge 来说不是问题(因为 merge 忽略中间提交),仅适用于 git rebase .

关于git - 为什么 "rebase --onto ABC"与 "rebase ABC"不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42616979/

相关文章:

git - git rebase通过提交提交

git - NPM 安装在 dockerized env 中失败

git - 无法克隆存储库 : git@gitlab. com : Permission denied (publickey, 键盘交互)

git rebase 一个分支,因为它被创建

git rebase 真正的旧提交

git - 如何执行 Git "Do not rebase published commits"规则?

git - 如何在 rebase 后保留 --no-ff merge

svn - 为什么 git-svn 随机将我的根目录更改为父目录?

git - 如何通过提交消息搜索 Git 存储库?

git - .gitignore 是否不会忽略包含 .git 子目录的目录?