如何通过Bash脚本在同一虚拟环境中同时运行Python包的稳定版与开发版(共享数据目录)
我完全懂你的需求:在同一个工作目录里用同一个虚拟环境跑稳定版和开发版,共享data/目录,还不想因为来回切换Git分支搞得手忙脚乱。你已经摸到了正确的方向——把稳定版源码复制到Git忽略的目录,再修改sys.path优先加载它,但卡在了两个关键问题上:PYTHONSTARTUP完全没起作用,而且Git分支切换后VSCode的状态识别也出了问题。咱们一步步来解决:
先搞懂为什么PYTHONSTARTUP没用
你踩了一个很容易忽略的坑:PYTHONSTARTUP环境变量指定的脚本只在交互式Python会话启动时才会执行(比如你直接敲python3进入命令行的时候)。但当你用python3 -m mypackage这种非交互式方式运行模块时,Python根本不会去读这个脚本,所以你的sys.path修改完全没生效。
替换掉麻烦的Git checkout逻辑
你原来的脚本需要切换到稳定版标签再切回开发分支,不仅要检查未提交文件,还会导致VSCode的Git状态识别异常(因为VSCode可能缓存了分支信息,即使切回原分支也没及时刷新)。其实咱们根本不用切换分支——用git archive就能直接导出指定标签的源码,完全不干扰当前工作区:
git archive可以把仓库里指定版本(标签/提交)的某个目录直接导出到目标路径,不需要修改当前的工作区或分支状态,完美解决你的Git相关问题。
最终的run-stable.sh脚本(带完整注释)
把原来的脚本替换成下面这个版本,我会在注释里解释每一步的作用:
#!/usr/bin/bash # 切换到项目根目录并激活虚拟环境,失败则退出 PROJECT_ROOT="$HOME/path/to/mypackage" cd "$PROJECT_ROOT" || { echo "无法进入项目根目录" >&2; exit 1; } . venv/bin/activate || { echo "无法激活虚拟环境" >&2; exit 1; } # 定义要使用的稳定版标签 LATEST_STABLE="0.4.1" # 读取已构建的稳定版版本号(如果文件存在) CURRENT_BUILD_VER=$(cat build/stable.version 2>/dev/null) # 如果已构建的版本和目标版本不一致,重新构建 if [[ "$CURRENT_BUILD_VER" != "$LATEST_STABLE" ]]; then # 创建稳定版构建目录(如果不存在) mkdir -p build/stable # 导出指定标签的src/mypackage目录到build/stable/,自动去掉src前缀 git archive "v$LATEST_STABLE" src/mypackage | tar -x -C build/stable/ --strip-components=1 # 记录当前构建的版本号 echo "$LATEST_STABLE" > build/stable.version echo "已更新稳定版构建:$CURRENT_BUILD_VER -> $LATEST_STABLE" fi # 动态生成Python启动脚本,先修改sys.path再运行包 python3 <(cat << 'EOF' import sys import os # 获取项目根目录(和Bash脚本里的PROJECT_ROOT一致) PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) # 移除src/目录的路径(确保不会加载开发版代码) SRC_PATH = os.path.join(PROJECT_ROOT, 'src') while SRC_PATH in sys.path: sys.path.remove(SRC_PATH) # 把稳定版源码目录加到sys.path的最前面 STABLE_SRC_PATH = os.path.join(PROJECT_ROOT, 'build', 'stable') sys.path.insert(0, STABLE_SRC_PATH) # 运行你的包的__main__模块(和python -m mypackage效果一致) from mypackage.__main__ import main main() EOF ) "$@"
关键细节说明
Git archive的优势:
- 不需要切换分支,完全不影响当前的工作区,也不用检查未提交文件
- 直接导出标签对应的源码,确保稳定版的代码是完全符合标签的,没有任何本地修改
sys.path修改的可靠性:
- 用动态生成的Python启动脚本,在加载你的包之前就修改
sys.path,完全避开了PYTHONSTARTUP的局限性 - 循环移除
src/的路径,确保即使虚拟环境里因为pip install -e添加了这个路径,也会被彻底移除 - 把稳定版的路径插在
sys.path最前面,确保Python优先加载稳定版的代码
- 用动态生成的Python启动脚本,在加载你的包之前就修改
参数传递:
- 脚本最后用
"$@"把命令行参数传递给你的Python包,和原来的run.sh的参数行为保持一致
- 脚本最后用
验证方法
你可以在启动脚本里加一行打印sys.path的代码,确认路径是否正确:
print("当前sys.path顺序:", sys.path)
运行run-stable.sh后,应该能看到build/stable/在最前面,src/不在列表里。
备注:内容来源于stack exchange,提问作者sakuragasaki46




