没有完美的方法来做到这一点。您可以使用钩子(如下所述)将开发人员推向正确的方向;如果您希望开发人员会遵守 no-ff 政策,但只是想帮助他们避免推动错误,那应该没问题。但是如果你需要真正严格的执行,那么你可能只需要使用访问控制来限制谁可以推送到分支。
通常,要执行有关分支如何移动的策略,您会使用钩子。有关在 bitbucket 中使用 hooks 的信息可以在这里找到:https://confluence.atlassian.com/bitbucketserver/using-repository-hooks-776639836.html
因此可行的方式是,开发人员可以在本地进行快进;但是当他们尝试将其推送到远程时,您将编写一个识别并拒绝该分支的快进的钩子。您让您的开发人员知道您正在这样做,然后任何明智的开发人员将在本地应用 --no-ff 配置,这样他们就不会意外地进行本地提交,而他们不得不浪费时间撤消。您甚至可以在 repo 中放置一个脚本来更新本地配置以简化操作。 (但你不能强制它必须在本地运行——这就是你依赖钩子的原因。)
但是,在推送时,通常无法判断是否发生了快进合并[1]。您可以做的最好的事情是拒绝似乎可能发生快进的推送,并接受似乎可能没有发生快进的推送。
因此,您可以寻找两件事。可能最“物有所值”是要求分支上的所有提交(仅遍历第一个父母)都是合并提交。所以你的钩子可以在从旧参考到建议的更新参考的提交范围内运行类似git rev-list --first-parent --no-merges 的东西。如果这产生了任何输出,则推送被拒绝。
除了拒绝快进合并之外,这还会拒绝直接提交到分支的提交。这可能是您想要的,但如果出现异常情况,处理起来可能会很麻烦。无论如何,直接提交到分支的提交通常与您通常从快进合并中获得的内容没有区别。
从技术上讲,有人仍然可以做这样的事情
x -- x -- o <--(target_branch)
|\
| ----- M <-(other_branch)
\ /
A -- B
然后在不触发挂钩的情况下将target_branch 快进到other_branch。
如果目标分支的第一个父提交包含曾经推送到远程中不同分支的任何提交,您可以做的另一件事是让钩子拒绝推送。就其本身而言,这不会阻止某人创建本地分支并在没有推送它的情况下快速转发到它。它可以与第一个“仅合并”检查一起用作额外检查。但它只会捕获偶尔出现的边缘情况,而且编写起来会更复杂,运行起来也会更昂贵——因此不太可能值得。
[1] 从远程的角度来看,从技术上讲,分支在 push 上的移动方式通常被认为是快进。它可能是对在本地 repo 中创建的合并的快进,但对于远程本身仍然“看起来”是快进,除非在强制推送的情况下。