git rebase奇怪的行为
对于下一个示例,我有一个奇怪的git重基行为。 假设我有一棵本地树:git rebase奇怪的行为,git,rebase,Git,Rebase,对于下一个示例,我有一个奇怪的git重基行为。 假设我有一棵本地树: ∨ b1--b2--b3 / a1--a2--a3 那棵遥远的树呢 b1--b2--b3 / a1--a2--a3--a4--a5--a6 分支是主分支的位置 目前,我在b3。 我调用下面的命令: git pull origin master maste
∨
b1--b2--b3
/
a1--a2--a3
那棵遥远的树呢
b1--b2--b3
/
a1--a2--a3--a4--a5--a6
分支是主分支的位置
目前,我在b3。
我调用下面的命令:
git pull origin master master // fixed typo
git rebase master
完成此操作后,我得到了一棵树,它看起来像:
a4'--a5'--a6'--b1--b2--b3
/
a1--a2--a3--a4--a5--a6
反而
b1--b2--b3
/
a1--a2--a3--a4--a5--a6
为什么会出现这种情况?我总是建议人们在非常熟悉git之前避免使用git pull,因为git的功能太多了,有点神秘,这很难解释。它通常(相当准确地)被描述为等同于运行
git fetch
,然后运行git merge
或git rebase
,但棘手的是,它传递给git merge
或git rebase
的参数并不是您所期望的
也就是说,让我们将这些分解,并仔细查看每个步骤。我还将以稍微不同的方式绘制提交图。(您在上面称之为“树”,这不是最好的术语,原因有二。首先,提交图是一个图,特别是一个D定向a循环G图或DAG。所有树都是DAG,但并非所有DAG都是树。其次,Git使用术语树来指代“树对象”;每个提交都携带一个树对象。)
我相信,您的初始提交图如下所示:
B1--B2--B3 <-- branch (HEAD)
/
A1--A2--A3 <-- master, origin/master
在FETCH\u HEAD
中的内容有点棘手。此文件的内容包括原始名称,即,master
和可能的mastert
,如另一个Git上所示,没有Git通常使用的任何origin/
重命名。也可能有一些行用于标记。这些行中的某些行也可以用注释,不用于合并
。所有行都包含特定Git对象(提交,有时是标记)的哈希ID。git-fetch
程序将这些行专门留给git-pull
程序检查
接下来,您的git pull
命令从FETCH\u HEAD
提取新获得的提交的散列ID。也就是说,它在FETCH\u HEAD
中搜索未标记为而不是合并的提交的哈希ID。(我假设您在这里执行的是合并样式的拉取,而不是rebase样式的拉取。)然后使用这些哈希ID运行git merge
git merge
步骤进行合并提交
同样,现在不管您是运行git pull origin master
还是git pull origin master
,都很重要。如果您运行后者,并且有一个名为mastert
的分支,那么将有两个匹配行,可能还有两个不同的哈希ID。在本例中,您的git pull
命令将执行这两个哈希的八达通合并
否则,您将得到一个散列的正常合并。我假设你得到一个正常的合并。结果是:
B1--B2--B3------M <-- branch (HEAD)
/ /
A1--A2--A3 <-- master /
\ /
A4--A5-----A6 <-- origin/master, FETCH_HEAD
您正在告诉Git复制当前分支上的任何提交(即,分支
),这些提交无法从名为master
的分支访问,并且不是合并提交(您将复制可从合并访问的提交,但不会复制合并本身)。请注意,这不是使用origin/master
,而是使用master
。因此,您要求Git复制的提交是B1
、B2
、和B3
、和A4
、A5
、和A6
。。。以某种顺序(实际顺序有点难以预测,尽管A组和B组将一起复制,因为Git在收集要复制的提交的ID时使用--topoorder
)
您要求Git复制它们的位置是“在master
的提示之后”,即A3
之后
如果Git首先复制B1
,它通常会保持B1
不变,因为Git-rebase
会尽可能做到这一点。如果它首先复制A4
,出于同样的原因,它还可以尝试保持A4
不变;但这一机制却被这一特殊的再基础所阻碍(见下面的评论)。一旦Git通过A6
复制了A4
,它必须将B1
复制到一个新的提交中,该提交的父项是A6
的副本(此提交与原始的B1
不同,因为B1
的父项是A3
)
(但是,您可以强制git-rebase
进行复制,例如,使用--no-ff
或--force
)
您的结果表明您的Git选择先复制A4
。这将为您提供:
A4'-A5'-A6'-B1'-B2'-B3' <-- branch
/
A1--A2--A3 <-- master
\
A4--A5--A6 <-- origin/master
或者(可以而且有时确实)产生:
B1--B2--B3--A4'-A5'-A6'我总是建议人们在对git非常熟悉之前避免使用git pull
,因为它做得太多了,有点神秘,这很难解释。它通常(相当准确地)被描述为等同于运行git fetch
,然后运行git merge
或git rebase
,但棘手的是,它传递给git merge
或git rebase
的参数并不是您所期望的
也就是说,让我们将这些分解,并仔细查看每个步骤。我还将以稍微不同的方式绘制提交图。(您在上面称之为“树”,这不是最好的术语,原因有二。首先,提交图是一个图,特别是一个D定向a循环G图或DAG。所有树都是DAG,但并非所有DAG都是树。其次,Git使用术语树来指代“树对象”;每个提交都携带一个树对象。)
我相信,您的初始提交图如下所示:
B1--B2--B3 <-- branch (HEAD)
/
A1--A2--A3 <-- master, origin/master
在FETCH\u HEAD
中的内容有点棘手。该文件的内容包括原始名称,即,master
和可能的mastert
,如另一个Git上所示,没有任何原始名称
A4'-A5'-A6'-B1'-B2'-B3' <-- branch
/
A1--A2--A3 <-- master
\
A4--A5--A6 <-- origin/master
A1--A2--A3 <-- master
\
A4--A5--A6 <-- origin/master
\
B1'-B2'-B3' <-- branch (HEAD)
B1--B2--B3--A4'-A5'-A6' <-- branch (HEAD)
/
A1--A2--A3 <-- master
\
A4--A5--A6 <-- origin/master