# git-deploy **Repository Path**: goodbugood/git-deploy ## Basic Information - **Project Name**: git-deploy - **Description**: git 部署上线代码脚本 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-10 - **Last Updated**: 2025-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 部署脚本使用手册 ## 概述 `deploy.sh` 是一个基于原子分支切换技术的零停机部署和回滚工具,支持线上代码的安全上线和紧急下线操作。脚本采用创新的 `git fetch origin master:master` 原子更新方案,彻底解决了传统 git pull 过程中的文件不一致问题,并集成了智能的 Composer 依赖检测功能。 ## 核心特性 ### ✨ **零停机部署** - 使用原子分支切换技术,切换过程在毫秒级完成 - 避免传统 git pull 过程中的文件不一致问题 - 网络中断不影响当前运行的服务 ### 🔍 **智能依赖检测** - 自动检测 composer.lock 文件的内容变化 - 基于文件内容(MD5)比较,而非时间窗口 - 支持上线和回滚场景的依赖变化检测 ### 🛡️ **全面安全机制** - 多层确认机制,防止误操作 - 完整的错误回滚机制 - 详细的操作日志记录 ## 使用方法 ### 基本语法 ```bash ./deploy.sh [on|off] ``` ### 参数说明 - `on` - 上线操作,更新线上代码到最新版本 - `off` - 下线操作,回滚代码到上一个提交版本 - `help` - 显示帮助信息 ## 技术原理详解 ### 原子分支切换技术 #### 传统 git pull 的问题 ```bash # 传统方式的问题 git pull origin master # 问题:pull 过程中文件逐个更新,服务可能读取到不完整的代码 ``` #### 我们的原子切换方案 ```bash # 1. 切换到临时分支(保护当前服务状态) git checkout -b deploy-temp-20241201_143022 # 2. 后台更新主分支(不影响工作区文件) git fetch origin master:master # 3. 原子切换回主分支(毫秒级完成) git checkout master # 4. 清理临时分支 git branch -D deploy-temp-20241201_143022 ``` **关键优势**:`git fetch origin master:master` 只更新本地分支引用,不改变工作区文件,后续的 `git checkout` 是原子操作。 ### 智能依赖检测机制 #### 检测原理 不再依赖时间窗口(如1分钟内),而是比较切换前后的 `composer.lock` 状态: ```bash # 切换前记录状态 BEFORE_MD5=$(md5sum composer.lock | cut -d' ' -f1) BEFORE_MTIME=$(stat -c %Y composer.lock) # 执行代码切换... # 切换后比较状态 AFTER_MD5=$(md5sum composer.lock | cut -d' ' -f1) AFTER_MTIME=$(stat -c %Y composer.lock) # 智能判断是否需要更新依赖 if [[ "$BEFORE_MD5" != "$AFTER_MD5" ]]; then # 内容真正发生变化,提醒更新依赖 fi ``` #### 检测场景覆盖 | 场景 | 检测结果 | 处理方式 | |------|----------|----------| | 正常上线,依赖有更新 | ✅ 检测到变化 | 提醒执行 composer install | | 正常上线,依赖无更新 | ❌ 无变化 | 跳过依赖安装 | | 回滚操作,依赖需要降级 | ✅ 检测到变化 | 提醒执行 composer install | | 仅时间戳变化,内容相同 | ❌ 无实际变化 | 跳过依赖安装 | ### 上线操作流程 (`./deploy.sh on`) #### 第一步:环境检查 ``` 检查当前目录是否为 git 仓库 ├── 成功 → 继续执行 └── 失败 → 报错退出 ``` **必要性**:确保脚本在正确的代码仓库中运行,避免在错误目录执行部署操作。 #### 第二步:分支状态检查 ``` 获取当前分支和主分支信息 ├── 当前分支 = 主分支 → 执行正常上线流程 └── 当前分支 ≠ 主分支 → 执行回滚后上线流程 ``` **必要性**:识别是否有人执行过回滚操作,防止在回滚状态下直接上线导致代码版本混乱。 #### 第三步:原子切换上线流程 ``` 当前在主分支(master/main) ├── 记录切换前 composer.lock 状态 ├── 创建临时分支并切换:git checkout -b deploy-temp-xxx ├── 后台更新主分支:git fetch origin master:master ├── 原子切换回主分支:git checkout master ├── 清理临时分支:git branch -D deploy-temp-xxx ├── 检查 composer.lock 变化并处理依赖更新 └── 提示重启服务 ``` **必要性**: - **状态记录**:为智能依赖检测做准备 - **临时分支保护**:确保切换过程中服务不中断 - **后台更新**:`git fetch origin master:master` 只更新分支引用,不影响工作区 - **原子切换**:`git checkout` 毫秒级完成,真正零停机 - **依赖智能检测**:自动处理 Composer 依赖变化 #### 第四步:回滚后上线流程 ``` 检测到当前不在主分支(处于回滚状态) ├── 显示警告信息:"有人回滚了代码,不可以上线,请与他沟通" ├── 要求用户确认 │ ├── 用户取消 → 脚本退出 │ └── 用户确认 → 继续执行 ├── 记录切换前 composer.lock 状态 ├── 后台更新主分支:git fetch origin master:master ├── 原子切换到主分支:git checkout master ├── 检查 composer.lock 变化并处理依赖更新 └── 提示重启服务 ``` **必要性**: - **警告机制**:防止多人协作时的代码冲突,强制沟通确认 - **手动确认**:避免自动覆盖回滚状态,给操作者最后的决定权 - **原子更新**:回滚状态下也使用相同的原子切换技术 - **统一体验**:两种场景使用相同的安全机制 ### 下线操作流程 (`./deploy.sh off`) #### 第一步:环境检查 ``` 检查当前目录是否为 git 仓库 ├── 成功 → 继续执行 └── 失败 → 报错退出 ``` #### 第二步:获取版本信息 ``` 获取提交历史 ├── 当前提交:git rev-parse HEAD ├── 当前提交信息:git log -1 --pretty=format:"%s" HEAD ├── 上一个提交:git rev-parse HEAD~1 └── 上一个提交信息:git log -1 --pretty=format:"%s" HEAD~1 ``` **必要性**:让操作者清楚了解即将回滚的版本信息,避免回滚到错误版本。 #### 第三步:版本确认 ``` 显示版本对比信息 ┌─────────────────────────────────────┐ │ 当前版本:[commit_id] [commit_msg] │ │ 回滚目标:[commit_id] [commit_msg] │ └─────────────────────────────────────┘ ├── 要求用户确认 │ ├── 用户取消 → 脚本退出 │ └── 用户确认 → 继续执行 ``` **必要性**: - **版本透明化**:让操作者明确知道回滚的影响范围 - **二次确认**:防止误操作导致的线上故障 #### 第四步:工作区安全检查 ``` 检查是否有未提交的更改 ├── 工作区干净 → 直接回滚 └── 有未提交更改 → 再次确认 ├── 用户取消 → 脚本退出 └── 用户确认 → 继续回滚(数据将丢失) ``` **必要性**:保护本地开发工作,防止重要更改丢失。 #### 第五步:执行回滚 ``` 执行回滚操作 ├── 记录回滚前 composer.lock 状态 ├── git checkout [上一个提交ID] │ ├── 成功 → 继续检查依赖 │ └── 失败 → 报错退出 ├── 检查 composer.lock 变化并处理依赖更新 └── 提示重启服务 ``` **新增功能**: - **智能依赖检测**:回滚后自动检测依赖是否需要降级安装 - **完整回滚体验**:确保代码和依赖都回滚到一致状态 ## 日志系统 ### 日志文件 - **文件名**:`deploy.log` - **位置**:脚本执行目录 - **格式**:`[YYYY-MM-DD HH:MM:SS] 日志内容` ### 日志内容 ``` [2024-01-01 10:00:00] ========================================= [2024-01-01 10:00:01] 部署脚本开始执行,参数: on [2024-01-01 10:00:01] 执行用户: www-data [2024-01-01 10:00:01] 执行目录: /var/www/html [2024-01-01 10:00:01] ========================================= [2024-01-01 10:00:02] 开始执行上线操作 [2024-01-01 10:00:02] 当前分支: master [2024-01-01 10:00:02] 主分支: master [2024-01-01 10:00:03] 在主分支,开始拉取最新代码 [2024-01-01 10:00:05] 代码拉取完成 [2024-01-01 10:00:05] 上线操作执行完毕 [2024-01-01 10:00:05] ========================================= [2024-01-01 10:00:05] 部署脚本执行完成 [2024-01-01 10:00:05] ========================================= ``` ### 日志用途 1. **操作审计**:追踪谁在什么时候执行了什么操作 2. **问题排查**:当部署出现问题时,快速定位失败原因 3. **合规要求**:满足线上操作的日志记录要求 ## 安全机制 ### 1. 分支保护 - 自动识别主分支(master/main) - 防止在错误分支进行部署 - 强制确认回滚后的上线操作 ### 2. 数据保护 - 检查工作区状态,防止未提交更改丢失 - 多层确认机制,防止误操作 - 详细的版本信息展示 ### 3. 操作日志 - 完整记录所有操作步骤 - 包含用户信息和时间戳 - 便于后续审计和排查 ### 4. 错误处理 - 每一步都有错误检查 - 失败时立即停止执行 - 提供清晰的错误信息 ## 使用场景 ### 场景一:正常发版上线 ```bash # 开发完成,代码已合并到master分支 ./deploy.sh on # 输出示例: # [2024-01-01 14:30:22] 开始原子分支切换部署 # [2024-01-01 14:30:23] 记录切换前 composer.lock 状态: mtime=1701234567, md5=abc12345... # [2024-01-01 14:30:24] 后台更新主分支代码(不影响当前工作区) # [2024-01-01 14:30:26] 原子切换到更新后的主分支 # [2024-01-01 14:30:26] 原子分支切换部署完成 # ⚠️ 检测到 Composer 依赖变化 # 原因: composer.lock 文件内容发生变化 # 是否现在执行 composer install --no-dev?y # ✅ Composer 依赖安装完成 # ✅ 服务器代码已更新,请重启后台常驻进程和 queue:listen ``` ### 场景二:发现线上问题,紧急回滚 ```bash # 紧急回滚到上一个版本 ./deploy.sh off # 输出示例: # 当前提交: abc123def456 # 当前提交信息: fix: 修复支付异常问题 # # 即将回滚到上一个提交: # 提交ID: def456abc789 # 提交信息: feat: 新增用户权限管理 # # 请输入 y 确认,其他任意键取消: y # [2024-01-01 15:10:30] 记录回滚前 composer.lock 状态 # ⚠️ 检测到 Composer 依赖变化 # 原因: composer.lock 文件内容发生变化 # 切换前修改时间: 2024-01-01 14:25:33 # 切换后修改时间: 2024-01-01 10:30:22 ← 回滚到旧时间 # 是否现在执行 composer install --no-dev?y # ✅ Composer 依赖安装完成 # ✅ 代码已回滚到上一个提交 ``` ### 场景三:回滚后重新上线 ```bash # 问题修复后,重新上线 ./deploy.sh on # 输出示例: # WARNING: 当前不在主分支,可能有人回滚了代码 # 有人回滚了代码,不可以上线,请与他沟通。如果他确认了,请输入 y 继续: y # [2024-01-01 15:30:45] 记录切换前 composer.lock 状态 # [2024-01-01 15:30:46] 后台更新主分支代码(不影响当前工作区) # [2024-01-01 15:30:48] 原子切换到更新后的主分支 # ⚠️ 检测到 Composer 依赖变化 # ✅ 服务器代码已更新,请重启后台常驻进程和 queue:listen ``` ### 场景四:无依赖变化的上线 ```bash # 仅代码更新,依赖无变化 ./deploy.sh on # 输出示例: # [2024-01-01 16:20:15] composer.lock 文件无需更新依赖 # ✅ 服务器代码已更新,请重启后台常驻进程和 queue:listen ``` ## 注意事项 ### 1. 执行前准备 - 确保脚本有执行权限:`chmod +x deploy.sh` - 确保服务器有 git 命令和仓库访问权限 - 确保当前用户有文件写入权限(用于日志记录) ### 2. 网络要求 - 服务器能访问 git 远程仓库 - 网络稳定,避免 git pull 过程中断 ### 3. 权限管理 - 建议只有运维人员和项目负责人有脚本执行权限 - 定期检查 deploy.log,监控部署操作 ### 4. 服务重启 - 脚本完成后,务必按提示重启相关服务: - 后台常驻进程(daemon进程) - 队列监听进程(queue:listen) - Web服务器(如nginx、apache) - PHP-FPM(如果使用) ### 5. 备份建议 - 重要发版前建议创建数据库备份 - 保留近期的 deploy.log 文件 - 关键配置文件的版本管理 ## 故障排除 ### 常见问题 #### 1. git pull 失败 **现象**:拉取代码时提示权限不足或网络错误 **解决**: - 检查 git 配置和 SSH 密钥 - 检查网络连接 - 确认仓库访问权限 #### 2. 工作区不干净 **现象**:提示有未提交的更改 **解决**: - 查看具体更改:`git status` - 提交更改:`git add . && git commit -m "message"` - 或储藏更改:`git stash` #### 3. 分支切换失败 **现象**:无法切换到主分支 **解决**: - 检查分支是否存在:`git branch -a` - 手动切换:`git checkout master` 或 `git checkout main` #### 4. 权限问题 **现象**:脚本无法执行或写入日志失败 **解决**: - 添加执行权限:`chmod +x deploy.sh` - 检查目录写入权限:`ls -la` ### 紧急恢复 如果脚本执行过程中出现严重问题: 1. **立即停止**:`Ctrl+C` 中断脚本执行 2. **查看状态**:`git status` 和 `git log --oneline -10` 3. **手动恢复**:根据 deploy.log 和 git 状态手动恢复 4. **联系团队**:通知相关开发人员协助处理 ## 最佳实践 ### 部署前准备 1. **团队沟通**:重要发版前通知团队成员,避免冲突操作 2. **依赖检查**:关注 composer.json 和 composer.lock 的变化 3. **错峰部署**:避免在业务高峰期进行部署操作 4. **备份确认**:重要数据库变更前确保有完整备份 ### 部署过程管控 1. **渐进发布**:重要功能可考虑灰度发布或蓝绿部署 2. **监控观察**:部署后密切关注系统监控、错误日志和业务指标 3. **服务重启**:按脚本提示及时重启相关服务进程 4. **功能验证**:部署完成后进行关键功能的快速验证 ### 异常处理 1. **回滚决策**:发现问题时优先使用脚本快速回滚,而非修复 2. **日志分析**:充分利用 deploy.log 进行问题排查 3. **依赖一致性**:回滚后注意检查依赖版本是否需要同步回滚 4. **团队协作**:回滚操作完成后及时通知相关人员 ### 性能优化建议 1. **网络优化**:确保服务器到 Git 仓库的网络连接稳定 2. **磁盘空间**:定期清理 Git 仓库和 Composer 缓存 3. **权限管理**:合理设置文件权限,避免权限问题影响部署 4. **进程管理**:使用进程管理工具(如 Supervisor)管理后台进程 ## 与传统方案对比 | 特性 | 传统 git pull | 蓝绿部署 | 我们的原子切换 | |------|---------------|----------|----------------| | **停机时间** | 秒级中断 | 零停机 | 零停机 | | **资源消耗** | 最少 | 双倍资源 | 最少 | | **实现复杂度** | 简单 | 复杂 | 简单 | | **网络容错性** | 差 | 好 | 优秀 | | **依赖管理** | 手动 | 需额外设计 | 自动检测 | | **回滚速度** | 慢 | 快 | 快 | | **学习成本** | 低 | 高 | 低 | ## 总结 本部署脚本通过创新的原子分支切换技术和智能依赖检测机制,在保持简单易用的同时,实现了企业级的零停机部署能力。相比传统方案,具有以下显著优势: - ✅ **真正零停机**:毫秒级原子切换,消除服务中断 - ✅ **智能自动化**:自动检测并处理依赖变化 - ✅ **网络容错强**:网络中断不影响当前服务 - ✅ **资源消耗低**:无需额外服务器资源 - ✅ **操作简单**:一键部署,一键回滚 - ✅ **安全可靠**:多重保护机制,完整错误处理 通过遵循本手册的指导,团队可以安全、高效地执行代码部署和回滚操作,最大化保障线上系统的稳定性和可用性。