@akiojin/claude-worktree
Version:
Interactive Git worktree manager for Claude Code with graphical branch selection
117 lines • 3.57 kB
JavaScript
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