git pull*after*git rebase?

tis*_*sek 41 git rebase

我有一个功能分支和一个主分支.

Master分支已经发展,我的意思是让这些更新尽可能少地与master分支发生分歧.

所以我git pull在两个分支,git checkout feature/branch最后git rebase master.

现在,我要么期望一切顺利运行,要么在继续rebase之前需要解决冲突,直到所有主提交在功能分支上成功重新应用.

现在在我的案例中真正发生的是我不明白的事情:

$>git rebase master
First, rewinding head to replay your work on top of it...
Applying: myFirstCommitDoneOnTheBranch
Applying: myOtherCommitDoneOnTheBranch
$>git status
On branch feature/branch
Your branch and 'origin/feature/feature' have diverged,
and have 27 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
$>git pull
*load of conflicts*
Run Code Online (Sandbox Code Playgroud)

现在,我可以理解他在拉动之后加载了冲突; 我不明白需要拉.从逻辑上讲,它应该在分支时回滚到master,保存在分支上进行的提交,转发到master上的最新提交,然后应用保存的提交.

我不明白Applying消息所指的是什么:什么是应用提交哪个版本?

Enr*_*lio 65

文艺青年最爱的你应该同时更新master,并featuregit pullgit pull --rebase 以前重订基feature之上master. 你的分支重新设置git pull 之后,没有必要做.featuremaster

根据您当前的工作流程,原因git status告诉您:

您的分支和"origin/feature"已经分歧,每个分别有27个和2个不同的提交.

是因为你的重建基础feature分支现在有25个新提交不是来自可达origin/feature(因为他们从底垫上前来master加)2所提交这从可达的origin/feature,但有不同的提交的ID.这些提交包含相同的更改(即它们是相同的修补程序)但它们具有不同的SHA-1哈希值,因为它们基于origin/feature与您在本地存储库中重新引用它们的提交不同的提交.

这是一个例子.让我们假设这是你的历史之前git pullmaster:

A - B - C (master)
         \
          D - E (feature)
Run Code Online (Sandbox Code Playgroud)

之后git pull,master得到了承诺F:

A - B - C - F (master, origin/master)
         \
          D - E (feature)
Run Code Online (Sandbox Code Playgroud)

在这一点上,你变基feature之上master,其中应用 DE:

A - B - C - F (master, origin/master)
             \
              D - E (feature)
Run Code Online (Sandbox Code Playgroud)

与此同时,远程分支origin/feature仍然基于提交C:

A - B - C - F (master, origin/master)
         \   \
          \   D' - E' (feature)
           \
             D - E (origin/feature)
Run Code Online (Sandbox Code Playgroud)

如果你做git statusfeature,Git会告诉你,你feature的分支已经从分歧origin/feature3(F,D',E')和2(D,E分别)款.

请注意D'E'包含相同的更改D,E但具有不同的提交ID,因为它们已经重新定位F.

解决的办法是做git pull上都masterfeature 之前衍合featuremaster.但是,由于您可能已经提交了feature尚未推送的提交origin,您可能希望:

git checkout feature && git pull --rebase
Run Code Online (Sandbox Code Playgroud)

避免在您和本地之间创建合并提交.origin/featurefeature

关于变基的后果的最新情况:

根据这一评论,我扩大了分歧.在rebase之后git status报告featureorigin/feature 分歧的原因是由于rebase引入了新的提交feature,而且它重写了之前推送的提交origin/feature.

审时度势拉,但底垫:

A - B - C - F (master)
         \
          D - E (feature, origin/feature)
Run Code Online (Sandbox Code Playgroud)

此时,featureorigin/feature指向相同的提交E- 换句话说,它们处于" 同步 "状态.经过重订feature之上master,历史将是这样的:

A - B - C - F (master)
         \   \
          \   D' - E' (feature)
           \
             D - E (origin/feature)
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,feature并且origin/feature已经分歧,他们的共同祖先正在承诺C.这是因为feature现在包含F来自masterplus 的新提交D'E'(读作" D prime "和" E prime "),它们是提交DE应用于上面F.尽管它们包含相同的更改,但Git认为它们是不同的,因为它们具有不同的提交ID.同时,origin/feature仍然参考DE.

此时,您已经重写了历史记录:您已经通过对其进行重新定义来修改现有提交,从而有效地创建"新"提交.

现在,如果您要继续运行git pull,feature那将会发生什么:

A - B - C - F (master)
         \   \
          \   D' - E'- M (feature)
           \         /
             D - E - (origin/feature)
Run Code Online (Sandbox Code Playgroud)

由于git pullgit fetch+ git merge,这将导致创建合并提交M,其父母是E'E.

相反,如果您运行git pull --rebase(即git fetch+ git rebase),那么Git会:

  1. 移动feature提交C(的共同祖先featureorigin/feature)
  2. 申请DE来自origin/feature
  3. 申请F,D'E'

然而,注意到,D'并且E'包含相同的变化DE,Git的也只是将它们丢弃,造成了历史看起来像这样:

A - B - C - F (master)
         \   
          D - E - F' (feature)
              ^
             (origin/feature)
Run Code Online (Sandbox Code Playgroud)

请注意F,之前可以从中获取的提交是如何feature应用于origin/feature生成的F'.在这一点上,git status会告诉你这个:

您的分支通过1次提交超过"origin/feature".

当然,这是承诺F'.

  • 如果你想发布重新命名的`feature`分支,唯一的办法就是_force用itt push it_和`git push -f`.但是,请注意,您将发布_rewritten history_(在我们的示例中,"D"和"E"实际上是"新的"),所以如果其他人在旧的上面创建了提交(`D`和`E`他们在'git pull`之后会以相同的情况结束.所以,如果你可以安全地与_everyone_沟通,他们可能已经获取了你要重写提交的"origin/feature",你就可以了.否则,只是不要将`feature`和_merge_`master`改为`feature`. (4认同)
  • 这次真是万分感谢。但是我不明白的是,我 * 确实 * 在重新设置基础之前在两个分支上都做了一个 git pull --rebase ,我最终得到了这个。只是为了说明清楚:我不是在 master 之上 rebase 而是在 develop 上,尽管它不应该改变任何东西(是的,我使用的命令是 git rebase develop 而不是 git rebase master)。仍然为什么我仍然以这种“分叉”的方式结束? (2认同)
  • @EnricoCampidoglio我认为此评论应该是答案的一部分。我读了答案,心想:“太好了,现在我知道为什么了……但是处理所有这些虚假提交的最佳方法是什么?” 我一直在做`git push -f`以避免下次我重新设置基础时发生无限的合并冲突,但是我没有想到其他人一直在分支上工作并拥有旧历史副本的情况。 (2认同)

ash*_*oli 11

如果远程版本的masterfeature/branch单独更新,则只需重置本地功能分支即可

git checkout feature/branch
git fetch origin feature/branch
git reset --hard origin/feature/branch
Run Code Online (Sandbox Code Playgroud)

那么如果你想引入master分支的变化,

git rebase origin/master
Run Code Online (Sandbox Code Playgroud)

  • 说“从*主分支引入更改”可能更清楚吗? (7认同)

cma*_*ter 5

当你在 master 之上重新建立你的特性分支时,你创建了一堆新的提交。但是,您的origin/feature分支仍然指向旧的分支。这是rebase后的情况:

C' (feature)
B'
A'
* (master, origin/master)
*
*
| C (origin/feature)
| B
| A
|/
* some base commit
Run Code Online (Sandbox Code Playgroud)

虽然提交A'包含与commit类似的更改集A,但它绝不是相同的提交。它包含一个不同的树,并且有一个不同的父节点。

现在,当您feature再次尝试拉取时,您会尝试创建此历史记录:

* (feature)
|\
C'|
B'|
A'|
* | (master, origin/master)
* |
* |
| C (origin/feature)
| B
| A
|/
* some base commit
Run Code Online (Sandbox Code Playgroud)

您正在合并两个引入了非常相似、不同的变化的分支。除了完全没有意义之外,这势必会造成大量冲突。

您需要做的是使用git push -f. 这将失去旧的历史,并用重写的历史代替它

另一种方法是避免git rebase在您已经推送到任何其他存储库的分支上使用,或者git rebase完全避免使用。这是更简洁的方法:它导致历史的发生,而不是像过去那样对历史撒谎git rebase。这至少是我更喜欢的。

  • 对“完全避免 git rebase”投了反对票。“git rebase”是一个有用的工具,对于有效的 DevOps 至关重要,尤其是在大型团队中。仅仅因为您不了解如何正确使用某些东西并不意味着您应该告诉其他人避免它。 (2认同)