Git钩子脚本如何禁止强制推送主分支

wen 实用脚本 1

本文目录导读:

Git钩子脚本如何禁止强制推送主分支

  1. 方法一:服务器端 pre-receive 钩子(推荐)
  2. 方法二:客户端 pre-push 钩子(辅助措施)
  3. 方法三:使用 Git 服务提供商的功能
  4. 测试脚本是否生效
  5. 注意事项

在Git仓库中禁止强制推送(force push)到主分支(如mainmaster),可以通过服务器端钩子(pre-receive)或客户端钩子(pre-push)实现,最推荐的方式是服务器端钩子,因为它能强制所有用户遵守规则。

服务器端 pre-receive 钩子(推荐)

此方法在远程仓库执行,所有推送都会被检查,无法绕过(除非拥有服务器直接修改权限)。

创建 pre-receive 脚本

在Git服务器端的仓库目录下(如 /path/to/repo.git/hooks/pre-receive),创建可执行脚本:

#!/bin/bash
# 禁止强制推送主分支(main 和 master)
# 此脚本应在服务器的 hooks 目录下
protected_branches="main master"
while read oldrev newrev refname; do
    # 检查是否涉及到受保护分支
    for branch in $protected_branches; do
        if [[ "$refname" == "refs/heads/$branch" ]]; then
            # oldrev 是全0(新创建的分支),跳过
            if [[ "$oldrev" =~ ^0+$ ]]; then
                continue
            fi
            # newrev 是全0(删除分支),阻止
            if [[ "$newrev" =~ ^0+$ ]]; then
                echo "ERROR: 不允许删除受保护分支: $branch"
                exit 1
            fi
            # 检查是否为强制推送
            # 获取两个提交的共同祖先
            merge_base=$(git merge-base "$oldrev" "$newrev" 2>/dev/null)
            # merge-base 不等于 oldrev,说明是强制推送(历史被修改)
            if [[ "$merge_base" != "$oldrev" ]]; then
                echo "ERROR: 不允许强制推送到受保护分支: $branch"
                echo "      请使用正常的推送方式或创建新分支提交代码"
                exit 1
            fi
        fi
    done
done
exit 0

设置执行权限

chmod +x /path/to/repo.git/hooks/pre-receive

客户端 pre-push 钩子(辅助措施)

此方法在本地执行,只能作为提醒,不能完全阻止(用户可绕过)。

创建 pre-push 脚本

在本地仓库的 .git/hooks/pre-push 创建:

#!/bin/bash
# 禁止强制推送到主分支(客户端验证)
protected_branches="main master"
while read local_ref local_sha remote_ref remote_sha; do
    for branch in $protected_branches; do
        if [[ "$remote_ref" == "refs/heads/$branch" ]]; then
            # 如果存在 --force 或 -f 参数,阻止
            if [[ " $* " == *" --force "* ]] || [[ " $* " == *" -f "* ]]; then
                echo "ERROR: 不允许强制推送到受保护分支: $branch"
                echo "      请移除 --force 参数并重试"
                exit 1
            fi
            # 如果是强制推送(通过rev-list检测)
            # 注意:此方法可能不够准确
            if git rev-list "$remote_sha..$local_sha" 2>/dev/null | head -1 | grep -q .; then
                # 正常推送,没问题
                continue
            fi
            # 如果本地有强制推送操作
            if [[ "$local_sha" != "" ]] && [[ "$remote_sha" != "" ]]; then
                merge_base=$(git merge-base "$local_sha" "$remote_sha" 2>/dev/null)
                if [[ "$merge_base" != "$remote_sha" ]]; then
                    echo "ERROR: 检测到强制推送操作,禁止推送到 $branch"
                    exit 1
                fi
            fi
        fi
    done
done
exit 0

使用 Git 服务提供商的功能

如果你使用 Git Lab、GitHub、Bitbucket 等平台:

GitHub

  1. 进入仓库 Settings → Branches
  2. 添加分支保护规则
  3. 勾选 "Do not allow force pushes"

GitLab

  1. 进入 Settings → Repository → Protected Branches
  2. 选择要保护的分支
  3. 在 "Allowed to force push" 中选择 "No one"

Bitbucket

  1. 进入 Repository Settings → Branch permissions
  2. 添加权限规则
  3. 勾选 "Prevent force pushes"

测试脚本是否生效

测试强制推送是否被阻止:

# 尝试强制推送(应被阻止)
git push origin main --force
# 正常推送(应允许)
git push origin main

注意事项

  1. 服务器端钩子才是根本解决方案,客户端钩子可以被用户修改或绕过
  2. 对于已存在的强制推送,钩子不会拦截历史记录,只拦截未来的推送
  3. 如果使用 git push --force-with-lease,这个脚本同样会阻止
  4. 建议配合 pre-receive 钩子和平台功能双重保障

通过以上配置,可以有效防止开发人员意外或恶意强制推送到主分支。

抱歉,评论功能暂时关闭!