如何在裸仓库中编写钩子自动将main分支提交cherry-pick到其他工作树?
问题描述
我拥有main、macos、linux三个分支,希望在main分支完成提交后,自动将该提交cherry-pick到另外两个分支,且操作需在裸仓库中进行。
我已能通过手动执行以下命令完成该操作:
git --git-dir=<path-to-bare-repo>/worktrees/linux --work-tree=<path-to-bare-repo>/linux cherry-pick main git --git-dir=<path-to-bare-repo>/worktrees/macos --work-tree=<path-to-bare-repo>/macos cherry-pick main
但编写post-commit钩子脚本后,执行时出现“本地更改将被覆盖”的错误,钩子未按预期工作。我的钩子脚本如下:
#!/bin/bash current_branch=$(git symbolic-ref --short HEAD) # Check if committing to the main branch if [ "$current_branch" = "main" ]; then gitdir=$(dirname `pwd`) # Update the linux branch git --git-dir="$gitdir/worktrees/linux" --work-tree="$gitdir/linux" cherry-pick main # Update the macos branch git --git-dir="$gitdir/worktrees/macos" --work-tree="$gitdir/macos" cherry-pick main fi
执行提交时的错误信息为:
git commit -m "Add README" error: your local changes would be overwritten by cherry-pick. hint: commit your changes or stash them to proceed. fatal: cherry-pick failed error: your local changes would be overwritten by cherry-pick. hint: commit your changes or stash them to proceed. fatal: cherry-pick failed [main ed96ee9] Add README 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README
我也曾尝试使用cd ../linux; git cherry-pick main,但同样无法正常工作。请问如何修复该钩子脚本?
修复方案
出现“本地更改将被覆盖”错误的核心原因是linux、macos对应的worktree工作区存在未提交的本地修改,或者当前worktree的HEAD状态与分支最新提交不一致;另外钩子中通过dirname \pwd``获取git仓库路径的方式不可靠,因为post-commit钩子执行时的工作目录不一定是仓库根目录。
可以按以下思路修改钩子脚本:
- 用可靠方式获取仓库路径:通过
git rev-parse --git-dir获取裸仓库的绝对路径,避免依赖当前工作目录。 - 确保worktree分支状态正确:cherry-pick前切换到目标分支,保证分支处于最新状态。
- 处理工作区未提交修改:提前检查工作区是否干净,若有未提交内容先暂存,避免覆盖。
修改后的钩子脚本如下:
#!/bin/bash current_branch=$(git symbolic-ref --short HEAD) # 仅在main分支提交后执行操作 if [ "$current_branch" = "main" ]; then # 获取裸仓库的绝对路径 bare_repo=$(git rev-parse --git-dir) # 处理linux分支 linux_git_dir="$bare_repo/worktrees/linux" linux_work_tree="$bare_repo/linux" # 切换到linux分支并拉取最新状态(无需同步远程可去掉pull) git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" checkout linux git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" pull origin linux # 检查工作区是否有未提交修改,有则暂存 if ! git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" diff --quiet; then git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" stash push -m "Auto-stash before cherry-pick from main" fi # 执行cherry-pick git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" cherry-pick main # 可选:若需要恢复暂存的修改,取消下面注释(注意可能引发冲突) # git --git-dir="$linux_git_dir" --work-tree="$linux_work_tree" stash pop # 处理macos分支(逻辑同linux分支) macos_git_dir="$bare_repo/worktrees/macos" macos_work_tree="$bare_repo/macos" git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" checkout macos git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" pull origin macos if ! git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" diff --quiet; then git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" stash push -m "Auto-stash before cherry-pick from main" fi git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" cherry-pick main # git --git-dir="$macos_git_dir" --work-tree="$macos_work_tree" stash pop fi
额外注意事项
- 确保钩子脚本拥有可执行权限:在裸仓库中执行
chmod +x hooks/post-commit。 - 如果你的linux、macos分支不需要同步远程仓库,可以去掉
git pull步骤。 - 若自动恢复暂存的修改,需做好冲突处理的准备,建议在稳定的代码场景下使用。
内容的提问来源于stack exchange,提问作者sahinakkaya
相关产品推荐
相关产品推荐

