与git pull --rebase和git rebase的细微差别?

时间:2015-03-02 21:53:27

标签: git

尽管有所有描述,git pull --rebase的工作方式与git fetch/git rebase [branch]不同。 git pull --rebase被描述为fetch + rebase命令的别名,但我试图找出他们的不同之处?


在另一篇文章中,我被赋予了git pull --rebase作为rebase问题的解决方案,其中git没有正确处理由于上游功能分支上的合并冲突解决而改变了哈希值的提交。 / p>

到目前为止,我们一直在使用git fetch upstreamgit rebase upstream/a-feature-branch的组合。

然而,当这样做时,它的行为就像任何不再与上游分支上的哈希相匹配的提交都是新工作。它试图重新应用它们并导致合并冲突:

$ git fetch upstream
-- no results, already fetched this morning
$ git rebase upstream/a-feature-branch
First, rewinding head to replay your work on top of it...
Applying: D-06437 (note: this commit already exists, but a merge conflict upstream has changed its hash)
Using index info to reconstruct a base tree...
...
Falling back to patching base and 3-way merge...
Auto-merging (file)
CONFLICT (content): Merge conflict in (file)
Failed to merge in the changes.
Patch failed at 0001 D-06437

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

imac: projectName ((c1452be...)|REBASE) $

但是,运行拉动可以实现我们想要的目标:

$ git pull --rebase upstream a-branch-name
 * branch            a-branch-name -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: B-07241

此解决方案不会导致任何冲突,并且已使用上游具有修改后的提交/哈希值正确更新了历史记录。


更新#1:

git pull --rebase upstream feature-branch-name等同于: git-rebase --onto c1452be62cf271a25d3d74cc63cd67eca51a127d 634b622870a1016e717067281c7739b1fe08e08d

以下是开发人员工作分支中最近提交的三个提交:

92b2194 Rick B-07241
634b622 Sue Merge pull request #254 from dboyle/B-07290
bc76e5b Bob [B-07290] Order Parts Ship To/Comments

最新的" new"功能分支:

c1452be Sue [B-07290] Order Parts Ship To/Comments

注意:"合并"提交已经丢失,并且"订购部件"提交现在显示为由苏完成,而不是鲍勃。我试图确认,但要么是某人挑选了提交,要么以某种方式运行了一个废弃合并提交的方式。

以下是git-rebase.sh在每个变量中使用的几个变量。唯一的区别是

"git-rebase" Variables during `git pull --rebase upstream feature-branch-name`
orig_head = 92b2194e3adc29eb3fadd93ddded0ed34513d587
onto_name = c1452be62cf271a25d3d74cc63cd67eca51a127d
onto = c1452be62cf271a25d3d74cc63cd67eca51a127d
mb = 438cc917c6f517913c9531e0a38f308d3aa13f0b
revisions = 634b622870a1016e717067281c7739b1fe08e08d..92b2194e3adc29eb3fadd93ddded0ed34513d587


"git-rebase" Variables during `git rebase upstream/feature-branch-name`
orig_head = 92b2194e3adc29eb3fadd93ddded0ed34513d587
onto_name = upstream/PartsInterface_E-01960
onto = c1452be62cf271a25d3d74cc63cd67eca51a127d
mb = 438cc917c6f517913c9531e0a38f308d3aa13f0b
revisions = c1452be62cf271a25d3d74cc63cd67eca51a127d..92b2194e3adc29eb3fadd93ddded0ed34513d587

由" git rebase"计算的修订版本与git pull不同。

注意:634b6228是仅在本地分支上存在的合并提交,它不再存在于上游。

2 个答案:

答案 0 :(得分:2)

答案取决于版本,因为git pull --rebasegit rebase(普通rebase的实现,没有很多具体参数)在git 1.7和git之间发生了相当大的变化2.3。

一般来说,你的git版本越现代,应该有的差别越小(我不能说“是”,只是“应该”,:-)部分是因为我没有遵循确切的路径随着时间的推移)这是一般推力:

  • 没有参数,git rebase会自动查找“上游”。在这种情况下,“upstream”的定义与git pull使用的定义相同,因此,如果您可以git pull --rebase(没有其他参数),则必须有自动上游。

  • 运行git pull --rebase(没有其他参数)时,首先运行git fetch,像往常一样引入新的提交。此时 - 当你有新的提交,以及所有旧的提交,因为你尚未更新远程跟踪分支 - 很容易检测到实际发生的异常情况,即,上游“历史改写”。

  • 由于很容易检测到,旧版本的git会在git pull --rebase期间检测到这一点,并会自动补偿rebase。 (然而,那些旧版本的git会(故意)无法更新远程跟踪分支。因此,这种检测本身也有些限制。)

  • 在git 1.8.4中更改git fetch以更新远程跟踪分支,即使在git pull调用时,git pull可以轻松检测到的情况也变得更难再次检测。但是,如果您的远程跟踪分支机构具有reflog(通常是它们),则 reflogs 可以提供信息。因此,修改/增强了pull脚本和git,以使用reflog来提取“fork point”信息(请参阅git merge-base documentation中的--fork-point部分)。

鉴于能够找到“叉点”,git rebase可以(并且在最近的git版本中)使用与git pull --rebase相同的魔法,因此行为应该没有区别。但是,根据您拥有的git版本(介于1.7和2.3之间),git pull可能找不到正确的“叉点”,而git rebase则没有。请注意:

  

Applying: D-06437(注意:此提交已存在,但上游的合并冲突已更改其哈希值)

实际上有一个上游的“历史重写”,所以你需要git rebase这个新的“智能化”版本来自动发现它。较旧的,笨拙的/简单的rebase只是假设如果您在“现在”(在fetch之后)存储库中有这样的提交序列:

        OldD         <-- (origin/branch used to be here)
      /      \
* - *       B07241   <-- branch
      \
        D06437       <-- origin/branch (now)

并且您运行git rebase,然后您想要提交OldDB07241并将其应用于D06437之上。尝试挑选OldD并将结果差异应用于提交D06437时发生冲突。

很容易在交互式 rebase中修复此问题,因为您只需删除“旧”D提交的“选择”行。

答案 1 :(得分:0)

这不会解决您关于git rebasegit pull --rebase之间差异的问题,因为我不知道技术细节(我几乎从不使用git pull),但我知道以下作品:

  • 您获取存储库,使origin/branch定位一些新的提交A.
  • 您的分支HEAD指向提交B.
  • 您的本地branchorigin/branch分享共同的祖先ancestor
  • 重新定位branchgit rebase origin/branch)可以这样做:

    git reset --hard origin/branch # your branch is now the same as origin
    git cherry-pick ancestor..B # now you pick up the commit between the two branches.
    

我注意到git cherry-pickgit rebase工作得更好,但我认为这只是因为它重新应用提交而不是重播历史记录。