git-suggest
Version:
A lightweight command-line tool that automatically generates contextual, high-quality Git commit messages based on your staged code changes. Powered by GitHub Copilot CLI, it helps you write smarter commits with less typing.
124 lines • 4.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitUtils = void 0;
const child_process_1 = require("child_process");
class GitUtils {
static async getStagedChanges() {
try {
const statusOutput = (0, child_process_1.execSync)('git status --porcelain --staged', {
encoding: 'utf8',
cwd: process.cwd()
});
if (!statusOutput.trim()) {
throw new Error('No staged changes found. Please stage your changes with "git add" first.');
}
const changes = [];
const lines = statusOutput.trim().split('\n');
for (const line of lines) {
const status = line.substring(0, 2);
const file = line.substring(3);
let changeType;
if (status.includes('A'))
changeType = 'added';
else if (status.includes('M'))
changeType = 'modified';
else if (status.includes('D'))
changeType = 'deleted';
else if (status.includes('R'))
changeType = 'renamed';
else
changeType = 'modified';
const stats = await this.getFileStats(file, changeType);
const diff = await this.getFileDiff(file, changeType);
changes.push({
file,
status: changeType,
additions: stats.additions,
deletions: stats.deletions,
diff
});
}
return changes;
}
catch (error) {
if (error instanceof Error && error.message.includes('not a git repository')) {
throw new Error('Not in a Git repository. Please run this command from within a Git repository.');
}
throw error;
}
}
static async getFileStats(file, status) {
try {
if (status === 'deleted') {
return { additions: 0, deletions: 0 };
}
const output = (0, child_process_1.execSync)(`git diff --cached --numstat "${file}"`, {
encoding: 'utf8',
cwd: process.cwd()
});
const [additions, deletions] = output.trim().split('\t').map(n => parseInt(n) || 0);
return { additions, deletions };
}
catch {
return { additions: 0, deletions: 0 };
}
}
static async getFileDiff(file, status) {
try {
if (status === 'deleted') {
return `File deleted: ${file}`;
}
const output = (0, child_process_1.execSync)(`git diff --cached "${file}"`, {
encoding: 'utf8',
cwd: process.cwd(),
maxBuffer: 1024 * 1024 // 1MB limit for diff output
});
return output.trim();
}
catch {
return `Unable to get diff for ${file}`;
}
}
static async getCurrentBranch() {
try {
const branch = (0, child_process_1.execSync)('git branch --show-current', {
encoding: 'utf8',
cwd: process.cwd()
});
return branch.trim();
}
catch {
return 'main';
}
}
static async getRecentCommits(count = 5) {
try {
const output = (0, child_process_1.execSync)(`git log --oneline -n ${count}`, {
encoding: 'utf8',
cwd: process.cwd()
});
return output.trim().split('\n').filter(line => line.trim());
}
catch {
return [];
}
}
static async getRepositoryContext() {
try {
const remoteOutput = (0, child_process_1.execSync)('git remote get-url origin', {
encoding: 'utf8',
cwd: process.cwd()
});
const remote = remoteOutput.trim();
const name = remote.split('/').pop()?.replace('.git', '') || 'unknown';
return { name, remote };
}
catch {
const pwd = process.cwd();
const name = pwd.split('/').pop() || 'unknown';
return { name };
}
}
}
exports.GitUtils = GitUtils;
//# sourceMappingURL=git.js.map