本文目录导读:

在Git仓库中禁止强制推送(force push)到主分支(如main或master),可以通过服务器端钩子(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
- 进入仓库 Settings → Branches
- 添加分支保护规则
- 勾选 "Do not allow force pushes"
GitLab
- 进入 Settings → Repository → Protected Branches
- 选择要保护的分支
- 在 "Allowed to force push" 中选择 "No one"
Bitbucket
- 进入 Repository Settings → Branch permissions
- 添加权限规则
- 勾选 "Prevent force pushes"
测试脚本是否生效
测试强制推送是否被阻止:
# 尝试强制推送(应被阻止) git push origin main --force # 正常推送(应允许) git push origin main
注意事项
- 服务器端钩子才是根本解决方案,客户端钩子可以被用户修改或绕过
- 对于已存在的强制推送,钩子不会拦截历史记录,只拦截未来的推送
- 如果使用
git push --force-with-lease,这个脚本同样会阻止 - 建议配合
pre-receive钩子和平台功能双重保障
通过以上配置,可以有效防止开发人员意外或恶意强制推送到主分支。