在pre-push钩子中同步
这个方案在推送前先拉取上游最新代码,确保本地代码基于最新版本。

创建 pre-push 钩子
# 在 .git/hooks/ 目录下创建 pre-push 文件 touch .git/hooks/pre-push chmod +x .git/hooks/pre-push
pre-push 脚本内容
#!/bin/bash
# 获取当前分支名
current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
# 只对 master/main 分支执行
if [ "$current_branch" = "master" ] || [ "$current_branch" = "main" ]; then
echo "🔄 正在同步上游最新代码..."
# 保存当前状态
git stash --include-untracked 2>/dev/null || true
# 拉取最新代码
git fetch upstream
git rebase upstream/"$current_branch"
if [ $? -ne 0 ]; then
echo "❌ 合并冲突,已停止推送"
git stash pop 2>/dev/null || true
exit 1
fi
# 恢复暂存的工作
git stash pop 2>/dev/null || true
echo "✅ 上游代码同步完成"
fi
exit 0
在post-checkout钩子中同步
切换分支时自动同步,适合多分支协作场景。
创建 post-checkout 钩子
touch .git/hooks/post-checkout chmod +x .git/hooks/post-checkout
post-checkout 脚本内容
#!/bin/bash
# 参数说明: $1=旧HEAD, $2=新HEAD, $3=是否分支切换(1=是, 0=否)
if [ "$3" = "1" ]; then
new_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
echo "🌿 切换到分支: $new_branch"
echo "🔄 正在同步上游代码..."
# 确保有上游分支配置
if git rev-parse --abbrev-ref @{upstream} >/dev/null 2>&1; then
git fetch upstream
git rebase upstream/"$new_branch"
if [ $? -ne 0 ]; then
echo "⚠️ 同步失败,请手动处理"
exit 1
fi
echo "✅ 上游代码同步完成"
else
echo "ℹ️ 未配置上游分支,跳过同步"
fi
fi
exit 0
在post-merge钩子中同步
合并操作完成后自动同步到上游分叉点。
创建 post-merge 钩子
touch .git/hooks/post-merge chmod +x .git/hooks/post-merge
post-merge 脚本内容
#!/bin/bash
current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
# 跳过从上游拉取后的自动合并
if [ -f .git/MERGE_HEAD ]; then
exit 0
fi
echo "🔄 合并完成,检查上游更新..."
# 获取上游最新分支指向
upstream_ref="upstream/$current_branch"
if git rev-parse --verify "$upstream_ref" >/dev/null 2>&1; then
# 检查是否有新的提交
behind=$(git rev-list --count HEAD.."$upstream_ref" 2>/dev/null)
if [ "$behind" -gt 0 ]; then
echo "ℹ️ 上游有 $behind 个新提交"
read -p "是否现在同步? (y/N): " response
if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
git rebase "$upstream_ref"
echo "✅ 同步完成"
fi
else
echo "✅ 已是最新"
fi
fi
exit 0
高级版本:多场景智能同步脚本
这是一个更完整的解决方案,可适配多个钩子:
#!/bin/bash
# ===== 配置 =====
UPSTREAM_REMOTE="upstream"
ALLOW_DIRTY_WORK_TREE=true # 是否允许在修改工作区时同步
AUTO_STASH=true # 是否自动暂存修改
INTERACTIVE_MODE=false # 交互模式
# ===== 核心函数 =====
sync_upstream() {
local branch=${1:-$(git symbolic-ref --short HEAD 2>/dev/null)}
local source=${2:-"pre-push"}
# 跳过保护分支列表
local protected_branches="develop|test|staging"
if echo "$branch" | grep -Eq "^($protected_branches)$"; then
echo "ℹ️ 保护分支 $branch,跳过自动同步"
return 0
fi
# 检查远程是否可访问
if ! git remote get-url "$UPSTREAM_REMOTE" >/dev/null 2>&1; then
echo "⚠️ 未配置上游远程: $UPSTREAM_REMOTE"
return 0
fi
echo "=== 🚀 开始上游同步 ($source) ==="
echo "分支: $branch"
# 保存当前工作目录状态
local stashed=false
if [ "$AUTO_STASH" = true ] && ! git diff-index --quiet HEAD -- 2>/dev/null; then
echo "📦 暂存当前修改..."
git stash push -m "auto-sync-$(date +%s)"
stashed=true
fi
# 拉取最新代码
echo "📥 从 $UPSTREAM_REMOTE 获取更新..."
if ! git fetch "$UPSTREAM_REMOTE" "$branch"; then
echo "❌ 拉取失败"
[ "$stashed" = true ] && git stash pop
return 1
fi
# 检查是否有新提交
local behind_count=$(git rev-list --count HEAD.."$UPSTREAM_REMOTE/$branch" 2>/dev/null)
if [ "$behind_count" -eq 0 ]; then
echo "✅ 已是最新"
[ "$stashed" = true ] && git stash pop
return 0
fi
echo "📊 上游有 $behind_count 个新提交"
# 执行合并策略:优先 rebase
if git rebase "$UPSTREAM_REMOTE/$branch"; then
echo "✅ 基于上游变基成功"
else
echo "❌ 变基失败,尝试合并..."
git rebase --abort 2>/dev/null
if git merge "$UPSTREAM_REMOTE/$branch"; then
echo "✅ 合并成功"
else
echo "❌ 合并失败,存在冲突"
echo "⚠️ 请手动解决冲突后继续"
[ "$stashed" = true ] && git stash drop 2>/dev/null
return 1
fi
fi
# 恢复暂存
[ "$stashed" = true ] && git stash pop
echo "=== ✅ 同步完成 ==="
return 0
}
# ===== 主逻辑 =====
main() {
case "$1" in
"pre-push")
sync_upstream "$(git symbolic-ref --short HEAD)" "pre-push"
;;
"post-checkout")
if [ "$3" = "1" ]; then
sync_upstream "$(git symbolic-ref --short HEAD)" "post-checkout"
fi
;;
"post-merge")
if [ ! -f .git/MERGE_HEAD ]; then
sync_upstream "$(git symbolic-ref --short HEAD)" "post-merge"
fi
;;
*)
echo "Usage: $0 {pre-push|post-checkout|post-merge}"
exit 1
;;
esac
}
# 执行
main "$@"
安装和配置说明
安装钩子
#!/bin/bash
# 一键安装脚本 install-git-hooks.sh
HOOKS_DIR=".git/hooks"
SCRIPTS_DIR="scripts/git-hooks"
# 需要的钩子
HOOKS=("pre-push" "post-checkout" "post-merge")
for hook in "${HOOKS[@]}"; do
if [ -f "$SCRIPTS_DIR/$hook" ]; then
# 备份已有钩子
if [ -f "$HOOKS_DIR/$hook" ]; then
cp "$HOOKS_DIR/$hook" "$HOOKS_DIR/$hook.bak"
fi
# 安装新钩子
cp "$SCRIPTS_DIR/$hook" "$HOOKS_DIR/$hook"
chmod +x "$HOOKS_DIR/$hook"
echo "✅ 安装 $hook 钩子"
else
echo "⚠️ 未找到 $SCRIPTS_DIR/$hook"
fi
done
echo "🎉 钩子安装完成"
使用方法
- 手动执行测试:
# 测试 pre-push 钩子 bash .git/hooks/pre-push
手动触发同步
git push --dry-run
2. **临时跳过钩子**:
```bash
# 方法1:使用 --no-verify 参数
git push --no-verify
# 方法2:设置环境变量
SKIP_GIT_HOOKS=1 git push
配置上游仓库
确保已配置好上游远程仓库:
# 添加上游仓库 git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git # 或设置已有远程为上游 git remote rename origin upstream # 检查配置 git remote -v
注意事项
- 冲突处理:自动同步可能导致冲突,建议在干净的仓库上操作
- 性能影响:频繁的 fetch/rebase 会增加网络开销
- 团队协作:与团队成员沟通,确保不会干扰他人工作
- 保护分支:对重要分支建议只采用手动同步
- 日志记录:建议在脚本中添加日志功能:
exec 1>>"$HOME/.git-hooks.log" 2>&1 echo "[$(date)] 开始同步 $current_branch"
需要根据你的具体工作流程调整这些脚本,建议先在测试仓库中验证后再正式使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播