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

如何通过post-commit钩子实现main分支与所有分支/工作树自动同步?

错误原因

你报错的核心原因是post-commit钩子执行时,当前工作目录正处于你刚完成提交的分支上,直接尝试checkout已经被当前工作区占用的分支必然会失败。而且频繁切换工作区还会打乱你本地的未提交变更,本身就不适合在钩子中使用。

适配你需求的解决方案

根据你补充的场景,需求可以简化为两个分支逻辑,完全不需要切换当前工作区的分支就能实现:

  1. 提交到main分支时,将main的最新变更合并到所有其他本地分支
  2. 提交到非main分支时,仅将main的最新变更合并到当前提交的分支,避免后续合并冲突

版本要求(Git 2.30+)

Git 2.30及以上版本支持git merge --into-name参数,可以在不切换到目标分支的前提下完成合并操作,完美适配钩子场景。

完整post-commit脚本

#!/bin/sh

# 获取当前提交的分支名
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# 定义合并失败时的提示文本
MERGE_FAILED_MSG="合并main到%s失败,存在冲突,请手动解决后再提交\n"

if [ "$CURRENT_BRANCH" = "main" ]; then
  # 提交到main分支,遍历所有本地分支合并
  for BRANCH in $(git for-each-ref --format='%(refname:short)' refs/heads/ | grep -v "^main$"); do
    echo "正在合并main到$BRANCH..."
    git merge --into-name "$BRANCH" main --no-edit > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      printf "$MERGE_FAILED_MSG" "$BRANCH"
      # 回滚未完成的合并
      git merge --abort > /dev/null 2>&1
    fi
  done
else
  # 提交到非main分支,仅合并main到当前分支
  echo "正在合并main到$CURRENT_BRANCH..."
  git merge --into-name "$CURRENT_BRANCH" main --no-edit > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    printf "$MERGE_FAILED_MSG" "$CURRENT_BRANCH"
    git merge --abort > /dev/null 2>&1
  fi
fi

exit 0

低版本Git兼容方案(<2.30)

如果你的Git版本不支持--into-name参数,可以用临时worktree的方式实现,全程不影响当前工作区:

#!/bin/sh

CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
MERGE_FAILED_MSG="合并main到%s失败,存在冲突,请手动解决后再提交\n"
# 创建临时worktree目录
TMP_WORKTREE=$(mktemp -d)
trap 'rm -rf "$TMP_WORKTREE"' EXIT

git worktree add --detach "$TMP_WORKTREE" > /dev/null 2>&1
cd "$TMP_WORKTREE" || exit 1

if [ "$CURRENT_BRANCH" = "main" ]; then
  for BRANCH in $(git for-each-ref --format='%(refname:short)' refs/heads/ | grep -v "^main$"); do
    echo "正在合并main到$BRANCH..."
    git checkout "$BRANCH" > /dev/null 2>&1
    git merge main --no-edit > /dev/null 2>&1
    if [ $? -ne 0 ]; then
      printf "$MERGE_FAILED_MSG" "$BRANCH"
      git merge --abort > /dev/null 2>&1
    fi
  done
else
  echo "正在合并main到$CURRENT_BRANCH..."
  git checkout "$CURRENT_BRANCH" > /dev/null 2>&1
  git merge main --no-edit > /dev/null 2>&1
  if [ $? -ne 0 ]; then
    printf "$MERGE_FAILED_MSG" "$CURRENT_BRANCH"
    git merge --abort > /dev/null 2>&1
  fi
fi

注意事项

  • 由于你的配置文件对顺序敏感、容易出现冲突,脚本没有做自动冲突处理,合并失败后会直接提示你手动解决,避免生成错误的配置
  • 脚本默认只在本地分支执行合并,如果需要同步到远程,可自行在合并成功的逻辑中添加git push origin <分支名>的命令,不建议直接添加自动推送逻辑,避免错误合并被同步到远端
  • 不要直接操作.git/refs/heads下的文件获取分支列表,用git for-each-ref是更稳定的实现方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 17:03:01