我经常需要使用git reset
和git rebase
来更改一些最近的提交(重新排列,将多个提交合并为一个,......)。这需要在推动时使用强制选项。不幸的是,这也可能会覆盖远程存储库中其他用户的更改。
为什么我需要重写历史?因为我们在功能分支中做了很多工作(从使用Swing转换为SWT,具体而言)并且必须尽可能地保持它。为了达到这个目的,我们经常发现,在分支功能分支之前,有些提交应该转到master。
如果我没有从远程存储库中获取最新更改,如何使强制git push
失败?
答案 0 :(得分:4)
如果其他人已经看到了存储库中的历史提交,并且您稍后再重写它们,那么您将遇到问题。这只是git设计的一部分。
git无法真正区分您的重写提交但是拥有最新的存储库以及您没有重写提交但是在推送之前必须合并的提交。检测到最新推送的方法只需检查目标ref中的每个提交是否在您正在推送的ref的历史记录中;这被称为快进。重新绑定时,删除本地分支的提交,并创建新的类似提交。 git无法确定这些新提交是否等于历史记录中的旧提交,将其视为待处理合并,并且需要强制覆盖此设置并且覆盖目标存储库中已有的任何内容。 / p>
所以,如果你强迫,你会覆盖目的地的任何东西。这是设计的。此外,从您的存储库中撤出的其他人也会因此而看到问题。假设你翻转了存储库中提交的顺序:
A-------B-------C oldmaster
\
------C'------B' master
如果其他一些用户在本地拥有oldmaster的副本,并从master获取,git将尝试合并这两个分支。这将在C'
和B'
中重复应用修补程序。不好。 Git可以有时在合并时检测到这些问题,但即使它正确合并,您也会留下:
A-------B-------C------D master
\ /
------C'------B'----
现在你的重新提交已经从死里复活了。
使用rebase也没有帮助;你也可以最终得到:
A------B------C------C'------B'
在这样的简单情况下,git可能能够检测到双重应用的补丁并将其删除,但不能保证。
总而言之:不要重新定义其他人可见的提交。当它仍然是你在本地保留的私人分支时,或当它是一个有大警告的公共分支时说“开发分支 - 可能会被重新考虑 - 不要在这个分支上工作”时,做你想要的所有变基。但是,当其他人正在建立它的那一刻,停止搞乱历史。
如果绝对必须一直与多个用户混淆历史记录,您可能会发现使用StGIT,guilt,{{{ 3}}或类似的。然后,您可以将它们作为补丁使用,重新排序所需的补丁(但不要自行更改提交!),然后在将更改推送到上游时,将补丁线性化到原始顶部上游分支。
答案 1 :(得分:2)
我不知道一个简单的答案,虽然可能有一些魔法,你可以用回购上的钩子拉。然而,在多用户设置中强制更新通常是一个坏主意。我怀疑更好的答案是改变你使用git的方式。
首先,你真的需要重写历史吗?大多数情况下,正确的答案是保留历史,只添加新的提交。
如果你真的认为你必须重新安排提交(比如说符合编码标准吗?)并且你不能教育那些做出这些提交的人第一次正确使用它们,你是否考虑过不同的设置?拥有一个中央“祝福”存储库,但只允许发布工程师(或集成工程师或团队或任何您想要称之为的人)推送它。普通用户在其他地方(通常在他们自己的工作站上)发布repos而不是推送,他们要求发布工程师从他们那里取消。然后,发布工程师检查更改,根据需要重新排列和合并它们,运行任何测试或其他所需步骤,并将结果推送到受祝福的存储库。