在执行git rebase命令之后,我的本地分支和远程分支发生了分歧。

9

我有一个名为my-feature的分支,它已经推送到origin以进行代码审查。它没有被共享。最终,它将被合并到我所在团队中的develop分支中,这是一个共享的分支。我想把我的develop分支rebase到my-feature上,以保持历史记录的干净,并将我的特性分支合并到develop中。这是我一直在做的事情:

$ git checkout my-feature
// do some work. make commits.

$ git rebase develop
// fix some conflicts

$ git add .

$ git rebase --continue

在我成功地完成变基之后,我会检查状态:

$ git status
On branch my-feature
Your branch and 'origin/my-feature' have diverged,
and have 155 and 1 different commit each, respectively.
  (use "git pull" to merge the remote branch into yours)

$ git what do I do here?

我不知道该怎么办。如果我执行git pull,那么我会发现会出现一些没有意义的冲突。有些人建议强制推送,但我很紧张。如果没有其他人使用这个分支,将我的主题分支强制推送到源是否正常?

3个回答

17
首先,在这个阶段,你可以放心地执行git push --force:你已经声明了你的分支不是共享的。因此,在服务器端更改其历史记录不会影响任何其他用户。
其次,当你变基一个分支时,你会改变它与远程跟踪分支(origin/xxx)的共同祖先。
在执行git rebase develop之前,你有:
d--d--d (develop)
    \
     x--x--x--x--x--X--y--y--y (my-feature)
                    |
       (origin/my-feature)   

X是源分支和特性分支之间的共同祖先,这意味着您在my-feature分支中添加了一些提交。执行git status命令会返回类似以下内容:

On branch my-feature
Your branch is ahead of 'origin/my-feature' by 3 commit.

但是,当你将该分支在develop之上进行变基,就会将my-feature的所有提交重新应用在develop HEAD之上。

        X--X--X--X--X--X--Y--Y--Y  (my-feature)
       /
d--D--d (develop)
    \
     x--x--x--x--x--X
                    |
       (origin/my-feature)   

这次,my-featureorigin/my-feature 之间的共同祖先不再是一些添加的提交,而是 my-feature 的完整历史记录,再加上一些 develop 的提交!(D 在这里)
因此状态为:
Your branch and 'origin/my-feature' have diverged,
and have 155 and 1 different commit each, respectively.

由于您的分支没有共享,因此简单的git push --force origin my-feature命令将完成操作:

        X--X--X--X--X--X--Y--Y--Y  (my-feature, origin/my-feature)
       /
d--D--d (develop)

如果my-feature有一个上游分支,通过git push --force命令就足够了,前提是默认的推送策略push.default设置为simple
可以通过git rev-parse --abbrev-ref --symbolic-full-name @{u}命令检查一下。


很好的解释。那么我可以毫无后果地将我的“feature”合并到“develop”中吗? - Jeff
1
@VonC 根据使用者所用的 git 版本,git push --force 有一定风险。在 git 1.9.5 之前,git 推送的默认行为是从本地仓库推送每个分支。因此,最好还是明确定义分支: git push --force origin <分支名称> - Eruvanos
@Eruvanos 我同意。我已经编辑了答案,使其更加明显,并附上了一个指向 https://dev59.com/HHzaa4cB1Zd3GeqPQn0y#21772695 的链接。 - VonC
如果我的非共享 my-feature 分支(我已经从 develop 上进行了变基并强制推送)突然变成了共享状态(有人拉取它并开始提交),会发生什么?我会出现问题吗?我应该放弃这个分支吗? - Jeff
1
通过使用 git push --force 的精彩解释,它解决了我的问题。 - Sojimaxi
显示剩余2条评论

2
您看到的是 my-featureorigin/my-feature 不同(您上次检查时 my-feature 在 origin 上的样子),因为在 rebase 时您刚刚更改了 my-feature(您正在使用的 my-feature)。
当您进行 rebase 时,您会更改分支的历史记录,因此几乎总是需要在此之后使用 --force 推送。如果这是您自己的分支,并且没有其他协作者使用该分支,则没问题。
如果这个功能分支有协作者,那么一开始就不应该进行 rebase。通常的经验法则是不要更改共享分支的历史记录。如果是这种情况,您需要撤消 rebase,可以参考这篇文章来获得帮助。

谢谢,这很有道理。有时我不知道一个分支是否会有协作者,所以我想知道分享已经被rebase的特性分支的最佳实践是什么。我想我可以创建一个新分支,并将我想要的提交挑选到新分支上。 - Jeff
1
如果已经分享过了,就不要再变基。如果在任何人接手之前进行变基,那么没问题。通常情况下,你应该知道在你的情况下是否安全进行变基。 - jaredready

1
假设您有以下的git提交结构:
A--B--C--D--E(origin/my-feature)
 \
  F--G--H--I(someotherbranch)

如果你现在将origin/my-feature变基到someotherbranch,那么你会得到以下情况:
A--B--C--D--E(origin/my-feature)
 \
  F--G--H--I(someotherbranch)
            \
             B'--C'--D'--E'(my-feature)

那是一个分歧的情况。我的功能在与 origin/my-feature 不同的另一个分支上,你无法快进任何一个分支。现在,如果 origin/my-feature 没有被任何人拉取,你可以安全地使用 push -f。但是,如果有人已经拉取了它,如果该人继续在该分支上工作,你可能会遇到问题。检查是否有任何人已经将你错误的 origin/my-feature 拉取,并将该分支的 head 更改为你新强制提交的内容。

始终遵循规则:不要对已推送的提交进行 rebase。

糟糕的情况:

              J--K--G(origin/otherperson)
             /
A--B--C--D--E(origin/my-feature)
 \
  F--G--H--I(someotherbranch)
            \
             B'--C'--D'--E'(my-feature)

这应该被改为:


A--B--C--D--E(origin/my-feature) (orphaned if push-f)
 \
  F--G--H--I(someotherbranch)
            \
             \               J'--K'--G'(origin/otherperson)
              \             /
               B'--C'--D'--E'(my-feature)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接