Git 强制推送:如何防止覆盖其他用户的更改

Mot*_*Mot 4 git git-push

我经常必须使用git resetgit rebase更改一些最近的提交(重新排列、将多个提交合并为一个,...)。这需要在推动时使用力选项。不幸的是,这也可能会覆盖远程存储库中其他用户的更改。

为什么我需要重写历史?因为我们在功能分支中做了很多工作(具体来说,从使用 Swing 转换为 SWT)并且必须使其尽可能短。为了实现这一点,我们经常发现,一些提交应该在功能分支分叉之前提交给主控。

git push如果我没有从远程存储库获取最新更改,如何使强制失败?

bdo*_*lan 5

如果其他人已经看到存储库中的历史提交,而您稍后去重写它们,那么您将会遇到问题。这只是git设计的一部分。

git 无法真正区分重写的提交但拥有最新的存储库和未重写的提交但在推送之前必须合并的提交。检测最新推送的方法很简单,只需检查目标引用中的每个提交是否都在您要推送的引用的历史记录中即可;这称为快进。当您变基时,您从本地分支中删除提交,并创建新的类似提交。git 无法确定这些新提交是否等于历史记录中的旧提交,将其视为待处理的合并,并且需要强制覆盖它并覆盖目标存储库中已有的内容

因此,如果你强制执行,你就会覆盖目的地中的所有内容。这是设计使然。此外,从您的存储库中提取内容的其他人也会因此看到问题。假设您翻转存储库中的提交顺序:

A-------B-------C oldmaster
 \
  ------C'------B' master
Run Code Online (Sandbox Code Playgroud)

如果其他用户在本地有 oldmaster 的副本,并从 master 拉取,git 将尝试合并这两个分支。C'这将双重应用和中的补丁B'。不好。Git有时可以在合并时检测到这些问题,但即使它正确合并,您也会留下:

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

现在你的重新调整的提交已经死而复生了。

使用 rebase 也没有帮助;你也可以得到这样的结果:

A------B------C------C'------B'
Run Code Online (Sandbox Code Playgroud)

在像这样的简单情况下,git 可能能够检测到双重应用的补丁并删除它们,但这并不能保证。

所以结论是:不要对其他人可见的提交进行变基。当它仍然是您在本地保留的私有分支时,或者当它是一个带有大警告的公共分支时,请执行您想要的所有变基操作:“开发分支 - 可能会变基 - 不要在这个分支上进行工作”。但当其他人在其基础上进行建设时,就不要再乱搞历史了。

如果您绝对必须一直与多个用户打乱历史记录,那么您可能会发现最好将功能分支作为补丁包使用,使用StGITguilttopgit或类似的。然后,您可以将它们作为补丁使用,对补丁进行重新排序(但不要更改提交本身!),然后当需要将更改推送到上游时,将补丁线性化到原始上游分支之上。