Files
aibis-dream/split_commit.py
T
bottlefishandClaude Code cdeae42efb feat: 添加归档系统和销售系统基础
- 新增Archive相关资源和预制体
- 新增SalesSystem销售系统基础
- 添加火山美术资源文件夹

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-02-11 18:25:50 +08:00

347 lines
9.9 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Split Commit Tool - 交互式拆分未提交变更为多个原子提交
"""
import os
import sys
import subprocess
from pathlib import Path
# 配置
PROTECTED_BRANCHES = ['main', 'master', 'release/', 'hotfix/']
REPO_ROOT = Path(__file__).parent.absolute()
os.chdir(REPO_ROOT)
def run_command(cmd, capture_output=True):
"""执行Git命令"""
try:
result = subprocess.run(
cmd,
shell=True,
capture_output=capture_output,
text=True,
encoding='utf-8'
)
return result.returncode == 0, result.stdout, result.stderr
except Exception as e:
return False, "", str(e)
def is_protected_branch(branch_name):
"""检查是否为保护分支"""
for protected in PROTECTED_BRANCHES:
if protected.endswith('/') and branch_name.startswith(protected):
return True
if branch_name == protected:
return True
return False
def get_current_branch():
"""获取当前分支"""
success, stdout, stderr = run_command("git branch --show-current")
return stdout.strip() if success else ""
def analyze_changes():
"""分析变更"""
print("=" * 60)
print("步骤 1: 分析变更")
print("=" * 60)
# git status
print("\n[git status]")
success, stdout, stderr = run_command("git status")
print(stdout or stderr)
# git diff --stat
print("\n[git diff --stat]")
success, stdout, stderr = run_command("git diff --stat")
print(stdout or stderr)
return True
def create_commit(msg):
"""使用msg.txt创建提交(避免中文乱码)"""
msg_file = REPO_ROOT / "msg.txt"
try:
with open(msg_file, 'w', encoding='utf-8') as f:
f.write(msg)
f.write("\n\nCo-Authored-By: Claude Code <noreply@anthropic.com>\n")
success, stdout, stderr = run_command("git commit -F msg.txt")
if not success:
print(f"❌ 提交失败: {stderr}")
return False
print(f"✅ 提交成功: {msg}")
return True
finally:
if msg_file.exists():
msg_file.unlink()
def commit_all_changes():
"""一次性提交所有变更"""
print("\n" + "=" * 60)
print("一次性提交所有变更")
print("=" * 60)
# 处理删除的文件
run_command("git ls-files --deleted -z | xargs -0 git rm", capture_output=False)
# 添加所有变更
run_command("git add -A", capture_output=False)
# 创建提交
create_commit("chore: 批量提交变更")
# 显示提交历史
print("\n[提交历史]")
run_command("git log --oneline -5", capture_output=False)
def interactive_split():
"""交互式拆分提交"""
print("\n" + "=" * 60)
print("步骤 2: 分组变更")
print("=" * 60)
# 获取所有变更
success, status_output, _ = run_command("git status --short")
if not success:
print("❌ 无法获取变更状态")
return False
# 分析变更类型
staged_files = []
modified_files = []
deleted_files = []
untracked_files = []
for line in status_output.strip().split('\n'):
if not line:
continue
status = line[:2]
file_path = line[3:]
if status == 'M ':
staged_files.append(file_path)
elif status == ' M':
modified_files.append(file_path)
elif status == 'D ':
deleted_files.append(file_path)
elif status == ' D':
deleted_files.append(file_path)
elif status == '??':
untracked_files.append(file_path)
elif status == 'MM':
staged_files.append(file_path)
modified_files.append(file_path)
# 显示分组建议
groups = []
print("\n[变更分组方案]")
order = 1
# 删除文件
if deleted_files:
groups.append({
'order': order,
'files': deleted_files,
'message': '删除旧文件',
'type': 'delete'
})
print(f"{order}. 删除 {len(deleted_files)} 个文件")
for f in deleted_files[:3]:
print(f" - {f}")
if len(deleted_files) > 3:
print(f" ... 还有 {len(deleted_files) - 3} 个文件")
order += 1
# 修改的meta文件
meta_files = [f for f in modified_files if f.endswith('.meta')]
if meta_files:
groups.append({
'order': order,
'files': meta_files,
'message': '更新.meta文件',
'type': 'meta'
})
print(f"{order}. 修改 {len(meta_files)} 个.meta文件")
for f in meta_files[:3]:
print(f" - {f}")
if len(meta_files) > 3:
print(f" ... 还有 {len(meta_files) - 3} 个文件")
order += 1
# 场景文件
scene_files = [f for f in modified_files if f.endswith('.unity')]
if scene_files:
groups.append({
'order': order,
'files': scene_files,
'message': '更新场景',
'type': 'scene'
})
print(f"{order}. 修改 {len(scene_files)} 个场景文件")
for f in scene_files:
print(f" - {f}")
order += 1
# 脚本文件
script_files = [f for f in modified_files if f.endswith('.cs')]
if script_files:
for script_file in script_files:
groups.append({
'order': order,
'files': [script_file],
'message': f'更新脚本: {Path(script_file).name}',
'type': 'script'
})
print(f"{order}. 修改脚本: {script_file}")
order += 1
# 未跟踪文件
if untracked_files:
groups.append({
'order': order,
'files': untracked_files,
'message': '添加新文件',
'type': 'untracked'
})
print(f"{order}. 添加 {len(untracked_files)} 个新文件")
for f in untracked_files[:3]:
print(f" - {f}")
if len(untracked_files) > 3:
print(f" ... 还有 {len(untracked_files) - 3} 个文件")
print("\n" + "=" * 60)
print("步骤 3: 确认拆分方案")
print("=" * 60)
choice = input("\n是否开始拆分? [1] 开始拆分 [2] 取消拆分 [3] 自定义分组: ")
if choice == '2':
print("\n已取消拆分")
return False
if choice == '3':
print("\n自定义分组功能暂未实现,请使用自动分组")
return False
# 开始拆分
print("\n" + "=" * 60)
print("步骤 4: 执行拆分")
print("=" * 60)
for group in groups:
print(f"\n>>> 处理第 {group['order']} 组")
# 根据类型执行不同的git操作
if group['type'] == 'delete':
# 删除文件
for file_path in group['files']:
run_command(f'git rm "{file_path}"', capture_output=False)
elif group['type'] == 'untracked':
# 添加新文件
run_command('git add -A', capture_output=False)
else:
# 修改文件
for file_path in group['files']:
run_command(f'git add "{file_path}"', capture_output=False)
# 创建提交
success = create_commit(group['message'])
if not success:
print(f"❌ 第 {group['order']} 组提交失败,拆分中止")
return False
input("\n按回车继续下一组...")
print("\n" + "=" * 60)
print("步骤 5: 完成")
print("=" * 60)
print("\n[提交历史]")
success, stdout, _ = run_command("git log --oneline -" + str(len(groups)))
print(stdout)
print(f"\n✅ 拆分完成!共创建 {len(groups)} 个原子提交")
return True
def main():
"""主函数"""
print("=" * 60)
print("Split Commit - 交互式拆分提交工具")
print("=" * 60)
# 检查保护分支
current_branch = get_current_branch()
print(f"\n当前分支: {current_branch}")
if is_protected_branch(current_branch):
print("\n❌ 当前为保护分支,无法直接拆分")
print("\n选项:")
print("[1] 创建新分支再拆分 (推荐)")
print("[2] 压成单commit并移到新分支")
print("[3] 取消")
choice = input("\n请选择: ")
if choice == '1':
branch_name = input("请输入新分支名: ")
if not branch_name:
print("❌ 分支名不能为空")
return
print("\n执行:")
print("1. git stash push --include-untracked")
print(f"2. git checkout -b {branch_name}")
print("3. git stash pop")
confirm = input("\n确认执行?(y/n): ")
if confirm.lower() == 'y':
run_command("git stash push --include-untracked", capture_output=False)
run_command(f"git checkout -b {branch_name}", capture_output=False)
run_command("git stash pop", capture_output=False)
print(f"\n✅ 已切换到新分支: {branch_name}")
print("请重新运行此工具进行拆分")
elif choice == '2':
print("\n功能暂未实现")
return
# 非保护分支,继续拆分流程
print("\n✅ 非保护分支,可以进行拆分")
# 分析变更
if not analyze_changes():
return
# 选择模式
print("\n" + "=" * 60)
print("选择拆分模式:")
print("=" * 60)
print("[1] 交互式拆分 (推荐)")
print("[2] 一次性提交所有变更")
mode = input("\n请选择: ")
if mode == '1':
interactive_split()
elif mode == '2':
commit_all_changes()
else:
print("❌ 无效选择")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n已取消操作")
sys.exit(0)
except Exception as e:
print(f"\n❌ 发生错误: {e}")
sys.exit(1)