特征分支改基后拒绝Git推送

好吧,我以为这是一个简单的git场景,我错过了什么?

我有一个master分支和一个feature分支。我在master上做了一些工作,在feature上做了一些工作,然后在master上做了更多的工作。我最终得到了这样的东西(字典顺序意味着提交的顺序):

A--B--C------F--G  (master)\D--E  (feature)

我对git push origin master保持远程master更新没有问题,也没有git push origin feature(在feature时)为我的feature工作维护远程备份。到目前为止,我们很好。

但是现在我想在master上的F--G提交之上重新设置feature,所以我git checkout featuregit rebase master。仍然很好。现在我们有:

A--B--C------F--G  (master)\D'--E'  (feature)

问题:在我想备份新的重新基于的feature分支时使用git push origin feature推送被拒绝,因为树由于重新基于而发生了变化。这只能用git push --force origin feature来解决。

我讨厌在不确定自己是否需要的情况下使用--force。那么,我需要它吗?重新设置必然是否意味着下一个push应该是--force ful?

此功能分支不与任何其他开发人员共享,因此我对强制推送没有问题事实上,我不会丢失任何数据,问题更具概念性。

393174 次浏览

feature分支上的git merge master有什么问题?这将保留您的工作,同时将其与主线分支分开。

A--B--C------F--G\         \D--E------H

编辑:啊,对不起,没有阅读您的问题声明。当您执行rebase时,您将需要强制。所有修改历史记录的命令都需要--force参数。这是一个故障保险,以防止您丢失工作(旧的DE将丢失)。

所以你执行了一个git rebase,使树看起来像(尽管部分隐藏,因为DE不再在命名分支中):

A--B--C------F--G\         \D--E      D'--E'

因此,当尝试推送新的feature分支(其中包含D'E')时,您将丢失DE

问题是git push假设远程分支可以快速转发到您的本地分支,即本地分支和远程分支之间的所有区别在于本地分支末尾有一些新的提交,如下所示:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)\T--Y    <- some-branch

当您执行git rebase提交时,D和E将应用于新基础并创建新提交。这意味着在rebase之后,您会有类似的东西:

A--B--C------F--G--D'--E'   <- feature-branch\D--E                <- origin/feature-branch

在这种情况下,远程分支不能快速转发到本地。虽然,理论上本地分支可以合并到远程(显然在这种情况下你不需要它),但由于git push只执行快进合并,它会抛出和错误。

--force选项所做的只是忽略远程分支的状态并将其设置为您正在推送的提交。所以git push --force origin feature-branch简单地用本地feature-branch覆盖origin/feature-branch

在我看来,将功能分支重新基于master并强制将它们推回到远程存储库是可以的,只要您是唯一一个在该分支上工作的人。

解决这个问题的一种方法是做msysGit的定基合并脚本所做的事情——在rebase之后,将feature的旧头部与-s ours合并。你最终得到提交图:

A--B--C------F--G (master)\         \\         D'--E' (feature)\           /\       --\    /D--E (old-feature)

feature的推送将是一个快进。

换句话说,你可以这样做:

git checkout featuregit branch old-featuregit rebase mastergit merge -s ours old-featuregit push origin feature

(没有测试,但我认为这是正确的…)

其他人已经回答了你的问题。如果你重新定位一个分支,你将需要强制推动该分支。

rebase和共享存储库通常相处不好。这是重写历史。如果其他人正在使用该分支或从该分支分支,那么rebase将非常不愉快。

一般来说,rebase适用于本地分支管理。远程分支管理最适合显式合并(--no-ff)。

我们也避免将master合并到一个功能分支中。相反,我们将基重新设置为master,但使用新的分支名称(例如添加版本后缀)。这避免了在共享存储库中重新设置基的问题。

这个分支上可能只有一个开发人员,也可能没有,现在(在rebase之后)与起源/功能不一致。

因此,我建议使用以下序列:

git rebase mastergit checkout -b feature_branch_2git push origin feature_branch_2

是的,新的分支,这应该可以在没有--force的情况下解决这个问题,我认为这通常是一个主要的git缺点。

以下对我有用:

git push -f origin branch_name

它不会删除我的任何代码。

但是,如果你想避免这种情况,你可以做到以下几点:

git checkout mastergit pull --rebasegit checkout -b new_branch_name

然后您可以选择所有提交到新分支。git cherry-pick COMMIT ID然后推你的新分支。

由于OP确实理解问题,只是寻找更好的解决方案…

这作为一种实践怎么样?

  • 拥有实际的功能开发分支(在那里你永远不会重新定位和强制推送,所以你的功能开发同事不会讨厌你)。在这里,定期通过合并从main获取这些更改。

  • 有第二个功能开发分支,其中一个功能团队成员常规推送所有功能提交,实际上是重新基于的,实际上是强制的。所以几乎完全基于最近的主提交。功能完成后,将该分支推送到master之上。

可能已经有此方法的模式名称。

我将使用“签出-b”,这更容易理解。

git checkout myFeaturegit rebase mastergit push origin --delete myFeaturegit push origin myFeature

当您删除时,您会阻止推送包含不同SHA ID的退出分支。在这种情况下,我只删除远程分支。

而不是使用-f--force开发人员应该使用

--force-with-lease

为什么?因为它会检查远程分支是否有更改,这绝对是个好主意。假设James和Lisa在同一个功能分支上工作,Lisa推送了一个提交,James现在重写他的本地分支,当试图推送时被拒绝。James当然认为这是由于rebase的原因,并且使用--force并且会重写Lisa所有的更改。如果James使用了--force-with-lease,他会收到一个警告,说有其他人完成了提交。我不明白为什么有人在rebase后推送时会使用--force而不是--force-with-lease

我避免强制推动的方法是创建一个新分支并继续在该新分支上工作,在一些稳定性之后,删除重新基于的旧分支:

  • 在本地重设签出分支
  • 从rebase分支分支到新分支
  • 将该分支作为新分支推送到远程。并删除远程上的旧分支

对我来说,以下简单的步骤有效:

1. git checkout myFeature2. git rebase master3. git push --force-with-lease4. git branch -f master HEAD5. git checkout master6. git pull

完成以上操作后,我们也可以通过以下命令删除myFeature分支:

git push origin --delete myFeature

获取master的新变化,在最新master的基础上rebase特征分支

git checkout mastergit pullgit checkout featuregit pull --rebase origin mastergit push origin feature

我会像下面这样做

rebase featuregit checkout -b feature2 origin/featuregit push -u origin feature2:feature2Delete the old remote branch featuregit push -u origin feature:feature

现在遥控器将具有功能(基于最新的主服务器)和功能2(具有旧的主服务器头)。如果您在重新解决冲突时犯了错误,这将允许您稍后进行比较。

首先道歉,这不是一个答案通常这应该是一个答案,但我认为重要的是要强调答案看起来不像使用rebase的正确方法(有些是有效的解决方法,但并不像我们对git的期望那样优雅)。

  1. “git force”-很危险,可能会覆盖其他人的工作
  2. 创建新分支-将需要与在此功能分支上工作的其他人同步,错过了使用git的重点。
  3. 重新创建分支(在使用或不使用单行魔术命令删除它之后),与#2中的问题相同。
  4. “git合并”-rebase旨在避免/防止日志中的合并提交并保持git日志的干净和一致。

不幸的是,我还没有答案。在上面的“git合并”之间是唯一对团队工作安全的。


[编辑#1]根据艾特莱森的伟大医生 rebase应该只用于你的本地工作

不要重写公共历史。正如我们之前在重写历史中讨论过的,一旦提交被推送到公共存储库,你就永远不应该重设提交基数。重设基数会用新提交替换旧提交,看起来你的项目历史的这一部分突然消失了。


[编辑#2]根据这个很好的解释,这是一个预期的行为。这意味着您可能需要重新合并已经在原始提交中合并的内容。如果torec是正确的,如果我得到了正确的,那么我投票支持旧的拉(获取/合并)流。

[编辑#3]以上所有可能是正确的,具体取决于场景。如果你和朋友一起工作在一个功能分支上,不要“推送--force”但获取并合并来源/功能1。如果你独自工作在一个分支上,你可以“推送--force”并享受一个漂亮的日志。