[英]Understanding “git pull --rebase” vs “git rebase”
根据我对git pull --rebase origin master
理解,它应该相当于运行以下命令:
(from branch master): $ git fetch origin
(from branch master): $ git rebase origin/master
我似乎找到了一些不按预期工作的情况。 在我的工作区中,我有以下设置:
origin/master
参考远程origin
上的分支master
master
设置为跟踪origin/master
,并且通过多次提交落后于 master。 feature
设置为跟踪本地分支master
,并通过多次提交在master
之前 。 有时,我会通过运行以下一系列步骤来丢失提交
(from branch master): $ git pull --rebase
(from branch master): $ git checkout feature
(from branch feature): $ git pull --rebase
在这一点上,我正在进行的一些提交feature
现在已经丢失了。 现在,如果我重置我的位置,而是执行以下操作:
(from branch feature): $ git reset --hard HEAD@{2} # rewind to before second git pull
(from branch feature): $ git rebase master
提交已正确应用,我的新提交feature
仍然存在。 这似乎直接与我对git pull
如何工作的理解相矛盾,除非git fetch .
做了比我想象的更奇怪的事情。
不幸的是,对于所有提交,这不是100%可重复的。 但是,当它确实适用于提交时,它每次都有效。
注意:我的git pull --rebase
在这里应该被理解为--rebase=preserve
,如果这很重要的话。 我的~/.gitconfig
有以下~/.gitconfig
:
[pull]
rebase = preserve
(编辑,2016年11月30日:另请参阅这个答案 为什么git rebase会丢弃我的提交? 。现在几乎可以肯定它是由于fork-point选项。)
有手动和之间的一些区别pull
基于git rebase
(现在少在2.7比有在比罗马的Git版本--fork-point
在选项git merge-base
)。 而且,我怀疑你的自动保留合并可能会涉及到。 这有点难以确定,但是你的本地分支跟随你的另一个本地分支这一事实正在变得非常具有启发性。 同时,最近在C中重写了旧的git pull
脚本,因此很难看到它的作用(尽管你可以将环境变量GIT_TRACE
设置为1
以使git在内部运行时显示命令)。
在任何情况下,这里有两三个关键项目(取决于你如何计算和拆分它们,我会把它变成3):
git pull
运行git fetch
,然后根据指令运行git merge
或git rebase
,但是当它运行git rebase
它使用新的fork-point机器“从上游rebase恢复”。
当git rebase
在没有参数的情况下运行时,它有一个特殊的情况来调用fork-point机制。 使用参数运行时,除非使用--fork-point
显式请求,否则将禁用fork-point机制。
当git rebase
被指示保留合并时,它使用交互式rebase代码(非交互式)。 我不确定这在这里真的很重要(因此上面可能会涉及)。 通常它会使合并变平,只有交互式rebase脚本才能保存它们(这段代码实际上重新进行了合并,因为没有其他方法可以处理它们)。
这里最重要的项目(肯定)是叉点代码。 此代码使用reflog来处理通过绘制提交图的一部分而最佳显示的案例。
在正常情况下(没有叉点需要)rebase案例你有这样的事情:
... - A - B - C - D - E <-- origin/foo
\
I - J - K <-- foo
其中A
和B
是您启动分支时的提交(因此B
是合并基础), C
到E
是您通过git fetch
从远程git fetch
新提交,而I
到K
是您自己的提交。 底垫代码副本I
通过K
,所述第一副本附加到E
,第二到拷贝-OF- I
,第三到拷贝-OF- J
。
无论如何, Git计算出 - 或者习惯 - 使用git rev-list origin/foo..foo
进行复制,即使用当前分支( foo
)的名称来查找K
并向后工作,以及其名称上游( origin/foo
)找到E
并向后工作。 向后行军在合并基础处停止,在本例中为B
,复制的结果如下所示:
... - A - B - C - D - E <-- origin/foo
\ \
\ I' - J' - K' <-- foo
\
I - J - K [foo@{1}: reflog for foo]
当这里的上游origin/foo
本身重新定位时,会出现这种方法的问题。 比方说,比如,关于origin
有人力推动,使得B
是由新副本替换B'
有不同的提交措辞(也许不同的树为好,但我们希望,没有什么会影响我们的I
-through- K
)。 起点现在看起来像这样:
B' - C - D - E <-- origin/foo
/
... - A - B <-- [origin/foo@{n}]
\
I - J - K <-- foo
使用git rev-list origin/foo..foo
,我们选择要复制的提交B
, I
, J
和K
,并尝试像往常一样在E
之后粘贴它们; 但我们不想复制B
因为它真的来自origin
并且已被其自己的副本B'
取代。
fork point code的作用是查看origin
的reflog,看看B
是否可以在某个时间到达。 也就是说,它不仅检查origin/master
(找到E
并扫描回B'
然后是A
),还检查origin/master@{1}
(可能直接指向B
,取决于你运行git fetch
频率) , origin/master@{2}
,依此类推。 任何来自任何 origin/master@{n}
foo
提交都包括在内,以便在图中找到最低公共祖先节点时考虑(即,它们都被视为选项,成为git merge-base
打印出来)。
(值得注意的是这里存在的缺陷:这种自动化叉点检测只能找到维护reflog条目时可以访问的提交,在这种情况下默认为30天。但是,这与您的问题不是特别相关。)
在您的情况下,您有三个分支名称(因此涉及三个reflog):
origin/master
,由git fetch
更新(分支master
git pull
第一步) master
,由你(通过正常提交)和git rebase
( git pull
第二步)更新,以及 feature
,由你(通过正常提交)和git rebase
(你的第二个 git pull
第二步)更新:你从你自己“获取”,一个无操作,然后在master
上的rebase feature
)。 两个rebase都使用--preserve-merges
--onto new-tip fork-point
(因此是非交互式交互模式)和--onto new-tip fork-point
,其中通过运行git merge-base --fork-point upstream-name HEAD
找到fork-point
commit ID git merge-base --fork-point upstream-name HEAD
。 第一个rebase的upstream-name
是origin/master
(well, refs/remotes/origin/master
),第二个rebase的upstream-name
是master
( refs/heads/master
)。
这应该都是Just Work。 如果整个过程开始时的提交图与您所描述的类似:
... - A - B <-- master, origin/master
\
I - J - K <-- feature
然后第一次fetch
引入一些提交并使origin/master
指向新的提示:
C - D - E <-- origin/master
/
... - A - B <-- master, origin/master@{1}
\
I - J - K <-- feature
然后第一个rebase找不到任何要复制的东西( master
和B
的合并库 - B
= fork-point(master,origin / master) - 只是B
所以没有什么可复制的),给出:
C - D - E <-- master, origin/master
/
... - A - B <-- master@{1}, origin/master@{1}
\
I - J - K <-- feature
第二次获取是来自你自己和完全没有操作/跳过,留下这作为第二个rebase的输入。 --onto
目标是master
,它是提交E
, HEAD
( feature
)和master
的fork-point也提交B
,像往常一样将提交I
到K
复制到E
之后。
如果某些提交被删除,在这个过程中出现问题,但我看不清楚是什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.