@morodomi/ait3
Version:
AIT³ Development Platform - AI + Ticket + Test + Tool driven development methodology
100 lines (99 loc) • 3.77 kB
JavaScript
import { simpleGit } from 'simple-git';
export class SimpleGitService {
git;
constructor(basePath) {
this.git = simpleGit(basePath);
}
async isRepository() {
try {
return await this.git.checkIsRepo();
}
catch {
return false;
}
}
async hasUncommittedChanges() {
const status = await this.git.status();
return status.files.length > 0;
}
async fetch() {
await this.git.fetch();
}
async findBranches(pattern) {
const branchSummary = await this.git.branch(['-a']);
return branchSummary.all
.filter(branch => branch.includes(pattern))
.map(branch => this.cleanBranchName(branch));
}
cleanBranchName(branch) {
// Convert remotes/origin/feature/xxx to origin/feature/xxx
if (branch.startsWith('remotes/')) {
return branch.replace('remotes/', '');
}
return branch;
}
async createBranch(name) {
await this.git.checkoutBranch(name, 'HEAD');
}
async checkout(name) {
await this.git.checkout(name);
}
async getCurrentBranch() {
const result = await this.git.revparse(['--abbrev-ref', 'HEAD']);
return result.trim();
}
async getMergeBase(branch1, branch2) {
const result = await this.git.raw(['merge-base', branch1, branch2]);
return result.trim();
}
async getCommits(base) {
const log = await this.git.log({ from: base, to: 'HEAD' });
return log.all.map(commit => ({
hash: commit.hash,
message: commit.message
}));
}
async moveFile(oldPath, newPath) {
try {
await this.git.raw(['mv', oldPath, newPath]);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
// Enhanced error classification for better debugging
if (errorMessage.includes('does not exist in index')) {
throw new Error(`Git file not tracked: ${oldPath} is not under version control`);
}
if (errorMessage.includes('Permission denied')) {
throw new Error(`Permission denied: Cannot move ${oldPath} to ${newPath}`);
}
if (errorMessage.includes('destination already exists')) {
throw new Error(`Destination exists: ${newPath} already exists`);
}
if (errorMessage.includes('fatal: not a git repository')) {
throw new Error('Not a Git repository: Cannot use git mv outside a Git repository');
}
// Re-throw original error with additional context
throw new Error(`Git move failed: ${errorMessage}`);
}
}
async removeFile(filePath) {
try {
await this.git.raw(['rm', filePath]);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
// Enhanced error classification for better debugging
if (errorMessage.includes('does not exist in index')) {
throw new Error(`Git file not tracked: ${filePath} is not under version control`);
}
if (errorMessage.includes('Permission denied')) {
throw new Error(`Permission denied: Cannot remove ${filePath}`);
}
if (errorMessage.includes('fatal: not a git repository')) {
throw new Error('Not a Git repository: Cannot use git rm outside a Git repository');
}
// Re-throw original error with additional context
throw new Error(`Git remove failed: ${errorMessage}`);
}
}
}