调用os.system命令后Python代码仅处理首个Git仓库即停止的问题
解决Git批量推送脚本仅处理第一个仓库的问题
问题根源
你的代码中使用os.chdir()修改了进程的全局工作目录,处理第一个Git仓库后,当前工作目录切换到该仓库根目录,导致后续os.walk()基于新的工作目录继续遍历,无法找到初始路径下的其他仓库。即使使用线程,线程共享进程的工作目录,第一个线程的os.chdir()操作仍会干扰主线程的遍历逻辑。
解决方案核心
不修改全局工作目录,而是在执行Git命令时直接指定仓库路径。可以通过Git的-C参数指定工作目录,或使用subprocess模块的cwd参数实现。
方案1:基于os.system的修改版本
import os import threading def push_repository(repo_path): try: # 使用git -C参数指定仓库路径,无需切换全局工作目录 os.system(f'git -C "{repo_path}" add *') # 捕获commit输出,避免无修改时的报错中断流程 commit_output = os.popen(f'git -C "{repo_path}" commit -m "Automated commit"').read() print(f"{repo_path} 提交结果:\n{commit_output}") push_output = os.popen(f'git -C "{repo_path}" push').read() print(f"{repo_path} 推送结果:\n{push_output}") except Exception as e: print(f"{repo_path} 处理出错: {str(e)}") def commit_and_push_git_folders(path): for root, dirs, files in os.walk(path): if '.git' in dirs: print(f"找到仓库: {os.path.join(root, '.git')}") # 仓库根目录即为当前root路径 t = threading.Thread(target=push_repository, args=(root,)) t.start() # 移除.git目录,避免遍历其内部文件,提升效率 dirs.remove('.git') commit_and_push_git_folders('.')
方案2:更健壮的subprocess版本(推荐)
subprocess模块比os.system更灵活,能更好地处理命令输出和错误:
import os import threading import subprocess def push_repository(repo_path): try: # 执行git add操作 add_result = subprocess.run( ['git', '-C', repo_path, 'add', '*'], capture_output=True, text=True ) if add_result.returncode != 0: print(f"{repo_path} 添加文件失败: {add_result.stderr.strip()}") return # 执行git commit,无修改时返回非0属于正常情况 commit_result = subprocess.run( ['git', '-C', repo_path, 'commit', '-m', 'Automated commit'], capture_output=True, text=True ) if commit_result.returncode == 0: print(f"{repo_path} 提交成功:\n{commit_result.stdout.strip()}") else: print(f"{repo_path} 无修改可提交:\n{commit_result.stderr.strip()}") # 执行git push操作 push_result = subprocess.run( ['git', '-C', repo_path, 'push'], capture_output=True, text=True ) if push_result.returncode == 0: print(f"{repo_path} 推送成功:\n{push_result.stdout.strip()}") else: print(f"{repo_path} 推送失败:\n{push_result.stderr.strip()}") except Exception as e: print(f"{repo_path} 处理异常: {str(e)}") def commit_and_push_git_folders(path): for root, dirs, files in os.walk(path): if '.git' in dirs: print(f"找到仓库: {os.path.join(root, '.git')}") t = threading.Thread(target=push_repository, args=(root,)) t.start() dirs.remove('.git') commit_and_push_git_folders('.')
关键改进点
- 移除
os.chdir()操作,改用git -C <仓库路径>指定命令执行的工作目录,不影响全局进程状态。 - 在
os.walk中移除.git目录,避免遍历其内部文件,提升遍历效率。 - 增强错误处理,捕获命令执行的输出,方便排查问题。
内容的提问来源于stack exchange,提问作者Alexander Shestak
相关产品推荐
相关产品推荐

