You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Git Pre-Receive Hook中检测推送是否包含Rebase?

判断Git推送中的Rebase操作(Pre-Receive Hook实现)

问题描述

我有一个Git Pre-Receive Hook,希望能够判断某次推送是否包含Rebase操作。我在网上找不到明确的处理方法,想请教各位是否有可行方案?目前我已通过以下代码处理合并请求,但无法处理Rebase:

parent_count=$(git rev-list --parents -n 1 "$rev" | awk '{print NF-1}')
if [[ $parent_count -gt 1 ]]; then
  exit 0
fi

核心思路

Rebase的本质是重写提交历史,会生成全新的提交对象(SHA值改变),但通常会保留原提交的内容。预接收钩子中可以通过「强制推送特征」+「提交内容哈希对比」来识别Rebase操作。

具体实现方案

1. 利用预接收钩子的输入参数

预接收钩子会从标准输入获取每行格式为oldrev newrev refname的内容:

  • oldrev:推送前分支的HEAD哈希
  • newrev:推送后分支的HEAD哈希
  • refname:推送的目标分支名

2. 初步过滤:判断是否为强制推送

Rebase后几乎必然需要强制推送,可先通过拓扑关系判断:

# 若newrev是oldrev的后代,说明是普通快进/非强制推送,无需检查Rebase
if git merge-base --is-ancestor "$oldrev" "$newrev"; then
  exit 0
fi

3. 深度检查:对比提交内容哈希

遍历新旧提交集合,检查是否存在「内容完全相同但SHA不同」的提交(这是Rebase的典型特征):

# 获取被替换的旧提交集合
old_commits=$(git rev-list "$newrev".."$oldrev")
# 获取Rebase生成的新提交集合
new_commits=$(git rev-list "$oldrev".."$newrev")

# 遍历新提交,对比内容哈希
for new_commit in $new_commits; do
  new_content_hash=$(git show "$new_commit" | git hash-object --stdin)
  for old_commit in $old_commits; do
    old_content_hash=$(git show "$old_commit" | git hash-object --stdin)
    if [[ "$new_content_hash" == "$old_content_hash" ]]; then
      echo "错误:推送包含Rebase操作,禁止提交"
      exit 1
    fi
  done
done

4. 完整钩子示例(结合原有合并判断)

#!/bin/bash

while read oldrev newrev refname; do
  # 处理首次推送(oldrev为全0哈希)
  if [[ "$oldrev" == "0000000000000000000000000000000000000000" ]]; then
    exit 0
  fi

  # 原有合并提交判断逻辑
  parent_count=$(git rev-list --parents -n 1 "$newrev" | awk '{print NF-1}')
  if [[ $parent_count -gt 1 ]]; then
    exit 0
  fi

  # 强制推送+Rebase检查
  if ! git merge-base --is-ancestor "$oldrev" "$newrev"; then
    old_commits=$(git rev-list "$newrev".."$oldrev")
    new_commits=$(git rev-list "$oldrev".."$newrev")

    for new_commit in $new_commits; do
      new_content_hash=$(git show "$new_commit" | git hash-object --stdin)
      for old_commit in $old_commits; do
        old_content_hash=$(git show "$old_commit" | git hash-object --stdin)
        if [[ "$new_content_hash" == "$old_content_hash" ]]; then
          echo "错误:推送包含Rebase操作,禁止提交"
          exit 1
        fi
      done
    done
  fi
done

exit 0

注意事项

  • 该方案无法覆盖「完全重写提交内容」的极端Rebase场景,但能处理绝大多数常规Rebase操作。
  • 若需允许特定分支的Rebase推送,可通过refname添加分支白名单判断。

内容的提问来源于stack exchange,提问作者Darragh MacKenna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:03:28