commit c51237969c4c3afcd8613311b4a9ec54aeb90206 Author: 树萌芽 <3205788256@qq.com> Date: Sat Feb 14 00:53:29 2026 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7503322 --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +# Node/React +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +build/ +dist/ +coverage/ +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Go +*.exe +*.exe~ +*.test +*.out +*.dll +*.so +*.dylib +vendor/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +*.egg-info/ +dist/ +build/ + +# 数据文件 +data/data.json +*.db +*.sqlite + +# 日志文件 +*.log +logs/ + +# 操作系统 +.DS_Store +Thumbs.db +desktop.ini + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ +.project +.classpath +.settings/ + +# 其他 +*.bak +*.tmp +*.temp diff --git a/mengya_git_manager.py b/mengya_git_manager.py new file mode 100644 index 0000000..50dbf77 --- /dev/null +++ b/mengya_git_manager.py @@ -0,0 +1,561 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +萌芽一键Git管理工具 +支持快速初始化Git仓库、提交更改、推送到GitHub和Gitea +""" + +import os +import sys +import subprocess +from typing import Optional, List + + +class Colors: + """控制台颜色""" + HEADER = '\033[95m' + BLUE = '\033[94m' + CYAN = '\033[96m' + GREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + + +class GitManager: + """Git管理器""" + + def __init__(self): + self.gitea_host = "repo.shumengya.top" + self.gitea_port = "8022" + self.github_user = "shumengya" + self.current_dir = os.getcwd() + + def print_header(self, text: str): + """打印标题""" + print(f"\n{Colors.HEADER}{Colors.BOLD}{'='*50}") + print(f" {text}") + print(f"{'='*50}{Colors.ENDC}\n") + + def print_success(self, text: str): + """打印成功信息""" + print(f"{Colors.GREEN}✓ {text}{Colors.ENDC}") + + def print_error(self, text: str): + """打印错误信息""" + print(f"{Colors.FAIL}✗ {text}{Colors.ENDC}") + + def print_info(self, text: str): + """打印提示信息""" + print(f"{Colors.CYAN}ℹ {text}{Colors.ENDC}") + + def print_warning(self, text: str): + """打印警告信息""" + print(f"{Colors.WARNING}⚠ {text}{Colors.ENDC}") + + def run_command(self, command: str, show_output: bool = True) -> tuple[bool, str]: + """ + 执行命令 + 返回: (是否成功, 输出内容) + """ + try: + result = subprocess.run( + command, + shell=True, + capture_output=True, + text=True, + encoding='utf-8', + errors='ignore' + ) + + output = result.stdout + result.stderr + + if show_output and output.strip(): + print(output) + + return result.returncode == 0, output + except Exception as e: + self.print_error(f"命令执行失败: {str(e)}") + return False, str(e) + + def is_git_repo(self) -> bool: + """检查当前目录是否是Git仓库""" + return os.path.isdir('.git') + + def get_gitignore_template(self) -> str: + """获取.gitignore模板""" + return """# Node/React +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +build/ +dist/ +coverage/ +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Go +*.exe +*.exe~ +*.test +*.out +*.dll +*.so +*.dylib +vendor/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +*.egg-info/ +dist/ +build/ + +# 数据文件 +data/data.json +*.db +*.sqlite + +# 日志文件 +*.log +logs/ + +# 操作系统 +.DS_Store +Thumbs.db +desktop.ini + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ +.project +.classpath +.settings/ + +# 其他 +*.bak +*.tmp +*.temp +""" + + def init_git_repo(self): + """初始化Git仓库""" + self.print_header("初始化Git仓库") + + if self.is_git_repo(): + self.print_warning("当前目录已经是Git仓库") + return True + + # 1. 初始化Git仓库 + self.print_info("正在初始化Git仓库...") + success, _ = self.run_command("git init", show_output=False) + if not success: + self.print_error("Git初始化失败") + return False + self.print_success("Git仓库初始化成功") + + # 2. 创建main分支 + self.print_info("正在创建main分支...") + success, _ = self.run_command("git checkout -b main", show_output=False) + if success: + self.print_success("main分支创建成功") + else: + self.print_warning("main分支创建失败,将使用默认分支") + + # 3. 创建.gitignore文件 + self.print_info("正在创建.gitignore文件...") + try: + with open('.gitignore', 'w', encoding='utf-8') as f: + f.write(self.get_gitignore_template()) + self.print_success(".gitignore文件创建成功") + except Exception as e: + self.print_error(f".gitignore文件创建失败: {str(e)}") + + # 4. 首次提交 + self.print_info("正在进行首次提交...") + self.run_command("git add .", show_output=False) + success, _ = self.run_command('git commit -m "first commit"', show_output=False) + if success: + self.print_success("首次提交完成") + else: + self.print_warning("首次提交失败(可能没有文件可提交)") + + # 5. 配置远程仓库 + self.configure_remotes() + + return True + + def configure_remotes(self): + """配置远程仓库""" + self.print_info("\n配置远程仓库...") + + print("\n请选择要配置的远程仓库:") + print("1. GitHub") + print("2. Gitea") + print("3. 两者都配置") + print("4. 跳过") + + choice = input("\n请选择 [1-4]: ").strip() + + if choice == '1': + self.add_github_remote() + elif choice == '2': + self.add_gitea_remote() + elif choice == '3': + self.add_github_remote() + self.add_gitea_remote() + else: + self.print_info("跳过远程仓库配置") + + def add_github_remote(self): + """添加GitHub远程仓库""" + repo_name = input(f"\n请输入GitHub仓库名: ").strip() + if not repo_name: + self.print_warning("仓库名不能为空,跳过GitHub配置") + return + + remote_url = f"git@github.com:{self.github_user}/{repo_name}.git" + + # 检查remote是否已存在 + success, output = self.run_command("git remote", show_output=False) + if "github" in output: + self.run_command("git remote remove github", show_output=False) + + success, _ = self.run_command(f'git remote add github {remote_url}', show_output=False) + if success: + self.print_success(f"GitHub远程仓库已添加: {remote_url}") + else: + self.print_error("GitHub远程仓库添加失败") + + def add_gitea_remote(self): + """添加Gitea远程仓库""" + user = input(f"\n请输入Gitea用户名: ").strip() + if not user: + self.print_warning("用户名不能为空,跳过Gitea配置") + return + + repo_name = input(f"请输入Gitea仓库名: ").strip() + if not repo_name: + self.print_warning("仓库名不能为空,跳过Gitea配置") + return + + remote_url = f"ssh://git@{self.gitea_host}:{self.gitea_port}/{user}/{repo_name}.git" + + # 检查remote是否已存在 + success, output = self.run_command("git remote", show_output=False) + if "gitea" in output: + self.run_command("git remote remove gitea", show_output=False) + + success, _ = self.run_command(f'git remote add gitea {remote_url}', show_output=False) + if success: + self.print_success(f"Gitea远程仓库已添加: {remote_url}") + else: + self.print_error("Gitea远程仓库添加失败") + + def commit_and_push(self): + """提交并推送更改""" + self.print_header("提交并推送更改") + + if not self.is_git_repo(): + self.print_error("当前目录不是Git仓库,请先初始化") + return False + + # 1. 检查是否有更改 + self.print_info("检查文件更改...") + success, output = self.run_command("git status --short", show_output=False) + + if not output.strip(): + self.print_warning("没有文件更改,无需提交") + return True + + print("\n当前更改的文件:") + print(output) + + # 2. 输入提交信息 + commit_msg = input("\n请输入提交信息 (直接回车使用默认信息): ").strip() + if not commit_msg: + from datetime import datetime + commit_msg = f"update: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" + + # 3. 添加所有更改 + self.print_info("正在添加文件...") + success, _ = self.run_command("git add .", show_output=False) + if not success: + self.print_error("添加文件失败") + return False + self.print_success("文件添加成功") + + # 4. 提交更改 + self.print_info("正在提交更改...") + success, _ = self.run_command(f'git commit -m "{commit_msg}"', show_output=True) + if not success: + self.print_error("提交失败") + return False + self.print_success("提交成功") + + # 5. 推送到远程仓库 + self.push_to_remote() + + return True + + def push_to_remote(self): + """推送到远程仓库""" + # 获取当前分支 + success, branch = self.run_command("git branch --show-current", show_output=False) + if not success or not branch.strip(): + branch = "main" + else: + branch = branch.strip() + + # 获取所有远程仓库 + success, output = self.run_command("git remote", show_output=False) + if not success or not output.strip(): + self.print_warning("没有配置远程仓库") + return + + remotes = [r.strip() for r in output.strip().split('\n') if r.strip()] + + if not remotes: + self.print_warning("没有配置远程仓库") + return + + print("\n可用的远程仓库:") + for idx, remote in enumerate(remotes, 1): + print(f"{idx}. {remote}") + print(f"{len(remotes) + 1}. 全部推送") + + choice = input(f"\n请选择要推送的远程仓库 [1-{len(remotes) + 1}]: ").strip() + + try: + choice_idx = int(choice) + if choice_idx == len(remotes) + 1: + # 推送到所有远程仓库 + for remote in remotes: + self.push_to_specific_remote(remote, branch) + elif 1 <= choice_idx <= len(remotes): + # 推送到指定远程仓库 + remote = remotes[choice_idx - 1] + self.push_to_specific_remote(remote, branch) + else: + self.print_error("无效的选择") + except ValueError: + self.print_error("无效的输入") + + def push_to_specific_remote(self, remote: str, branch: str): + """推送到指定远程仓库""" + self.print_info(f"正在推送到 {remote}...") + + # 检查是否需要设置上游分支 + success, _ = self.run_command(f"git push {remote} {branch}", show_output=True) + + if not success: + # 尝试设置上游分支 + self.print_info(f"尝试设置上游分支...") + success, _ = self.run_command(f"git push -u {remote} {branch}", show_output=True) + + if success: + self.print_success(f"成功推送到 {remote}") + else: + self.print_error(f"推送到 {remote} 失败") + + def pull_from_remote(self): + """从远程仓库拉取""" + self.print_header("从远程仓库拉取") + + if not self.is_git_repo(): + self.print_error("当前目录不是Git仓库") + return False + + # 获取所有远程仓库 + success, output = self.run_command("git remote", show_output=False) + if not success or not output.strip(): + self.print_warning("没有配置远程仓库") + return False + + remotes = [r.strip() for r in output.strip().split('\n') if r.strip()] + + if not remotes: + self.print_warning("没有配置远程仓库") + return False + + print("\n可用的远程仓库:") + for idx, remote in enumerate(remotes, 1): + print(f"{idx}. {remote}") + + choice = input(f"\n请选择要拉取的远程仓库 [1-{len(remotes)}]: ").strip() + + try: + choice_idx = int(choice) + if 1 <= choice_idx <= len(remotes): + remote = remotes[choice_idx - 1] + + # 获取当前分支 + success, branch = self.run_command("git branch --show-current", show_output=False) + if not success or not branch.strip(): + branch = "main" + else: + branch = branch.strip() + + self.print_info(f"正在从 {remote} 拉取 {branch} 分支...") + success, _ = self.run_command(f"git pull {remote} {branch}", show_output=True) + + if success: + self.print_success(f"成功从 {remote} 拉取更新") + else: + self.print_error(f"从 {remote} 拉取失败") + else: + self.print_error("无效的选择") + except ValueError: + self.print_error("无效的输入") + + def show_status(self): + """显示仓库状态""" + self.print_header("仓库状态") + + if not self.is_git_repo(): + self.print_error("当前目录不是Git仓库") + return + + print(f"{Colors.CYAN}当前目录:{Colors.ENDC} {self.current_dir}\n") + + # Git状态 + self.print_info("Git状态:") + self.run_command("git status", show_output=True) + + # 远程仓库 + print(f"\n{Colors.CYAN}远程仓库:{Colors.ENDC}") + self.run_command("git remote -v", show_output=True) + + # 最近提交 + print(f"\n{Colors.CYAN}最近3次提交:{Colors.ENDC}") + self.run_command("git log --oneline -3", show_output=True) + + def manage_remotes(self): + """管理远程仓库""" + self.print_header("管理远程仓库") + + if not self.is_git_repo(): + self.print_error("当前目录不是Git仓库") + return + + while True: + print("\n远程仓库管理:") + print("1. 查看远程仓库") + print("2. 添加GitHub远程仓库") + print("3. 添加Gitea远程仓库") + print("4. 删除远程仓库") + print("5. 返回主菜单") + + choice = input("\n请选择 [1-5]: ").strip() + + if choice == '1': + print(f"\n{Colors.CYAN}当前远程仓库:{Colors.ENDC}") + self.run_command("git remote -v", show_output=True) + elif choice == '2': + self.add_github_remote() + elif choice == '3': + self.add_gitea_remote() + elif choice == '4': + self.remove_remote() + elif choice == '5': + break + else: + self.print_error("无效的选择") + + def remove_remote(self): + """删除远程仓库""" + success, output = self.run_command("git remote", show_output=False) + if not success or not output.strip(): + self.print_warning("没有配置远程仓库") + return + + remotes = [r.strip() for r in output.strip().split('\n') if r.strip()] + + if not remotes: + self.print_warning("没有配置远程仓库") + return + + print("\n当前远程仓库:") + for idx, remote in enumerate(remotes, 1): + print(f"{idx}. {remote}") + + choice = input(f"\n请选择要删除的远程仓库 [1-{len(remotes)}]: ").strip() + + try: + choice_idx = int(choice) + if 1 <= choice_idx <= len(remotes): + remote = remotes[choice_idx - 1] + confirm = input(f"确认删除远程仓库 '{remote}'? [y/N]: ").strip().lower() + if confirm == 'y': + success, _ = self.run_command(f"git remote remove {remote}", show_output=False) + if success: + self.print_success(f"远程仓库 '{remote}' 已删除") + else: + self.print_error("删除失败") + else: + self.print_error("无效的选择") + except ValueError: + self.print_error("无效的输入") + + def run(self): + """运行主程序""" + self.print_header("萌芽一键Git管理工具") + print(f"{Colors.CYAN}当前目录:{Colors.ENDC} {self.current_dir}") + print(f"{Colors.CYAN}Git仓库:{Colors.ENDC} {'是' if self.is_git_repo() else '否'}") + + while True: + print(f"\n{Colors.BOLD}请选择操作:{Colors.ENDC}") + print("1. 初始化Git仓库") + print("2. 提交并推送更改") + print("3. 从远程仓库拉取") + print("4. 查看仓库状态") + print("5. 管理远程仓库") + print("6. 退出") + + choice = input(f"\n{Colors.BOLD}请输入选项 [1-6]: {Colors.ENDC}").strip() + + if choice == '1': + self.init_git_repo() + elif choice == '2': + self.commit_and_push() + elif choice == '3': + self.pull_from_remote() + elif choice == '4': + self.show_status() + elif choice == '5': + self.manage_remotes() + elif choice == '6': + self.print_success("感谢使用萌芽Git管理工具!") + break + else: + self.print_error("无效的选择,请重新输入") + + +def main(): + """主函数""" + try: + manager = GitManager() + manager.run() + except KeyboardInterrupt: + print(f"\n\n{Colors.WARNING}程序被用户中断{Colors.ENDC}") + sys.exit(0) + except Exception as e: + print(f"\n{Colors.FAIL}发生错误: {str(e)}{Colors.ENDC}") + sys.exit(1) + + +if __name__ == "__main__": + main()