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

Git post-receive钩子远程执行异常:子模块拉取失败

问题:Git checkout --recurse-submodules无法拉取Hugo主题子模块导致构建失败

场景描述

在服务器上配置Git自动化编译Hugo网站并部署到/var/www/html,流程为:创建临时Hugo站点 → 检出目标仓库及其Hugo主题子模块 → Hugo构建静态文件并部署到Web目录。但执行git --work-tree=$TARGET_DIR --git-dir=./ checkout -f --recurse-submodules时,子模块无法正常拉取,导致Hugo因缺少主题无法完成构建。

仓库结构:site.ext仓库包含content/、hugo.toml、static/目录,Hugo主题以Git子模块形式存在。

原脚本

#!/bin/bash

# Directory where to work on our site
TARGET_DIR=/tmp/site-compile
# Public dir where to push the site once compiled
PUBLIC_WWW="/var/www/html"
BACKUP_WWW=$HOME/site-backup
SITE_DOMAIN=https://site.ext
# repository logical name
REPO="site.ext"
# Branch that is going to be deployed to server
BRANCH="master"
# date to be appended to latest tag
NOW=$(date +"%d%m%Y-%H%M")

set -xe

# delete the working directory first
rm -rf $TARGET_DIR
# create new temporary site
/usr/local/bin/hugo new site $TARGET_DIR
# backup public www directory first then setup trap
rsync -avz --no-t $PUBLIC_WWW/ $BACKUP_WWW
trap "echo 'A problem occurred.  Reverting to backup.'; rsync -avz --no-t --del $BACKUP_WWW/ $PUBLIC_WWW; rm -rf $TARGET_DIR" EXIT

while read oldrev newrev ref
do
        # if TARGET_DIR is empty we don't want deploy for this project
        if [[ ! $TARGET_DIR == "" ]]; then
                if [[ "$GL_REPO" == "$REPO" ]]; then
                        # let's check that we are deploying to the correct branch
                        if [[ $ref = refs/heads/${BRANCH} ]]; then
                                echo "Ref $ref received. Deploying '${BRANCH}' branch to production..."
                                git --work-tree=$TARGET_DIR --git-dir=./ checkout -f --recurse-submodules
                                rm ${TARGET_DIR}/config.toml
                                rm -rf $PUBLIC_WWW/*
                                /usr/local/bin/hugo -s $TARGET_DIR -d $PUBLIC_WWW -b "${SITE_DOMAIN}" -t "dagreynix" --noTimes --minify
                                git tag release_$NOW $BRANCH
                                echo "   /==============================="
                                echo "   | DEPLOYMENT COMPLETED - ${REPO}"
                                echo "   | Target branch: ${BRANCH}"
                                echo "   | Target folder: ${PUBLIC_WWW}"
                                echo "   | Tag name     : release_${NOW}"
                                echo "   \==============================="
                        else
                                echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
                        fi
                fi
        else
                echo "Target directory not declared. Skipping deploy to server."
        fi
done

rm -rf $TARGET_DIR
trap - EXIT

问题原因

当使用--work-tree和--git-dir分离Git工作树与仓库目录时,checkout --recurse-submodules参数无法正确触发子模块的初始化与更新。Git在这种分离模式下,不会自动关联子模块的目录结构,导致子模块内容无法拉取到指定的工作树路径。

解决方法

将原脚本中的checkout命令拆分为两步:先执行分支检出,再单独初始化并更新子模块,明确指定工作树路径:

替换原脚本中:

git --work-tree=$TARGET_DIR --git-dir=./ checkout -f --recurse-submodules

为:

# 先检出主仓库分支到目标工作树
git --work-tree=$TARGET_DIR --git-dir=./ checkout -f
# 初始化并递归更新所有子模块到目标工作树
git --work-tree=$TARGET_DIR --git-dir=./ submodule update --init --recursive

修正后完整脚本

#!/bin/bash

# Directory where to work on our site
TARGET_DIR=/tmp/site-compile
# Public dir where to push the site once compiled
PUBLIC_WWW="/var/www/html"
BACKUP_WWW=$HOME/site-backup
SITE_DOMAIN=https://site.ext
# repository logical name
REPO="site.ext"
# Branch that is going to be deployed to server
BRANCH="master"
# date to be appended to latest tag
NOW=$(date +"%d%m%Y-%H%M")

set -xe

# delete the working directory first
rm -rf $TARGET_DIR
# create new temporary site
/usr/local/bin/hugo new site $TARGET_DIR
# backup public www directory first then setup trap
rsync -avz --no-t $PUBLIC_WWW/ $BACKUP_WWW
trap "echo 'A problem occurred.  Reverting to backup.'; rsync -avz --no-t --del $BACKUP_WWW/ $PUBLIC_WWW; rm -rf $TARGET_DIR" EXIT

while read oldrev newrev ref
do
        # if TARGET_DIR is empty we don't want deploy for this project
        if [[ ! $TARGET_DIR == "" ]]; then
                if [[ "$GL_REPO" == "$REPO" ]]; then
                        # let's check that we are deploying to the correct branch
                        if [[ $ref = refs/heads/${BRANCH} ]]; then
                                echo "Ref $ref received. Deploying '${BRANCH}' branch to production..."
                                git --work-tree=$TARGET_DIR --git-dir=./ checkout -f
                                git --work-tree=$TARGET_DIR --git-dir=./ submodule update --init --recursive
                                rm ${TARGET_DIR}/config.toml
                                rm -rf $PUBLIC_WWW/*
                                /usr/local/bin/hugo -s $TARGET_DIR -d $PUBLIC_WWW -b "${SITE_DOMAIN}" -t "dagreynix" --noTimes --minify
                                git tag release_$NOW $BRANCH
                                echo "   /==============================="
                                echo "   | DEPLOYMENT COMPLETED - ${REPO}"
                                echo "   | Target branch: ${BRANCH}"
                                echo "   | Target folder: ${PUBLIC_WWW}"
                                echo "   | Tag name     : release_${NOW}"
                                echo "   \==============================="
                        else
                                echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
                        fi
                fi
        else
                echo "Target directory not declared. Skipping deploy to server."
        fi
done

rm -rf $TARGET_DIR
trap - EXIT

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 05:03:36