Git合并脚本需确保工作区干净、分步验证分支切换与拉取、按需选择--no-ff或--squash策略、禁止静默跳过冲突、推送前校验远端状态并保留恢复路径,且必须正确传递退出码和处理中断。

git merge 脚本必须先确保工作区干净
直接在脏工作区执行 git merge 极易失败,报错如 error: Your local changes to the following files would be overwritten by merge。这不是脚本逻辑问题,而是 Git 的强制保护机制。
实操建议:
- 每次合并前必须运行
git status --porcelain检查输出是否为空;非空则拒绝继续 - 不推荐无条件
git reset --hard && git clean -fd—— 会永久丢失未提交代码,应优先用git stash - 若检测到
stash存在,需在合并后执行git stash pop并检查冲突,不能假设自动成功 - 注意:某些 CI 环境禁用
git stash(如 shallow clone),此时应改用临时 commit +git reset --soft HEAD~1回退
目标分支切换与拉取要分步验证
常见错误是把 git checkout master && git pull 写成单条命令,一旦 checkout 失败(比如分支不存在),pull 仍会执行,导致操作对象错乱。
实操建议:
- 先用
git show-ref refs/heads/$target_branch或git ls-remote --heads origin $target_branch验证远端分支存在 -
git checkout $target_branch后立即执行git rev-parse --abbrev-ref HEAD,比对输出是否等于预期分支名 -
git pull origin $target_branch必须加--ff-only参数(除非明确接受 merge commit),否则可能意外创建本地 merge 提交 - 拉取后检查
git diff origin/$target_branch是否为空,确认本地已完全同步
合并策略选 --no-ff 还是 --squash 取决于协作规范
脚本里硬编码一种策略会导致团队流程断裂。git merge --no-ff 保留完整分支拓扑,适合功能追踪;git merge --squash 生成单个 commit,适合发布集成,但会丢失原始作者和时间戳。
实操建议:
- 通过参数控制:
./merge.sh feature/login --squash或./merge.sh feature/login --no-ff -
--squash后必须手动git commit,脚本需提供默认提交信息模板(如"Squash merge of $source_branch"),并支持传入-m覆盖 - 若使用
--no-ff,需检查当前分支是否已是目标分支的直接祖先(用git merge-base --is-ancestor),避免无意义的 fast-forward - 禁止在脚本中静默跳过冲突:一旦
git merge返回非 0,必须中止并提示用户手动处理,不能尝试git merge --abort后重试
推送失败后不能简单 exit,要留出恢复路径
git push origin $target_branch 失败原因多样:权限不足、pre-receive hook 拒绝、远端有新提交。脚本如果直接退出,用户会卡在“已合并未推送”状态,极易引发重复合并。
实操建议:
- 推送前先做
git fetch origin $target_branch,再用git rev-list --count HEAD ^origin/$target_branch确认本地是否领先远端 - 若发现远端有新提交(计数为 0),应提示
"远端 $target_branch 已有新提交,请先 git pull --rebase",而非强制覆盖 - 推送失败时,记录当前 HEAD 和 MERGE_HEAD 到临时文件(如
.merge-state.json),方便用户后续git merge --continue或git merge --abort - 所有关键操作(checkout / merge / push)前后都应保存
git log -n 3 --oneline快照,用于事后审计
git 命令后没加 || return $?,导致上游错误被吞掉;还有就是没处理 Ctrl+C 中断,留下半合并的 index.lock 文件。这些细节不显眼,但会让运维同学深夜排查两小时。


















