Skip to content

Git API

概述

Trae Git API 提供了完整的 Git 版本控制功能,支持仓库管理、分支操作、提交历史、远程仓库同步等操作。开发者可以通过 API 实现 Git 工作流的自动化和集成。

核心概念

Git 仓库

typescript
import { git, Uri } from '@trae/api';

interface Repository {
  readonly rootUri: Uri;
  readonly state: RepositoryState;
  readonly inputBox: SourceControlInputBox;
  readonly resourceGroups: SourceControlResourceGroup[];
}

interface RepositoryState {
  readonly HEAD: Branch | undefined;
  readonly refs: Ref[];
  readonly remotes: Remote[];
  readonly submodules: Submodule[];
  readonly rebaseCommit: Commit | undefined;
  readonly mergeChanges: Change[];
  readonly indexChanges: Change[];
  readonly workingTreeChanges: Change[];
}

分支和引用

typescript
interface Branch {
  readonly name: string;
  readonly commit?: string;
  readonly type: RefType;
  readonly remote?: string;
  readonly upstream?: string;
  readonly ahead?: number;
  readonly behind?: number;
}

interface Ref {
  readonly type: RefType;
  readonly name?: string;
  readonly commit?: string;
  readonly remote?: string;
}

enum RefType {
  Head,
  RemoteHead,
  Tag
}

API 参考

仓库管理

获取仓库

typescript
// 获取当前工作区的 Git 仓库
const getCurrentRepository = (): Repository | undefined => {
  const repositories = git.repositories;
  return repositories.length > 0 ? repositories[0] : undefined;
};

// 获取指定路径的仓库
const getRepositoryByPath = (path: string): Repository | undefined => {
  const uri = Uri.file(path);
  return git.getRepository(uri);
};

// 监听仓库变化
git.onDidOpenRepository(repository => {
  console.log('Repository opened:', repository.rootUri.fsPath);
  setupRepositoryListeners(repository);
});

git.onDidCloseRepository(repository => {
  console.log('Repository closed:', repository.rootUri.fsPath);
});

初始化仓库

typescript
// 初始化新的 Git 仓库
const initRepository = async (path: string): Promise<Repository> => {
  try {
    const uri = Uri.file(path);
    const repository = await git.init(uri);
    console.log('Repository initialized:', repository.rootUri.fsPath);
    return repository;
  } catch (error) {
    console.error('Failed to initialize repository:', error);
    throw error;
  }
};

// 克隆远程仓库
const cloneRepository = async (
  url: string,
  parentPath: string,
  options?: CloneOptions
): Promise<Repository> => {
  try {
    const parentUri = Uri.file(parentPath);
    const repository = await git.clone(url, parentUri, options);
    console.log('Repository cloned:', repository.rootUri.fsPath);
    return repository;
  } catch (error) {
    console.error('Failed to clone repository:', error);
    throw error;
  }
};

interface CloneOptions {
  branch?: string;
  depth?: number;
  recursive?: boolean;
  progress?: (progress: Progress) => void;
}

分支操作

分支管理

typescript
// 获取所有分支
const getAllBranches = async (repository: Repository): Promise<Branch[]> => {
  try {
    return await repository.getBranches();
  } catch (error) {
    console.error('Failed to get branches:', error);
    return [];
  }
};

// 获取当前分支
const getCurrentBranch = (repository: Repository): Branch | undefined => {
  return repository.state.HEAD;
};

// 创建新分支
const createBranch = async (
  repository: Repository,
  name: string,
  checkout = true
): Promise<void> => {
  try {
    await repository.createBranch(name, checkout);
    console.log(`Branch '${name}' created${checkout ? ' and checked out' : ''}`);
  } catch (error) {
    console.error('Failed to create branch:', error);
    throw error;
  }
};

// 切换分支
const checkoutBranch = async (
  repository: Repository,
  name: string
): Promise<void> => {
  try {
    await repository.checkout(name);
    console.log(`Switched to branch '${name}'`);
  } catch (error) {
    console.error('Failed to checkout branch:', error);
    throw error;
  }
};

// 删除分支
const deleteBranch = async (
  repository: Repository,
  name: string,
  force = false
): Promise<void> => {
  try {
    await repository.deleteBranch(name, force);
    console.log(`Branch '${name}' deleted`);
  } catch (error) {
    console.error('Failed to delete branch:', error);
    throw error;
  }
};

分支合并

typescript
// 合并分支
const mergeBranch = async (
  repository: Repository,
  branch: string
): Promise<void> => {
  try {
    await repository.merge(branch);
    console.log(`Merged branch '${branch}'`);
  } catch (error) {
    console.error('Failed to merge branch:', error);
    throw error;
  }
};

// 变基操作
const rebaseBranch = async (
  repository: Repository,
  branch: string
): Promise<void> => {
  try {
    await repository.rebase(branch);
    console.log(`Rebased onto '${branch}'`);
  } catch (error) {
    console.error('Failed to rebase:', error);
    throw error;
  }
};

// 解决合并冲突
const resolveMergeConflicts = async (
  repository: Repository,
  files: Uri[]
): Promise<void> => {
  try {
    // 标记冲突文件为已解决
    for (const file of files) {
      await repository.add([file]);
    }
    
    console.log('Merge conflicts resolved');
  } catch (error) {
    console.error('Failed to resolve conflicts:', error);
    throw error;
  }
};

提交操作

暂存和提交

typescript
// 暂存文件
const stageFiles = async (
  repository: Repository,
  files: Uri[]
): Promise<void> => {
  try {
    await repository.add(files);
    console.log(`Staged ${files.length} files`);
  } catch (error) {
    console.error('Failed to stage files:', error);
    throw error;
  }
};

// 取消暂存文件
const unstageFiles = async (
  repository: Repository,
  files: Uri[]
): Promise<void> => {
  try {
    await repository.revert(files);
    console.log(`Unstaged ${files.length} files`);
  } catch (error) {
    console.error('Failed to unstage files:', error);
    throw error;
  }
};

// 提交更改
const commitChanges = async (
  repository: Repository,
  message: string,
  options?: CommitOptions
): Promise<void> => {
  try {
    await repository.commit(message, options);
    console.log('Changes committed:', message);
  } catch (error) {
    console.error('Failed to commit changes:', error);
    throw error;
  }
};

interface CommitOptions {
  all?: boolean;
  amend?: boolean;
  signoff?: boolean;
  signCommit?: boolean;
  empty?: boolean;
  noVerify?: boolean;
}

// 修改最后一次提交
const amendLastCommit = async (
  repository: Repository,
  message?: string
): Promise<void> => {
  try {
    await repository.commit(message || '', { amend: true });
    console.log('Last commit amended');
  } catch (error) {
    console.error('Failed to amend commit:', error);
    throw error;
  }
};

提交历史

typescript
// 获取提交历史
const getCommitHistory = async (
  repository: Repository,
  options?: LogOptions
): Promise<Commit[]> => {
  try {
    return await repository.log(options);
  } catch (error) {
    console.error('Failed to get commit history:', error);
    return [];
  }
};

interface LogOptions {
  maxEntries?: number;
  skip?: number;
  path?: string;
  branch?: string;
  author?: string;
  since?: Date;
  until?: Date;
}

interface Commit {
  readonly hash: string;
  readonly message: string;
  readonly parents: string[];
  readonly authorDate?: Date;
  readonly authorName?: string;
  readonly authorEmail?: string;
  readonly commitDate?: Date;
}

// 获取特定提交的详细信息
const getCommitDetails = async (
  repository: Repository,
  hash: string
): Promise<CommitDetails | undefined> => {
  try {
    return await repository.getCommit(hash);
  } catch (error) {
    console.error('Failed to get commit details:', error);
    return undefined;
  }
};

interface CommitDetails extends Commit {
  readonly changes: Change[];
  readonly diff: string;
}

远程仓库操作

远程仓库管理

typescript
// 获取远程仓库列表
const getRemotes = async (repository: Repository): Promise<Remote[]> => {
  try {
    return await repository.getRemotes();
  } catch (error) {
    console.error('Failed to get remotes:', error);
    return [];
  }
};

interface Remote {
  readonly name: string;
  readonly fetchUrl?: string;
  readonly pushUrl?: string;
  readonly isReadOnly: boolean;
}

// 添加远程仓库
const addRemote = async (
  repository: Repository,
  name: string,
  url: string
): Promise<void> => {
  try {
    await repository.addRemote(name, url);
    console.log(`Remote '${name}' added: ${url}`);
  } catch (error) {
    console.error('Failed to add remote:', error);
    throw error;
  }
};

// 删除远程仓库
const removeRemote = async (
  repository: Repository,
  name: string
): Promise<void> => {
  try {
    await repository.removeRemote(name);
    console.log(`Remote '${name}' removed`);
  } catch (error) {
    console.error('Failed to remove remote:', error);
    throw error;
  }
};

同步操作

typescript
// 拉取更新
const pullChanges = async (
  repository: Repository,
  remote?: string,
  branch?: string
): Promise<void> => {
  try {
    await repository.pull(remote, branch);
    console.log('Changes pulled successfully');
  } catch (error) {
    console.error('Failed to pull changes:', error);
    throw error;
  }
};

// 推送更改
const pushChanges = async (
  repository: Repository,
  remote?: string,
  branch?: string,
  force = false
): Promise<void> => {
  try {
    await repository.push(remote, branch, force);
    console.log('Changes pushed successfully');
  } catch (error) {
    console.error('Failed to push changes:', error);
    throw error;
  }
};

// 获取远程更新
const fetchChanges = async (
  repository: Repository,
  remote?: string
): Promise<void> => {
  try {
    await repository.fetch(remote);
    console.log('Remote changes fetched');
  } catch (error) {
    console.error('Failed to fetch changes:', error);
    throw error;
  }
};

状态和差异

仓库状态

typescript
// 获取工作区状态
const getWorkingTreeChanges = (repository: Repository): Change[] => {
  return repository.state.workingTreeChanges;
};

// 获取暂存区状态
const getIndexChanges = (repository: Repository): Change[] => {
  return repository.state.indexChanges;
};

// 获取合并状态
const getMergeChanges = (repository: Repository): Change[] => {
  return repository.state.mergeChanges;
};

interface Change {
  readonly uri: Uri;
  readonly originalUri: Uri;
  readonly renameUri: Uri | undefined;
  readonly status: Status;
}

enum Status {
  INDEX_MODIFIED,
  INDEX_ADDED,
  INDEX_DELETED,
  INDEX_RENAMED,
  INDEX_COPIED,
  MODIFIED,
  DELETED,
  UNTRACKED,
  IGNORED,
  INTENT_TO_ADD,
  BOTH_DELETED,
  ADDED_BY_US,
  DELETED_BY_THEM,
  ADDED_BY_THEM,
  DELETED_BY_US,
  BOTH_ADDED,
  BOTH_MODIFIED
}

文件差异

typescript
// 获取文件差异
const getFileDiff = async (
  repository: Repository,
  uri: Uri,
  staged = false
): Promise<string> => {
  try {
    return await repository.diff(uri, staged);
  } catch (error) {
    console.error('Failed to get file diff:', error);
    return '';
  }
};

// 获取提交间差异
const getCommitDiff = async (
  repository: Repository,
  commit1: string,
  commit2: string
): Promise<string> => {
  try {
    return await repository.diffBetween(commit1, commit2);
  } catch (error) {
    console.error('Failed to get commit diff:', error);
    return '';
  }
};

// 获取文件在特定提交的内容
const getFileAtCommit = async (
  repository: Repository,
  uri: Uri,
  commit: string
): Promise<string> => {
  try {
    return await repository.show(commit, uri.fsPath);
  } catch (error) {
    console.error('Failed to get file at commit:', error);
    return '';
  }
};

标签操作

typescript
// 创建标签
const createTag = async (
  repository: Repository,
  name: string,
  message?: string
): Promise<void> => {
  try {
    await repository.tag(name, message);
    console.log(`Tag '${name}' created`);
  } catch (error) {
    console.error('Failed to create tag:', error);
    throw error;
  }
};

// 获取所有标签
const getTags = async (repository: Repository): Promise<Ref[]> => {
  try {
    const refs = await repository.getRefs();
    return refs.filter(ref => ref.type === RefType.Tag);
  } catch (error) {
    console.error('Failed to get tags:', error);
    return [];
  }
};

// 删除标签
const deleteTag = async (
  repository: Repository,
  name: string
): Promise<void> => {
  try {
    await repository.deleteTag(name);
    console.log(`Tag '${name}' deleted`);
  } catch (error) {
    console.error('Failed to delete tag:', error);
    throw error;
  }
};

储藏操作

typescript
// 储藏更改
const stashChanges = async (
  repository: Repository,
  message?: string,
  includeUntracked = false
): Promise<void> => {
  try {
    await repository.createStash(message, includeUntracked);
    console.log('Changes stashed');
  } catch (error) {
    console.error('Failed to stash changes:', error);
    throw error;
  }
};

// 应用储藏
const applyStash = async (
  repository: Repository,
  index = 0
): Promise<void> => {
  try {
    await repository.popStash(index);
    console.log('Stash applied');
  } catch (error) {
    console.error('Failed to apply stash:', error);
    throw error;
  }
};

// 获取储藏列表
const getStashes = async (repository: Repository): Promise<Stash[]> => {
  try {
    return await repository.getStashes();
  } catch (error) {
    console.error('Failed to get stashes:', error);
    return [];
  }
};

interface Stash {
  readonly index: number;
  readonly description: string;
}

高级功能

Git 钩子

typescript
class GitHookManager {
  private repository: Repository;
  
  constructor(repository: Repository) {
    this.repository = repository;
  }
  
  // 安装预提交钩子
  async installPreCommitHook(script: string): Promise<void> {
    const hookPath = Uri.joinPath(
      this.repository.rootUri,
      '.git',
      'hooks',
      'pre-commit'
    );
    
    await workspace.fs.writeFile(hookPath, Buffer.from(script, 'utf8'));
    
    // 设置执行权限(在支持的平台上)
    if (process.platform !== 'win32') {
      await this.setExecutablePermission(hookPath);
    }
  }
  
  // 安装提交消息钩子
  async installCommitMsgHook(script: string): Promise<void> {
    const hookPath = Uri.joinPath(
      this.repository.rootUri,
      '.git',
      'hooks',
      'commit-msg'
    );
    
    await workspace.fs.writeFile(hookPath, Buffer.from(script, 'utf8'));
    
    if (process.platform !== 'win32') {
      await this.setExecutablePermission(hookPath);
    }
  }
  
  private async setExecutablePermission(uri: Uri): Promise<void> {
    // 实现设置文件执行权限的逻辑
    // 这通常需要调用系统命令或使用 Node.js fs 模块
  }
}

子模块管理

typescript
class SubmoduleManager {
  private repository: Repository;
  
  constructor(repository: Repository) {
    this.repository = repository;
  }
  
  // 添加子模块
  async addSubmodule(url: string, path: string): Promise<void> {
    try {
      await this.repository.addSubmodule(url, path);
      console.log(`Submodule added: ${path}`);
    } catch (error) {
      console.error('Failed to add submodule:', error);
      throw error;
    }
  }
  
  // 初始化子模块
  async initSubmodules(): Promise<void> {
    try {
      await this.repository.syncSubmodules();
      console.log('Submodules initialized');
    } catch (error) {
      console.error('Failed to initialize submodules:', error);
      throw error;
    }
  }
  
  // 更新子模块
  async updateSubmodules(): Promise<void> {
    try {
      const submodules = this.repository.state.submodules;
      
      for (const submodule of submodules) {
        await this.repository.updateSubmodule(submodule.path);
      }
      
      console.log('Submodules updated');
    } catch (error) {
      console.error('Failed to update submodules:', error);
      throw error;
    }
  }
}

Git 工作流自动化

typescript
class GitWorkflow {
  private repository: Repository;
  
  constructor(repository: Repository) {
    this.repository = repository;
  }
  
  // 功能分支工作流
  async createFeatureBranch(featureName: string): Promise<void> {
    // 确保在主分支上
    await this.repository.checkout('main');
    
    // 拉取最新更改
    await this.repository.pull();
    
    // 创建并切换到功能分支
    const branchName = `feature/${featureName}`;
    await this.repository.createBranch(branchName, true);
    
    console.log(`Feature branch '${branchName}' created`);
  }
  
  // 完成功能分支
  async finishFeatureBranch(featureName: string): Promise<void> {
    const branchName = `feature/${featureName}`;
    
    // 切换到主分支
    await this.repository.checkout('main');
    
    // 拉取最新更改
    await this.repository.pull();
    
    // 合并功能分支
    await this.repository.merge(branchName);
    
    // 推送更改
    await this.repository.push();
    
    // 删除功能分支
    await this.repository.deleteBranch(branchName);
    
    console.log(`Feature branch '${branchName}' finished`);
  }
  
  // 发布工作流
  async createRelease(version: string): Promise<void> {
    // 创建发布分支
    const releaseBranch = `release/${version}`;
    await this.repository.createBranch(releaseBranch, true);
    
    // 创建版本标签
    await this.repository.tag(`v${version}`, `Release version ${version}`);
    
    // 推送分支和标签
    await this.repository.push('origin', releaseBranch);
    await this.repository.pushTags();
    
    console.log(`Release ${version} created`);
  }
}

事件监听

仓库事件

typescript
class GitEventListener {
  private repository: Repository;
  private disposables: Disposable[] = [];
  
  constructor(repository: Repository) {
    this.repository = repository;
    this.setupListeners();
  }
  
  private setupListeners(): void {
    // 监听仓库状态变化
    this.disposables.push(
      this.repository.state.onDidChange(() => {
        this.handleStateChange();
      })
    );
    
    // 监听分支变化
    this.disposables.push(
      this.repository.onDidChangeState(() => {
        this.handleBranchChange();
      })
    );
  }
  
  private handleStateChange(): void {
    const state = this.repository.state;
    
    console.log('Repository state changed:');
    console.log('- Working tree changes:', state.workingTreeChanges.length);
    console.log('- Index changes:', state.indexChanges.length);
    console.log('- Current branch:', state.HEAD?.name || 'detached');
  }
  
  private handleBranchChange(): void {
    const currentBranch = this.repository.state.HEAD;
    console.log('Branch changed to:', currentBranch?.name || 'detached');
  }
  
  dispose(): void {
    this.disposables.forEach(d => d.dispose());
    this.disposables = [];
  }
}

错误处理

Git 操作错误处理

typescript
class GitError extends Error {
  constructor(
    message: string,
    public readonly operation: string,
    public readonly repository: Repository,
    public readonly originalError?: Error
  ) {
    super(message);
    this.name = 'GitError';
  }
}

const safeGitOperation = async <T>(
  operation: () => Promise<T>,
  operationName: string,
  repository: Repository
): Promise<T> => {
  try {
    return await operation();
  } catch (error) {
    throw new GitError(
      `Git ${operationName} failed: ${error.message}`,
      operationName,
      repository,
      error
    );
  }
};

// 使用示例
const safeCommit = async (
  repository: Repository,
  message: string
): Promise<void> => {
  return safeGitOperation(
    () => repository.commit(message),
    'commit',
    repository
  );
};

性能优化

Git 操作缓存

typescript
class GitCache {
  private branchCache = new Map<string, Branch[]>();
  private commitCache = new Map<string, Commit[]>();
  private cacheTimeout = 30000; // 30 seconds
  
  async getBranches(repository: Repository): Promise<Branch[]> {
    const key = repository.rootUri.toString();
    const cached = this.branchCache.get(key);
    
    if (cached) {
      return cached;
    }
    
    const branches = await repository.getBranches();
    this.branchCache.set(key, branches);
    
    // 设置缓存过期
    setTimeout(() => {
      this.branchCache.delete(key);
    }, this.cacheTimeout);
    
    return branches;
  }
  
  async getCommits(
    repository: Repository,
    options?: LogOptions
  ): Promise<Commit[]> {
    const key = `${repository.rootUri.toString()}-${JSON.stringify(options)}`;
    const cached = this.commitCache.get(key);
    
    if (cached) {
      return cached;
    }
    
    const commits = await repository.log(options);
    this.commitCache.set(key, commits);
    
    setTimeout(() => {
      this.commitCache.delete(key);
    }, this.cacheTimeout);
    
    return commits;
  }
  
  invalidate(repository: Repository): void {
    const prefix = repository.rootUri.toString();
    
    for (const key of this.branchCache.keys()) {
      if (key.startsWith(prefix)) {
        this.branchCache.delete(key);
      }
    }
    
    for (const key of this.commitCache.keys()) {
      if (key.startsWith(prefix)) {
        this.commitCache.delete(key);
      }
    }
  }
}

相关 API

示例项目

查看 Git API 示例 了解完整的实现示例。

您的终极 AI 驱动 IDE 学习指南