最简单可靠的方式是用 subprocess 直接调用 git pull,需显式指定 cwd、加 --ff-only、捕获 stderr;打包前用 importlib.util.cache_from_source() 清理 pyc;部署用 rsync 增量同步;定时任务交由 cron 等系统调度器管理。

用 subprocess 调用 git pull 最简单可靠
直接调用系统 git 命令比用 GitPython 更稳定,尤其在权限、SSH Agent、子模块等场景下不易出错。关键不是“用不用库”,而是控制好工作目录和错误退出。
常见错误现象:subprocess.CalledProcessError: Command 'git pull' returned non-zero exit status 1,多半是当前目录不对、远程分支名不匹配,或有未提交更改被拒绝合并。
- 必须用
cwd=显式指定仓库根目录,不能只靠os.chdir()(多线程/协程下会冲突) - 加
--ff-only参数避免意外合并提交,部署环境应禁止非快进更新 - 捕获
stderr并打印,否则失败时看不到真实报错(比如 SSH key 权限拒绝)
import subprocess
result = subprocess.run(
["git", "pull", "--ff-only"],
cwd="/var/www/myapp",
capture_output=True,
text=True
)
if result.returncode != 0:
print("Git pull failed:", result.stderr)
打包前先清理 __pycache__ 和 .pyc 文件
Python 源码更新后,旧的字节码文件可能残留,导致运行时行为不一致——特别是修改了函数签名但没清缓存时,容易静默出错。
不要依赖 python -m compileall 全量重编译,它不删旧文件;也不要用 find . -name "*.pyc" -delete 这种 shell 方式(跨平台差、权限问题多)。
- 用
importlib.util.cache_from_source()精准定位每个.py对应的缓存路径,再安全删除 - 递归扫描时跳过
.git目录,避免误删 Git 内部对象 - 打包命令建议用
tar --exclude='.git' -czf deploy.tar.gz .,别用zip(Linux 上默认不保留执行权限)
部署时用 rsync 替代 cp 或解压覆盖
直接覆盖线上目录风险高:服务进程可能正读取被删文件,导致 IOError: [Errno 2] No such file or directory;大项目解压耗时长,期间服务不可用。
rsync 的 --delete + --exclude 组合能实现原子化增量更新,且支持限速、断点续传。
- 目标路径末尾加
/(如/opt/app/)才表示同步内容,不加则会把整个目录复制进去 - 排除日志、配置、上传目录:用
--exclude='logs/' --exclude='config/local.py' --exclude='uploads/' - 加上
-avz --delete,别漏--delete,否则旧文件越积越多
定时触发别硬写 time.sleep(),走系统级调度
Python 进程常驻跑 while True: do(); time.sleep(3600) 看似简单,但进程崩溃、机器重启后就停摆,还占内存、难监控。
生产环境必须交由系统守护机制管理:Linux 用 cron,macOS 用 launchd,容器环境用 supercronic。
-
cron示例:0 * * * * cd /var/www/myapp && /usr/bin/python3 /opt/scripts/deploy.py >> /var/log/deploy.log 2>&1 - 脚本开头加
#!/usr/bin/env python3,并chmod +x,避免 cron 因 SHELL 环境缺失找不到 Python - 所有路径写绝对路径,
cron默认PWD=/root,相对路径极易失效
真正麻烦的从来不是拉代码或打包,而是环境变量隔离、数据库迁移是否已执行、新旧版本兼容性检查这些逻辑。脚本里留好钩子位置,比如 if os.path.exists('migrate.sh'): subprocess.run('./migrate.sh'),比把所有事塞进一个 Python 文件更可持续。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











