git merge:强制执行线性历史记录和合并提交

Edh*_*dil 3 git merge git-workflow

在我们的项目中,我们希望合并的功能分支在 中可见git log --graph,但仍然具有线性历史记录,以便在功能分支的持续时间内主分支上没有提交。这意味着,确保功能分支在合并到主分支之前重新基于主分支。

目前,我们已经使用别名merge = merge --no-ff并尝试记住git rebase合并之前所做的事情,但有时我们会忘记。

即如果合并之前的情况是这样的:

A--B--C--D
    \
     E--F
Run Code Online (Sandbox Code Playgroud)

我们想要强制执行这个结果 (0)

A--B--C--D------m--
          \    /
           E--F
Run Code Online (Sandbox Code Playgroud)

并阻止这种行为 (1)

A--B--C--D--m--
    \      /
     E----F
Run Code Online (Sandbox Code Playgroud)

或这个(2)

A--B--C--D--E--F--
Run Code Online (Sandbox Code Playgroud)

不幸的是,我不知道如何使用 git 别名来实现这一点。

  • git merge --no-ff创建合并提交,但允许结果 (1)
  • git merge --ff-only确保主分支上没有提交,但创建结果 (2)
  • git merge --ff愉快地创建(1)或(2),但没有创建(0)
  • git merge --ff-only --no-ff表现得像--no-ff

我们都需要独立于其他人提交到主分支,因此基于限制对主分支的访问或代码审查的解决方案并没有真正的帮助。

TTT*_*TTT 5

命名警告:我不建议将其称为“线性历史”,因为没有上下文,这几乎总是意味着根本没有合并提交。

您想要实现的目标通常称为“半线性合并”或“变基,合并”策略。这提供了“气泡”功能,并且这些气泡在日志中线性显示。请注意,当功能分支只有一次提交时,有些人允许跳过合并提交,因为从功能上讲,结果图中没有信息丢失。您应该决定是否允许这样做。(我个人的偏好是为了一致性而不允许这样做。但这意味着我们最终会得到很多微小的一次提交+一次合并提交气泡,这并不困扰我。)

至于如何实现这一点,我不推荐您提出的别名想法。在很多情况下,您可能希望在本地存储库的日常工作中快进合并。

相反,我首先倾向于在服务器端强制执行该策略,如果不可能,那么您可以尝试使用钩子。对于服务器端实现,这里有一个答案,讨论了流行的工具及其与此策略相关的功能。(目前,Azure DevOps 和 Bitbucket 都可以开箱即用地强制执行此操作。)如果您使用的工具没有内置支持,请考虑实施某种门控签入,以验证源分支是否完全是最新的允许完成合并(或推送)之前的目标。有很多方法可以进行该检查,其中之一可能是(使用 Bash):

# return the target branch tip commit if it passes, nothing otherwise:
git rev-list <source-branch> | grep $(git rev-parse <target-branch>)
Run Code Online (Sandbox Code Playgroud)

关于此声明的注意事项:

我们都需要独立于其他人提交到主分支,因此基于限制对主分支的访问或代码审查的解决方案并没有真正的帮助。

您仍然可以强制执行拉取请求完成策略,而不需要其他人批准您的代码。例如,在 Azure DevOps 中,您需要 PR 将分支合并到 中main,然后只允许半线性合并。AzDO 会自动为您重新设置基础(如果需要),然后创建合并提交,您仍然不需要涉及其他人。我非常确定 Bitbucket 具有开箱即用的相同功能。对于 GL 或 GH,您需要 MR/PR,但允许自行完成,并打开门控签入,仅允许在完全更新的情况下完成它。

如果您要合并到main本地并直接推送远程main,则另一种机制将使用Git hooks。也许pre-mergepre-push钩子效果最好。在钩子内部,您可以查看 的 HEAD 提交main,并确保以下内容为真:

  1. 这是一个合并提交。
  2. @^1两个父提交(和)的合并基础@^2等于与第一个父提交( )相同的提交@^1

旁注:将功能分支合并到共享分支时,可以强制执行此策略。但是,如果您使用的工作流程具有多个共享分支,则您不希望将一个共享分支变基到另一个共享分支,因此请确保在进行这些合并时仅使用普通的旧合并。