git 强制分支在合并和推送之前重新定基

x3naxklr  于 2023-05-05  发布在  Git
关注(0)|答案(4)|浏览(172)

我想在我的Gitlab服务器上添加一个钩子,以防止在master上推送合并的分支,如果它们之前没有重新定基。
例如:A---B---C---D ← master \ E---F---G ← new-feature
我希望用户在合并/推送之前重新调整他的功能。A---B---C---D-------------H ← master \ / E'---F'---G'
我不想把这个推A---B---C---D---H ← master \ / E---F---G
这是一个很好的开始,但我不认为这意味着只拒绝非空的合并提交:Force Feature Branch to be Rebased Before it is Merged or Pushed

igsr9ssn

igsr9ssn1#

如果你还在找这个。gitlab是唯一实现这一点的git服务器。他们称之为半线性历史。查看第二个选项

这将在你的合并请求中无缝地执行这种历史(看右边):

wwwo4jvm

wwwo4jvm2#

这当然是可能的,但你需要写一些代码。您还必须决定什么定义了一个“好的”提交图更新。你的例子说,一个请求从这个:

o--o--o--*   <-- master

对此:

o--o--o--*---o   <-- master
    \       /
     o--o--o

是要被拒绝的,而这个:

o--o--o--*---------o   <-- master
          \       /
           o--o--o

是被接受的。那么第三种选择呢:

o--o--o--*------o-----o   <-- master
          \    /     /
           o--o--o--o

这增加了两个合并而不是一个;但是没有 new commit的merge有任何父节点是master的先前值的祖先。
那这个呢

o--o--o   <-- master

(Here push已经 * 删除了 * 曾经是master的tip的commit。
如果第二次推送,增加了两个合并,但没有一个返回到任何以前的提交,* 不 * 被接受,* 最后一次推送也不被接受,你的任务的一部分很容易:你想允许最多一次合并,也许限制它正好有两个父节点,其中一个是它的两个父节点-也许这必须是“第一个父节点”-作为master的先前值(标记为*的提交)。剩下的任务可能就是完全允许 no 合并,只要提议的新master不是旧master的祖先(没有提交被删除)。
如果第二个(两个合并)推送 * 被接受,编码将更加复杂。请注意,如果它不被接受,某人仍然可以推送这样的合并,他们只需要分多个步骤来做(每个合并推送一次)。

ufj5ltwl

ufj5ltwl3#

强制变基的通常原因是对合并提交的病态厌恶,因为设置策略的人看不到它们的价值。不清楚为什么你想利用变基的缺点(可能中间提交没有经过测试),但仍然要合并;这在我看来是最不有价值的合并提交。但如果你一定要...
你暗示你想接受的合并将是“空的”;不完全是这样。它将更改应用于第一个父节点(但不应用于第二个父节点,因为如果允许的话,它将是一个快进)。
我认为你真正的意思是,如果第一个父节点可以从第二个父节点到达(通过父节点指针),你会接受合并。所以你可以把

git rev-list --merges $oldrev..$newrev

并将每个结果提交ID作为 commit-ID 参数提供给

git merge-base --is-ancestor commit-ID^ commit-ID^2

如果merge-base命令返回非零,则拒绝。
(从技术上讲,我猜你可能还想确保提交没有3个或更多的父节点。
仍然允许这样的事情发生

(origin/master)
            |
x -- x -- x -------------------- M <--(master)
           \                    /
            x -- x -------x -- x
                  \      /
                   x -- x

如果避免这是一条规则,那就明显更难了;你基本上会希望每个合并都可以通过头提交的第一个父指针到达。(但是你不能 * 只是 * 说合并应该从头提交的第一个父提交可到达,因为那样你仍然允许

(origin/master)
            |
x -- x -- x -------------------- M -- x<--(master)
           \                    /
            x -- x -------x -- x
                  \      /
                   x -- x

这是一回事。)所以,作为开始寻找合并之前的“第一步”,您可以执行

git rev-list --first-parent $oldrev..$newrev

并挂起返回的所有提交ID值的列表,这样当您找到每个合并时,您可以确认它在该列表中。
如果这一切听起来一点都不有趣,我完全同意;这就是为什么我不打算麻烦地尝试根据这个建议组装一个工作脚本,也是为什么我建议您要么允许合并,要么不允许合并,而不是试图采取这种不寻常的中间立场。

3lxsmp7m

3lxsmp7m4#

pre-receive hook:

#!/usr/bin/env python3

import fileinput
import sys
import subprocess

protected_branch = 'main'

for line in fileinput.input():
    s = line.split()
    old = s[0]
    new = s[1]
    ref = s[2]
    if ref == 'refs/heads/' + protected_branch:
        first_parent = subprocess.check_output(["git", "rev-parse", new + "^1"]).strip().decode()
        if first_parent != old:
            error = 'Rejected: Not a semi-linear update. See: https://stackoverflow.com/q/44500174/1725151'
            print(error, file=sys.stderr)
            exit(1)

这也将拒绝不是合并的更新,如果它们包含多个提交。如果您对快进合并没有问题,您可能希望更改这一点。
这可以扩展到在另一个答案中也包含deny-merges检查。

相关问题