为什么 "rebase --onto ABC" 与 "rebase ABC" 不同?
Why is "rebase --onto ABC" different than "rebase ABC"?
使用 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.
我理解好像upstream
和newbase
指向相同的"base reference",那么这意味着下面的两个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 同步。并且提交 "Create file 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
我误解了警告信息。当使用 --onto 时,认为 git 在默认值中被混淆了。所以我只想 "help" 通过告诉 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
相同。最后一次提交 "Create file 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~1
是 D
,HEAD~2
是 C
,等等),我们需要做一些事情来标记这两个新名称指向提交 A
的事实。不过,我打算将名称缩短为 Demo1
和 Demo2
。 (此时我创建了一个只有 o
到 E
提交的存储库,实际上 运行 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
("get help from A DOG" 正如有人所说)以这种方式显示了这个测试存储库(在我的例子中没有 origin/
b运行ch):
* 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
b运行ch 因此将 Demo1
和 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
这适用于当前的 b运行ch(HEAD
或 Demo1
)。它会找到 HEAD
上不在 FeatureABC
上的提交(gitrevisions 语法中的 FeatureABC..
)。那是提交 F
。这些提交被放入到 maybe 副本的提交列表中——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
, which I did here. 原来是显示的 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。)
复制失败,我得再猜一次
现在我们尝试用 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
命令没有设置上游("tracking")姓名:
$ 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>
没有 失败。为了让它没有失败,你的 b运行ch 必须有一个上游集。上游可能 是 origin/FeatureABC
或类似的,这意味着就 Git 而言,你是 运行ning:
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
选项 on 。
--fork-point
是什么
--fork-point
的 目标 是专门 drop 曾经在你的上游提交的,但不再在您的上游。请参阅 for an example. Since I don't have either your repository or your reflog, I cannot test out your specific case—but that's one reason, and probably the most likely reason given the hints in your question, that a commit that would affect the rebase tree result would get dropped. The commits that are dropped due to having the same patch ID 作为上游提交 [edit:] 通常 1 将 而不是 影响最后复制的提交的最终树:它们只会导致合并冲突 and/or 强制你使用 git rebase --skip
跳过它们,如果它们被包含。
1写完之后我突然想到有一个重要的例外(这可能与原始问题无关,但我应该提一下)。将功能或主题 b运行ch 重新定位到更主线的 b运行ch 上,当提交首先被挑选 out 功能进入主线时,然后 reverted 在主线,会导致问题。考虑,例如:
...--o--*--P--Q--C'-R--S--X--T <-- mainline
\
A--B--C--D--E <-- topic
其中 C'
是提交 C
的副本,X
是不应该放入 mainline
的提交 C
的还原然而。正在做:
git checkout topic
git rebase mainline
将指示 Git 将提交 A
到 E
放入 "candidates to copy" 列表中,但也会查看 P
到 T
看看是否有任何已经被采用。提交 C
被 采用,作为 C'
。如果 C
和 C'
具有相同的补丁程序 ID——通常,它们 将 ——Git 将从列表中删除 C
作为 "already copied"。但是,C
在提交 X
.
中被显式 还原
谁做 rebase 需要注意,如果需要和适当,请小心恢复 C
。
这种特殊行为 不是 git merge
的问题(因为合并忽略中间提交),只有 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.
我理解好像upstream
和newbase
指向相同的"base reference",那么这意味着下面的两个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 同步。并且提交 "Create file 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
我误解了警告信息。当使用 --onto 时,认为 git 在默认值中被混淆了。所以我只想 "help" 通过告诉 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
相同。最后一次提交 "Create file 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~1
是 D
,HEAD~2
是 C
,等等),我们需要做一些事情来标记这两个新名称指向提交 A
的事实。不过,我打算将名称缩短为 Demo1
和 Demo2
。 (此时我创建了一个只有 o
到 E
提交的存储库,实际上 运行 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
("get help from A DOG" 正如有人所说)以这种方式显示了这个测试存储库(在我的例子中没有 origin/
b运行ch):
* 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
b运行ch 因此将 Demo1
和 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
这适用于当前的 b运行ch(HEAD
或 Demo1
)。它会找到 HEAD
上不在 FeatureABC
上的提交(gitrevisions 语法中的 FeatureABC..
)。那是提交 F
。这些提交被放入到 maybe 副本的提交列表中——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
, which I did here. 原来是显示的 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。)
复制失败,我得再猜一次
现在我们尝试用 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
命令没有设置上游("tracking")姓名:
$ 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 inbranch.<name>.remote
andbranch.<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>
没有 失败。为了让它没有失败,你的 b运行ch 必须有一个上游集。上游可能 是 origin/FeatureABC
或类似的,这意味着就 Git 而言,你是 运行ning:
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
选项 on 。
--fork-point
是什么
--fork-point
的 目标 是专门 drop 曾经在你的上游提交的,但不再在您的上游。请参阅 git rebase --skip
跳过它们,如果它们被包含。
1写完之后我突然想到有一个重要的例外(这可能与原始问题无关,但我应该提一下)。将功能或主题 b运行ch 重新定位到更主线的 b运行ch 上,当提交首先被挑选 out 功能进入主线时,然后 reverted 在主线,会导致问题。考虑,例如:
...--o--*--P--Q--C'-R--S--X--T <-- mainline
\
A--B--C--D--E <-- topic
其中 C'
是提交 C
的副本,X
是不应该放入 mainline
的提交 C
的还原然而。正在做:
git checkout topic
git rebase mainline
将指示 Git 将提交 A
到 E
放入 "candidates to copy" 列表中,但也会查看 P
到 T
看看是否有任何已经被采用。提交 C
被 采用,作为 C'
。如果 C
和 C'
具有相同的补丁程序 ID——通常,它们 将 ——Git 将从列表中删除 C
作为 "already copied"。但是,C
在提交 X
.
谁做 rebase 需要注意,如果需要和适当,请小心恢复 C
。
这种特殊行为 不是 git merge
的问题(因为合并忽略中间提交),只有 git rebase
.