UNPKG

@akiojin/claude-worktree

Version:

Interactive Git worktree manager for Claude Code with graphical branch selection

117 lines 3.57 kB
import { execa } from 'execa'; import { GitError } from '../git.js'; /** * Git操作のための低レベルRepository * execaの直接呼び出しをカプセル化 */ export class GitRepository { async execute(args, options) { try { const { stdout } = await execa('git', args, options); return stdout; } catch (error) { throw new GitError(`Git command failed: git ${args.join(' ')}`, error); } } async isRepository() { try { await this.execute(['rev-parse', '--git-dir']); return true; } catch { return false; } } async getRepositoryRoot() { const stdout = await this.execute(['rev-parse', '--show-toplevel']); return stdout.trim(); } async getCurrentBranch() { try { const stdout = await this.execute(['branch', '--show-current']); return stdout.trim() || null; } catch { return null; } } async getBranches(options) { const args = ['branch']; if (options.remote) { args.push('-r'); } args.push('--format=%(refname:short)'); const stdout = await this.execute(args); return stdout .split('\n') .filter(line => line.trim()) .filter(line => !line.includes('HEAD')); } async createBranch(branchName, baseBranch) { const args = ['checkout', '-b', branchName]; if (baseBranch) { args.push(baseBranch); } await this.execute(args); } async deleteBranch(branchName, force = false) { const args = ['branch', force ? '-D' : '-d', branchName]; await this.execute(args); } async deleteRemoteBranch(branchName) { await this.execute(['push', 'origin', '--delete', branchName]); } async getStatus(options) { return await this.execute(['status', '--porcelain'], options?.cwd ? options : undefined); } async hasChanges(workdir) { const status = await this.getStatus(workdir ? { cwd: workdir } : undefined); return status.trim().length > 0; } async fetch(options) { const args = ['fetch']; if (options?.all) args.push('--all'); if (options?.prune) args.push('--prune'); await this.execute(args); } async push(options) { const args = ['push']; if (options?.upstream && options?.branch) { args.push('--set-upstream', 'origin', options.branch); } await this.execute(args); } async commit(message, options) { const args = ['commit', '-m', message]; if (options?.all) args.push('-a'); await this.execute(args); } async add(files) { const args = ['add']; if (Array.isArray(files)) { args.push(...files); } else { args.push(files); } await this.execute(args); } async stash(message) { const args = ['stash', 'push']; if (message) args.push('-m', message); await this.execute(args); } async checkout(target) { await this.execute(['checkout', target]); } async getChangedFilesCount(workdir) { const status = await this.getStatus(workdir ? { cwd: workdir } : undefined); return status.split('\n').filter(line => line.trim()).length; } } //# sourceMappingURL=git.repository.js.map