git pull的细微差别——rebase和git rebase?

git pull的细微差别——rebase和git rebase?,git,Git,尽管有各种描述,git-pull--rebase的工作原理与git-fetch/git-rebase[branch]不同gitpull--rebase被描述为fetch+rebase命令的别名,但我试图找出它们之间的区别 在另一篇文章中,我得到了git pull--rebase作为一个rebase问题的解决方案,在这个问题中,git没有正确处理提交,而提交由于上游功能分支上的合并冲突解决而改变了哈希值 到目前为止,我们一直在结合使用git-fetch-upstream和git-rebase-u

尽管有各种描述,
git-pull--rebase
的工作原理与
git-fetch/git-rebase[branch]
不同
gitpull--rebase
被描述为
fetch
+
rebase
命令的别名,但我试图找出它们之间的区别


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

到目前为止,我们一直在结合使用
git-fetch-upstream
git-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) $
但是,运行pull可以实现我们想要的:

$ 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——重新设置上游要素分支名称的基础
等于:
git重新基址——在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
以及“新”功能分支上的最新提交:

c1452be Sue [B-07290] Order Parts Ship To/Comments
注意:“合并”提交已丢失,“订单部分”提交现在显示为由Sue而不是Bob完成。我正试图确认,但要么是有人选择了提交,要么以某种方式运行了一个回基,从而放弃了合并提交

下面是在每个过程中使用的几个变量
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
是一个仅存在于本地分支上的合并提交,它不再存在于上游。

这不会解决您关于
git-rebase
git-pull--rebase
之间差异的问题,因为我也不知道技术细节(而且我实际上从未使用过
git-pull
)但我知道以下工作:

  • 您获取存储库,使
    源/分支
    以一些新提交为目标
  • 你的分支机构负责人指示提交B
  • 您的本地
    分支机构
    源/分支机构
    共享一个共同的祖先
    祖先
  • 重新定基分支机构(
    git-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 pick
git rebase
工作得更好,但我认为这只是因为它重新应用提交,而不是重放历史记录。

答案取决于版本,因为
git pull--rebase
git rebase
(简单的
rebase
,没有很多具体的参数)在Git1.7和Git2.3之间发展了很多

一般来说,git版本越现代,差异就应该越小(我不能说“是”,只是“应该是”,:-),部分原因是我没有遵循随着时间的推移而发展的确切路径)。以下是主要的要点:

  • 如果没有参数,
    git-rebase
    会自动查找“上游”。在这种情况下,“上游”的定义与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
    也很容易检测到的情况也变得很难再次检测到。但是,如果您的远程跟踪分支具有reflogs(通常是这样),reflogs可以提供信息。因此,
    pull
    脚本和git一般都被修改/增强,以使用reflogs提取“fork-point”信息(请参阅中的
    --fork-point
    部分)

考虑到找到“分叉点”的能力,
git-rebase
可以(而且,在最新版本的git中)使用与
git-pull-rebase
相同的魔力,因此在行为上应该没有区别。但是,根据您拥有的git版本(介于1.7和2.3之间),
git pull
可能找到了正确的“分叉点”,而
git rebase
可能找不到。根据你的笔记:

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

实际上有一个上游的“历史重写”,所以您需要这个新的“智能化”版本的
git-rebase
来自动发现它。更老、更简单/更简单的重基简单地假设,如果存储库中“现在”(在
fetch
ing之后)有此提交序列:


OldD只是补充说我有git版本1.9.3(Apple git-50),尽管我团队中的其他人可能有不同的版本。控制台输出
        OldD         <-- (origin/branch used to be here)
      /      \
* - *       B07241   <-- branch
      \
        D06437       <-- origin/branch (now)