本文作者:Ida,对移动端开发拥有深厚的技术积累。近年来,积极探索如何利用 AI 技术提升日常工作效率,并尝试将生成式 AI 应用于研发流程优化。曾参与多个复杂项目的开发与维护,擅长将创新技术融入实际场景,提升用户体验。热爱分享技术心得,致力于让更多人了解并掌握前沿科技。
当基础编码效率提升后,如何让 TRAE 成为真正懂你的 AI 工程师?本文将聚焦 Agent、Rules、图像理解等进阶能力,通过真实案例展示如何系统性提升开发效率,打造专属 AI 工作流。
用 Agent 进一步提效
TRAE 目前支持自定义 Agent,用一段做特定任务的提示词就可以创建一个 Agent,也可以给 Agent 关联上 MCP Tools,并在提示词中编排如何去调用它们。
在过往的开发中,你可能已经发现,有一些提示词会反复用来做某一个特定事情,之前是把这些提示词记到小本本上,用的时候复制过来,现在就可以用它们来创建 Agent 啦,如果提示词具有普适性,还可以直接将 Agent 分享给别人去使用,下面列举一些例子供大家参考。
Case 1:为关键链路补充 ALog
ALog 是抖音里用来打印日志的,当线上用户发生问题时可以回捞这部分日志,用来分析当时用户的代码执行过程,所以通常我们会在关键代码逻辑处,和异常返回处加上 ALog。
现在我们来把诉求告知 AI,然后让它来生成一份更加完善的提示词,再用这份提示词创建一个“抖音 ALog 助手”:
找一份老代码,用这个助手为其加上 ALog,我们来看看效果:
几秒钟的功夫,它就洋洋洒洒地给该文件加上了足够细致的 log,而且拼接出来的语句也都带上了关键的信息。这里不贴生成的提示词了,有需要的同学可以直接复制下面的链接添加到 TRAE 里:
我用 TRAE 做了一个有意思的 Agent 「抖音 ALog 助手」。 点击 https://share.bytedance.net/a/d86a16 立即复刻,一起来玩吧!
Case 2: 给老代码加上注释
同样地,我们也可以创建一个给老代码加注释的 Agent,提高代码阅读的效率。
效果验证
同样分享一下这个 Agent,大家也可以基于这份提示词再继续加工优化:
我用 TRAE 做了一个有意思的 Agent 「代码注释精灵」。 点击 https://share.bytedance.net/a/4f4fbf 立即复刻,一起来玩吧!
Case 3: 生成 UI 代码
UI 代码的生成也可以通过 Agent 一步到位完成,预期它要做的事情:
-
调用 Figma MCP 工具生成 UI 代码。
-
如果是生成 Swift 代码,需要使用 SnapKit 布局。
-
如果是生成 Objective-C 代码,需要使用 Masonry 布局。
在 TRAE 的官方 MCP 市场中可以找到 Figma,然后按照官方指引获取 FIGMA_API_KEY 配置上即可。
再编写提示词,内容如下:
上下滑动查看完整内容
你是一个 UI 代码生成助手 Agent。
你的主要任务是根据 Figma 设计稿生成高质量的 UI 代码。请遵循以下指示:
1. **调用 Figma MCP 工具**:使用 `Figma` 工具从设计稿中提取必要的布局信息和组件规范,并基于此生成初始的 UI 代码。
* **ICON 处理**:如果设计稿中包含 ICON,请确保导出并使用 PNG 格式的 3x 分辨率图。
2. **Swift 代码生成规范**:
* 如果目标语言是 Swift,你必须使用 SnapKit 框架进行布局。确保生成的约束代码简洁、易读,并符合 SnapKit 的最佳实践。
3. **Objective-C 代码生成规范**:
* 如果目标语言是 Objective-C,你必须使用 Masonry 框架进行布局。
4. **代码质量与组件管理**:
* **变量定义**:默认情况下,所有生成的 UI 视图组件都应作为局部临时变量进行定义和使用。除非用户明确指示需要将某个组件定义为属性(例如,为了后续在其他方法中访问或修改),否则不要将其声明为类的属性。
* **注释规范**:生成的代码中应避免过度注释。注释应保持简洁明了,只在必要时解释复杂逻辑或重要意图,而不是简单描述代码做了什么。
* 生成的代码应具有良好的可读性和可维护性。
* 遵循项目既有的代码风格和命名约定。
* 确保生成的代码没有明显的性能问题。
请在开始生成代码前,确认目标语言(Swift 或 Objective-C)和相关的设计稿信息。
现在可以创建 Agent 了,命名为【UI 魔法师】,并关联上Figma
这个工具。最后测试一下效果:
上下滑动查看完整内容
#import "MyCardView.h"
#import <Masonry/Masonry.h>
@implementation MyCardView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupUI];
}
return self;
}
- (void)setupUI {
self.layer.cornerRadius = 16;
self.layer.masksToBounds = YES;
self.layer.borderWidth = 1.5;
self.layer.borderColor = [UIColor colorWithWhite:1.0 alpha:0.15].CGColor;
// Background Gradient
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[
(id)[UIColor blackColor].CGColor,
(id)[UIColor blackColor].CGColor,
(id)[UIColor colorWithRed:0 green:0.267 blue:0.208 alpha:1.0].CGColor
];
gradientLayer.locations = @[@0, @0.6, @1.0];
gradientLayer.frame = self.bounds;
[self.layer insertSublayer:gradientLayer atIndex:0];
// Icon
UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon.png"]];
[self addSubview:iconView];
// Title Label
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.text = @"我是标题";
titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightMedium];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:titleLabel];
// Subtitle Label
UILabel *subtitleLabel = [[UILabel alloc] init];
subtitleLabel.text = @"我是副标题的介绍;
subtitleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
subtitleLabel.textColor = [UIColor colorWithWhite:0.6 alpha:1.0];
subtitleLabel.textAlignment = NSTextAlignmentCenter;
subtitleLabel.numberOfLines = 0;
[self addSubview:subtitleLabel];
// Button
UIButton *matchButton = [UIButton buttonWithType:UIButtonTypeSystem];
[matchButton setTitle:@"开始旅程" forState:UIControlStateNormal];
[matchButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
matchButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];
matchButton.layer.cornerRadius = 12;
matchButton.layer.masksToBounds = YES;
[self addSubview:matchButton];
// Button Gradient
CAGradientLayer *buttonGradient = [CAGradientLayer layer];
buttonGradient.colors = @[
(id)[UIColor colorWithRed:0.2 green:1.0 blue:0.867 alpha:1.0].CGColor,
(id)[UIColor colorWithRed:0.533 green:1.0 blue:0.337 alpha:1.0].CGColor
];
buttonGradient.startPoint = CGPointMake(0, 0.75);
buttonGradient.endPoint = CGPointMake(1, 1.1);
// The button's frame is set by autolayout, so we need to update the gradient layer's frame in layoutSubviews
[matchButton.layer insertSublayer:buttonGradient atIndex:0];
// Layout
[iconView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_top).offset(64);
make.centerX.equalTo(self);
make.width.height.mas_equalTo(120);
}];
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(iconView.mas_bottom).offset(8);
make.centerX.equalTo(self);
}];
[subtitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(titleLabel.mas_bottom).offset(4);
make.left.equalTo(self.mas_left).offset(84);
make.right.equalTo(self.mas_right).offset(-84);
}];
[matchButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_bottom).offset(-16);
make.left.equalTo(self.mas_left).offset(16);
make.right.equalTo(self.mas_right).offset(-16);
make.height.mas_equalTo(44);
}];
}
- (void)layoutSubviews {
[super layoutSubviews];
for (CALayer *layer in self.layer.sublayers) {
if ([layer isKindOfClass:[CAGradientLayer class]]) {
layer.frame = self.bounds;
}
}
for (CALayer *layer in [self.subviews.lastObject layer].sublayers) {
if ([layer isKindOfClass:[CAGradientLayer class]]) {
layer.frame = self.subviews.lastObject.bounds;
}
}
}
@end
用 Rules 规范生成的代码
经过一段时间对 TRAE 的使用,就会发现,有一些要求需要每次都写在提示词中,代码风格有时也不稳定,好在目前 TRAE 已经支持了 Rules,我们可以把一些对生成代码的通用要求配置在这里。对于这个配置的提示词,也可以让 TRAE 来生成。
对这份生成的提示词还比较满意,有需要的同学可以直接抱走~
上下滑动查看完整内容
# 代码风格规范指南
以下规则旨在指导代码生成和修改,以确保代码库的一致性和可读性。
## 1. 注释规范
### 1.1. Swift 注释
- **注释风格**:对于 Swift 代码,在为函数、类、属性、结构体等添加注释时,请始终使用三斜线注释 (`///`)。
```swift
/// 这是一个描述该函数功能的注释。
/// - Parameter name: 参数的描述。
/// - Returns: 返回值的描述。
func exampleFunction(name: String) -> String {
// ...
}
/// 这是一个描述该类功能的注释。
class ExampleClass {
/// 这是一个描述该属性功能的注释。
var exampleProperty: Int = 0
}
1.2. Objective-C 注释
- 注释风格:对于 Objective-C 代码,在添加注释时,请始终使用三斜线注释 (
///
)。/// 这是一个描述该方法功能的注释。 /// @param parameterName 参数的描述。 /// @return 返回值的描述。 - (NSString *)exampleMethodWithParameter:(NSString *)parameterName; /// 这是一个描述该属性功能的注释。 @property (nonatomic, strong, nullable) NSString *exampleProperty;
1.3. 通用注释要求
- 注释语言:所有注释内容请始终使用中文编写。
- 注释简洁性:注释应保持简洁明了,清晰地解释代码的意图、功能或复杂逻辑。避免过度注释,尤其不应添加描述代码修改过程的无意义注释(例如:“把XXX修改成XXX”、“修复BUG”等)。注释的目的是解释代码的“为什么”和“做什么”,而不是记录显而易见的修改历史。
2. Swift 代码风格
- SwiftLint 遵循:Swift 代码的格式化应严格遵守 SwiftLint 的规范。
- 参数垂直对齐:特别注意
vertical_parameter_alignment
规则:当函数或方法声明中的参数因过长而占据多行时,这些参数应当垂直对齐。 0- 非触发示例 (Good): 0
func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind, dictionary: SourceKittenDictionary) { } func validateFunction( _ file: SwiftLintFile, kind: SwiftDeclarationKind, dictionary: SourceKittenDictionary ) -> [StyleViolation]
- 触发示例 (Bad - 需要修正): 0
// SwiftLint会在此处报错 func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind, ↓dictionary: SourceKittenDictionary) { } // 'dictionary' 未对齐 func validateFunction(_ file: SwiftLintFile, ↓kind: SwiftDeclarationKind, // 'kind' 未对齐 ↓dictionary: SourceKittenDictionary) { } // 'dictionary' 未对齐
- 非触发示例 (Good): 0
3. Objective-C 代码风格
- Nullability 修饰符:为 Objective-C 代码生成方法(包括返回类型)和属性时,如果它们是指针类型,请始终为其添加
nullable
修饰符,除非上下文文明确要求nonnull
或已知其永不为空。// 示例: @property (nonatomic, strong, nullable) NSString *name; @property (nonatomic, copy, nullable) NSArray<NSString *> *items; - (nullable UIView *)viewWithTag:(NSInteger)tag; - (void)processData:(nullable NSData *)data completion:(nullable void (^)(NSError * _Nullable error))completion;
- 头文件
NS_ASSUME_NULLABLE
宏: 创建新的 Objective-C 头文件 (.h
) 时,其内容应始终被NS_ASSUME_NULLABLE_BEGIN
和NS_ASSUME_NULLABLE_END
宏包裹。这有助于管理区域性的 nullability 注解。参考示例:// SomeClass.h #import <Foundation/Foundation.h> // 或其他必要的 imports NS_ASSUME_NULLABLE_BEGIN @interface SomeClassName : NSObject // 属性和方法声明在此处 @end NS_ASSUME_NULLABLE_END
4. 单例命名规范
- 命名统一性:单例模式的实例访问方法或属性命名应保持统一规范:
- Swift:在 Swift 代码中,单例实例请统一命名为
shared
。class DataManager { static let shared = DataManager() private init() {} } // 使用: DataManager.shared
- Objective-C:在 Objective-C 代码中,单例实例的获取方法请统一命名为
sharedInstance
。// DataManager.h @interface DataManager : NSObject + (instancetype)sharedInstance; @end // DataManager.m @implementation DataManager + (instancetype)sharedInstance { static DataManager *sharedInstance = nil; staticdispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; } - (instancetype)init { self = [super init]; if (self) { // 初始化代码 } return self; } @end // 使用: [DataManager sharedInstance]
- Swift:在 Swift 代码中,单例实例请统一命名为
找了个文件测试了一下效果,看起来还不错,nullable 加上了,注释也都是按要求来的。




**把图作为上下文使用**
现在 TRAE 已经集成了 Gemini-2.5-Pro-Preview(0506)(最新版本中已经是 Gemini-2.5-Pro),**该模型支持图片理解** ,可以有效利用这一能力来节省写提示词的时间。前面有直接用类图生成代码的演示,这里再列举一些 Case。
**Case 1: 用线框图生成 debug 页面**
当我们想在 Debug 面板中加上某个功能的调试页面时,可以画好页面的线框图中,然后直接让 Gemini 根据图中样式去实现页面,这样基本可以一次性就把页面布局搞定。比如下面是给社交相机跳转的调试页面:
**上下滑动查看完整内容**
#import "AFDSocialCameraDebugViewController.h"
@interface AFDSocialCameraDebugViewController()
@property(nonatomic, strong) UILabel *enterFromLabel;
@property (nonatomic, strong) UITextField *enterFromTextField;
@property (nonatomic, strong) UILabel *shootWayLabel;
@property (nonatomic, strong) UITextField *shootWayTextField;
@property (nonatomic, strong) UILabel *socialCameraTypeLabel;
@property (nonatomic, strong) UITextField *socialCameraTypeTextField;
@property (nonatomic, strong) UILabel *configLabel;
@property (nonatomic, strong) UITextView *configTextView;
@property (nonatomic, strong) UIButton *generateSchemaButton;
@property (nonatomic, strong) UITextView *schemaTextView;
@property (nonatomic, strong) UIButton *openCameraButton;
@end
@implementation AFDSocialCameraDebugViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self setupUI];
} - (void)setupUI {
self.enterFromLabel = [UILabel new];
self.enterFromLabel.text = @"enter_from:";
[self.view addSubview:self.enterFromLabel];
self.enterFromTextField = [UITextField new];
self.enterFromTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:self.enterFromTextField];
self.shootWayLabel = [UILabel new];
self.shootWayLabel.text = @"shoot_way:";
[self.view addSubview:self.shootWayLabel];
self.shootWayTextField = [UITextField new];
self.shootWayTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:self.shootWayTextField];
self.socialCameraTypeLabel = [UILabel new];
self.socialCameraTypeLabel.text = @"social_camera_type:";
[self.view addSubview:self.socialCameraTypeLabel];
self.socialCameraTypeTextField = [UITextField new];
self.socialCameraTypeTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:self.socialCameraTypeTextField];
self.configLabel = [UILabel new];
self.configLabel.text = @"config:";
[self.view addSubview:self.configLabel];
self.configTextView = [UITextView new];
self.configTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.configTextView.layer.borderWidth = 1.0;
self.configTextView.layer.cornerRadius = 5.0;
[self.view addSubview:self.configTextView];
self.generateSchemaButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.generateSchemaButton setTitle:@"生成 Schema" forState:UIControlStateNormal];
self.generateSchemaButton.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:1.0 alpha:1.0];
self.generateSchemaButton.layer.cornerRadius = 10.0;
[self.view addSubview:self.generateSchemaButton];
self.schemaTextView = [UITextView new];
self.schemaTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.schemaTextView.layer.borderWidth = 1.0;
self.schemaTextView.layer.cornerRadius = 5.0;
[self.view addSubview:self.schemaTextView];
self.openCameraButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.openCameraButton setTitle:@"点击打开相机" forState:UIControlStateNormal];
self.openCameraButton.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:1.0 alpha:1.0];
self.openCameraButton.layer.cornerRadius = 10.0;
[self.view addSubview:self.openCameraButton];
// Layout
self.enterFromLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.enterFromTextField.translatesAutoresizingMaskIntoConstraints = NO;
self.shootWayLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.shootWayTextField.translatesAutoresizingMaskIntoConstraints = NO;
self.socialCameraTypeLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.socialCameraTypeTextField.translatesAutoresizingMaskIntoConstraints = NO;
self.configLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.configTextView.translatesAutoresizingMaskIntoConstraints = NO;
self.generateSchemaButton.translatesAutoresizingMaskIntoConstraints = NO;
self.schemaTextView.translatesAutoresizingMaskIntoConstraints = NO;
self.openCameraButton.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat padding = 20.0;
CGFloat textFieldHeight = 40.0;
CGFloat textViewHeight = 100.0;
CGFloat buttonHeight = 44.0;
[NSLayoutConstraint activateConstraints:@[
[self.enterFromLabel.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:padding],
[self.enterFromLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.enterFromTextField.topAnchor constraintEqualToAnchor:self.enterFromLabel.bottomAnchor constant:8],
[self.enterFromTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.enterFromTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
[self.enterFromTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
[self.shootWayLabel.topAnchor constraintEqualToAnchor:self.enterFromTextField.bottomAnchor constant:padding],
[self.shootWayLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.shootWayTextField.topAnchor constraintEqualToAnchor:self.shootWayLabel.bottomAnchor constant:8],
[self.shootWayTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.shootWayTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
[self.shootWayTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
[self.socialCameraTypeLabel.topAnchor constraintEqualToAnchor:self.shootWayTextField.bottomAnchor constant:padding],
[self.socialCameraTypeLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.socialCameraTypeTextField.topAnchor constraintEqualToAnchor:self.socialCameraTypeLabel.bottomAnchor constant:8],
[self.socialCameraTypeTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.socialCameraTypeTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
[self.socialCameraTypeTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
[self.configLabel.topAnchor constraintEqualToAnchor:self.socialCameraTypeTextField.bottomAnchor constant:padding],
[self.configLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.configTextView.topAnchor constraintEqualToAnchor:self.configLabel.bottomAnchor constant:8],
[self.configTextView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.configTextView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
[self.configTextView.heightAnchor constraintEqualToConstant:textViewHeight],
[self.generateSchemaButton.topAnchor constraintEqualToAnchor:self.configTextView.bottomAnchor constant:padding],
[self.generateSchemaButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[self.generateSchemaButton.widthAnchor constraintEqualToConstant:200],
[self.generateSchemaButton.heightAnchor constraintEqualToConstant:buttonHeight],
[self.schemaTextView.topAnchor constraintEqualToAnchor:self.generateSchemaButton.bottomAnchor constant:padding],
[self.schemaTextView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
[self.schemaTextView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
[self.schemaTextView.heightAnchor constraintEqualToConstant:textViewHeight],
[self.openCameraButton.topAnchor constraintEqualToAnchor:self.schemaTextView.bottomAnchor constant:padding],
[self.openCameraButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
[self.openCameraButton.widthAnchor constraintEqualToConstant:200],
[self.openCameraButton.heightAnchor constraintEqualToConstant:buttonHeight],
]];
}
@end

**Case 2: 用表格生成 libra 中配置的 json**
我一般习惯在技术方案中本次需求中涉及到的所有 AB 和 Settings 变量,有了这样的表格后,可以直接将其截图给 Gemini ,然后让它把其中的内容转换成 json 格式,省得自己去一点点拼接,几秒钟就完成了!



**编写提效脚本工具**
还可以用 TRAE 编写 Python 脚本,将需要手动重复操作的事情自动化处理,有想法就可以跟 LLM 去聊,让它先规划一下实现思路,觉得可行就开始让它继续往下写。
下面几个是我之前写的,完全是通过与 LLM 的对话来实现的,可供大家参考,打开思路。
**Case1: 快速创建 BugFix MR**
在日常工作中经常遇到的一种情况是,我正在热火朝天地开发需求赶 Deadline 呢,QA 突然找过来一个集成问题,有时不得不跟 alpha 修,之前的做法是打开 MBox ,切换 workspace,创建分支,这个过程就要等一会,然后再把修复问题的 commit chery-pick 过来,push 代码,创建 MR。
于是我就把这一套提 MR 的流程打包成了脚本,然后创建了一个 workspace 专门用来提 BugFix MR,最后又丰富了一下脚本的功能。
**上下滑动查看完整内容**
#!/usr/bin/env python3
import argparse
from datetime import datetime
import subprocess
import sys
import webbrowser
import os
import json
def run_git_command(command):
"""执行 git 命令并返回结果"""
# 定义允许的 git 命令白名单
allowed_commands = {
'git checkout', 'git pull', 'git checkout -b',
'git cherry-pick', 'git push', 'git fetch',
'git merge', 'git branch',
'git diff' # 新增允许的diff命令
}
# 验证命令是否在白名单中
ifnotany(command.startswith(cmd) for cmd in allowed_commands):
print(f"不允许执行的命令: {command}")
sys.exit(1)
try:
result = subprocess.run(command, shell=True, check=True,
capture_output=True, text=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Git 命令执行失败: {e}")
print(f"错误输出: {e.stderr}")
sys.exit(1)
def create_bugfix_branch(base_branch):
"""基于给定分支创建 bugfix 分支"""
# 获取当前日期和时间(添加时分秒)
now = datetime.now()
timestamp = now.strftime('%Y%m%d_%H%M%S')
new_branch = f"feature/ida_{timestamp}"
# 确保环境清洁
run_git_command("git branch -D temp_branch || true") # 强制清理旧分支
try:
run_git_command(f"git fetch origin {base_branch}")
run_git_command(f"git checkout -b temp_branch origin/{base_branch}")
finally:
run_git_command("git branch -D temp_branch || true") # 确保最终清理
# 创建新分支
run_git_command(f"git checkout -b {new_branch}")
run_git_command("git branch -D temp_branch") # 新增:删除临时分支
print(f"成功创建分支: \033[92m{new_branch}\033[0m")
return new_branch
def cherry_pick_commits(commit_hashes):
"""Cherry-pick 指定的提交"""
print("正在获取远端最新提交...")
run_git_command("git fetch --all --prune")
print("获取完成。")
for commit in commit_hashes:
try:
# 使用 GIT_EDITOR=true 防止 git 打开编辑器导致进程挂起
# 我们不使用 run_git_command 因为我们想自定义错误处理
result = subprocess.run(f"GIT_EDITOR=true git cherry-pick {commit}",
shell=True,
capture_output=True,
text=True)
if result.returncode != 0:
# 抛出异常,由 except 块统一处理
raise subprocess.CalledProcessError(result.returncode, result.args, output=result.stdout, stderr=result.stderr)
print(f"成功 cherry-pick 提交: {commit}")
except subprocess.CalledProcessError as e:
print(f"\nCherry-pick 失败,提交 hash: {commit}")
# 检查是否有冲突
conflict_files = run_git_command("git diff --name-only --diff-filter=U")
if conflict_files:
print("‼️ 检测到合并冲突。冲突文件列表:")
print(conflict_files)
print("\n请按以下步骤处理:")
print("1. 手动解决上述冲突文件")
print("2. 执行 git add 冲突文件")
print("3. 执行 git cherry-pick --continue 继续")
print("或使用 git cherry-pick --abort 中止操作")
else:
print("错误详情:")
print(e.stderr)
sys.exit(1)
def push_branch(branch_name):
"""推送分支到远端"""
try:
run_git_command(f"git push -u origin {branch_name}")
print(f"成功推送分支 \033[92m{branch_name}\033[0m到远端")
except Exception as e:
print(f"推送分支失败: {e}")
sys.exit(1)
def open_create_mr_page():
"""打开创建 MR 的网页"""
url = "MR 网页的URL"
try:
webbrowser.open(url)
print("已打开创建 MR 的网页")
except Exception as e:
print(f"打开网页失败: {e}")
print(f"请手动访问: {url}")
def merge_develop(branch_name):
try:
print("正在合并 develop 分支...")
run_git_command("git fetch origin develop") # 简化的fetch命令
# 修改合并命令添加冲突检测
result = subprocess.run("git merge origin/develop", shell=True, capture_output=True, text=True) # 明确指定远端分支
if result.returncode != 0:
conflict_files = run_git_command("git diff --name-only --diff-filter=U")
print("\n‼️ 合并冲突文件列表:")
print(conflict_files)
raise subprocess.CalledProcessError(result.returncode, result.args)
print("成功合并 develop 分支")
except Exception as e:
print(f"\n合并 develop 分支失败: {e}")
print("请按以下步骤处理:")
print("1. 手动解决上述冲突文件")
print("2. 执行 git add 冲突文件")
print("3. 执行 git commit 完成合并")
sys.exit(1)
def set_working_directory():
"""设置工作目录"""
work_dir = "/Volumes/Ida/DevMbox-BugFix/Aweme" # 默认工作目录
try:
os.chdir(work_dir)
print(f"已切换工作目录到: {work_dir}")
except Exception as e:
print(f"切换工作目录失败: {e}")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(description='Git 分支管理工具')
args = parser.parse_args()
set_working_directory()
# 获取并显示所有分支
branches = run_git_command("git branch").split('\n') # 修改为仅获取本地分支
current_branch = next((b.split()[-1] for b in branches if b.startswith('*')), 'unknown')
print("\n可用分支列表:")
for branch in branches:
display = branch.replace('* ', '')
if branch.startswith('*'):
print(f" \033[91m{display}\033[0m (当前分支)")
else:
print(f" {display}")
# 新增分支操作选项
# 修改后的分支操作选项
choice = None
while choice not in ['a', 'b', 'c', 'd']: # 新增选项d
print("\n请选择操作:")
print("a. 创建新分支")
print("b. 切换到现有分支")
print("c. 继续在当前分支操作")
print("d. 删除现有分支") # 新增删除选项
choice = input("请输入选项 (a/b/c/d): ").strip().lower()
# 修改后的分支操作逻辑
if choice == 'd': # 分支删除逻辑
branches_to_delete = input("请输入要删除的分支名称(多个用空格分隔): ").split()
for branch in branches_to_delete:
try:
run_git_command(f"git branch -D {branch}")
print(f"已删除分支: \033[91m{branch}\033[0m")
except Exception as e:
print(f"删除分支 {branch} 失败: {e}")
print(f"\n所有操作已完成!")
sys.exit(0)
elif choice == 'a': # 创建分支
base_branch = input("请输入要基于哪个分支创建(例如 develop): ").strip()
new_branch = create_bugfix_branch(base_branch)
elif choice == 'b': # 切换分支
target_branch = input("请输入要切换到的分支名称: ").strip()
run_git_command(f"git checkout {target_branch}")
new_branch = run_git_command("git branch --show-current")
print(f"已切换到分支: \033[92m{new_branch}\033[0m")
else: # 继续当前分支(选项c)
new_branch = current_branch
print(f"继续在当前分支操作: \033[92m{new_branch}\033[0m")
# Cherry-pick 确认(原有代码保持不变)
if input("是否要执行 cherry-pick?(Y/N): ").strip().upper() == 'Y':
commits = input("请输入要 cherry-pick 的提交 hash(多个用空格分隔): ").split()
if commits:
cherry_pick_commits(commits)
# 合并 develop 确认
if input("是否要合并 develop 分支?(Y/N): ").strip().upper() == 'Y':
merge_develop(new_branch)
# 推送分支
push_branch(new_branch)
# 新增打开网页确认
if input("是否要打开创建 MR 的网页?(Y/N): ").strip().upper() == 'Y':
open_create_mr_page()
print(f"\n所有操作已完成!")
if name == "main":
main()

**Case2: 生成代码的脚手架**
前段时间做了推人卡片接入异形卡框架的重构,重构之后再有新的卡片接入,按照一定的模式实现就行了,比如要创建哪些类,实现哪些接口。所以我直接把推人卡片代码改造成了模块化的代码,加了一些占位符,然后再通过脚本改成新卡片的代码。模板化改造这一部分也是用 TRAE 来完成的,主要是一些重命名,符号替换的工作。
**上下滑动查看完整内容**
import os
import shutil
import argparse
import subprocess
from datetime import datetime
def replace_in_file(file_path, replacements):
"""Replaces multiple occurrences in a file based on a dictionary of replacements."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
new_content = content
for old_str, new_str in replacements.items():
new_content = new_content.replace(old_str, new_str)
if new_content != content:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(new_content)
else:
print(f" - No content replacement needed in: {os.path.basename(file_path)}")
except Exception as e:
print(f" - Error processing file {file_path}: {e}")
def get_git_username():
"""Gets the current git username."""
try:
result = subprocess.run(['git', 'config', 'user.name'], capture_output=True, text=True, check=True)
return result.stdout.strip()
except (subprocess.CalledProcessError, FileNotFoundError):
print("Warning: Could not get git username. Using 'Default Author'.")
return"Default Author"
def generate_card_module(module_name):
"""Generates a new card module based on the BusinessCard template."""
source_dir = os.path.join(os.getcwd(), "BusinessCard")
target_dir = os.path.join(os.getcwd(), module_name)
new_prefix = f"AWE{module_name}"
old_prefix = "BusinessCard"
git_author = get_git_username()
current_date = datetime.now().strftime("%Y/%-m/%-d") # Format YYYY/M/D
ifnot os.path.exists(source_dir):
print(f"Error: Source directory '{source_dir}' not found.")
return
if os.path.exists(target_dir):
print(f"Error: Target directory '{target_dir}' already exists.")
return
try:
# 1. Create target directory
os.makedirs(target_dir)
# 2. Copy files
copied_files = []
for item in os.listdir(source_dir):
# Skip .DS_Store files
if item == ".DS_Store":
continue
s_path = os.path.join(source_dir, item)
d_path = os.path.join(target_dir, item)
if os.path.isfile(s_path):
shutil.copy2(s_path, d_path)
copied_files.append(item)
# 3. Rename files and replace content
for filename in copied_files:
if filename.startswith(old_prefix):
# Rename file
new_filename = filename.replace(old_prefix, new_prefix, 1)
old_filepath = os.path.join(target_dir, filename)
new_filepath = os.path.join(target_dir, new_filename)
os.rename(old_filepath, new_filepath)
# Prepare replacements
replacements = {
old_prefix: new_prefix,
"__AUTHOR__": git_author,
"__DATE__": current_date
}
# Replace content in the renamed file
replace_in_file(new_filepath, replacements)
else:
# Also replace content in files that don't match the prefix pattern
filepath = os.path.join(target_dir, filename)
replacements = {
old_prefix: new_prefix, # Keep prefix replacement if needed elsewhere
"__AUTHOR__": git_author,
"__DATE__": current_date
}
replace_in_file(filepath, replacements)
print(f"\033[92m\nSuccessfully generated module '{module_name}' in '{target_dir}'\033[0m")
except Exception as e:
print(f"An error occurred: {e}")
# Clean up if error occurs during creation
if os.path.exists(target_dir):
shutil.rmtree(target_dir)
print(f"Cleaned up directory: {target_dir}")
if name == "main":
parser = argparse.ArgumentParser(description="Generate a new card module framework.")
parser.add_argument("module_name", help="The name of the new card module (e.g., MateBigCard)")
args = parser.parse_args()
generate_card_module(args.module_name)
模板代码:

执行脚本:

python3 generate_code.py 你的卡片模块名称(比如推人大卡就可以是MateBigCard)
**Case3: 快速构造 mock 数据**
也是在做推人卡片重构时,发现手动去 mock 数据非常麻烦,而客户端的调试又依赖数据,所以琢磨能否用写个脚本来自动请求 user 数据,再拼接成符合要求的数据格式。




**作为 Source Control 工具**
TRAE IDE 里也集成了 Source Control 工具,同样推荐大家去试用:
* 这样就可以少开一个用来做 Source Control 的工具啦,并且可以随时查看代码变更。
* 可以自动生成 commit message。
* UI 交互区友好,基本零成本上手使用。


最后,无论 AI 生成的代码如何精妙,工程师对质量的守护永不可替代,在上线前还是要仔细地去 Review 代码,保持对线上代码的敬畏心。
点击**阅读原文** ,让 TRAE 成为你的提效加速器,用 AI 释放创造力,以专业守护代码质量。