Update from Git Manager GUI

This commit is contained in:
2026-02-02 17:55:33 +01:00
parent fd868ea238
commit fca9d9c66f
2 changed files with 635 additions and 2 deletions

View File

@@ -54,4 +54,282 @@ async function getCommitLogs(folderPath, count = 50) {
return log.all.map(c => `${c.hash.substring(0,7)} - ${c.message}`);
}
module.exports = { initRepo, commitAndPush, getBranches, getCommitLogs };
/* ================================
EXTENDED COMMIT HISTORY FUNCTIONS
================================ */
/**
* Get detailed commit history with full information
*/
async function getDetailedCommitHistory(folderPath, options = {}) {
const git = gitFor(folderPath);
const logOptions = {
maxCount: options.limit || 100,
file: options.file || undefined
};
if (options.author) {
logOptions['--author'] = options.author;
}
if (options.since) {
logOptions['--since'] = options.since;
}
if (options.until) {
logOptions['--until'] = options.until;
}
if (options.grep) {
logOptions['--grep'] = options.grep;
}
const log = await git.log(logOptions);
return log.all.map(commit => ({
hash: commit.hash,
shortHash: commit.hash.substring(0, 7),
author: commit.author_name,
authorEmail: commit.author_email,
date: commit.date,
message: commit.message,
body: commit.body,
refs: commit.refs || '',
parentHashes: commit.parent || []
}));
}
/**
* Get commit diff for a specific commit
*/
async function getCommitDiff(folderPath, commitHash) {
const git = gitFor(folderPath);
try {
// Get diff from parent to this commit
const diff = await git.diff([`${commitHash}~1`, commitHash]);
return diff;
} catch (error) {
// If no parent (first commit), show diff from empty tree
try {
const diff = await git.diff(['--root', commitHash]);
return diff;
} catch (err) {
console.error('Error getting diff:', err);
return '';
}
}
}
/**
* Get file changes for a specific commit
*/
async function getCommitFileChanges(folderPath, commitHash) {
const git = gitFor(folderPath);
try {
const diff = await git.diffSummary([`${commitHash}~1`, commitHash]);
return {
files: diff.files.map(file => ({
file: file.file,
changes: file.changes,
insertions: file.insertions,
deletions: file.deletions,
binary: file.binary || false
})),
insertions: diff.insertions,
deletions: diff.deletions,
changed: diff.changed
};
} catch (error) {
// First commit case
try {
const diff = await git.diffSummary(['--root', commitHash]);
return {
files: diff.files.map(file => ({
file: file.file,
changes: file.changes,
insertions: file.insertions,
deletions: file.deletions,
binary: file.binary || false
})),
insertions: diff.insertions,
deletions: diff.deletions,
changed: diff.changed
};
} catch (err) {
console.error('Error getting file changes:', err);
return { files: [], insertions: 0, deletions: 0, changed: 0 };
}
}
}
/**
* Get detailed commit info including stats
*/
async function getCommitDetails(folderPath, commitHash) {
const git = gitFor(folderPath);
try {
const log = await git.log({ from: commitHash, to: commitHash, maxCount: 1 });
if (log.all.length === 0) {
throw new Error('Commit not found');
}
const commit = log.all[0];
const fileChanges = await getCommitFileChanges(folderPath, commitHash);
const diff = await getCommitDiff(folderPath, commitHash);
return {
hash: commit.hash,
shortHash: commit.hash.substring(0, 7),
author: commit.author_name,
authorEmail: commit.author_email,
date: commit.date,
message: commit.message,
body: commit.body,
refs: commit.refs || '',
parentHashes: commit.parent || [],
fileChanges,
diff
};
} catch (error) {
console.error('Error getting commit details:', error);
throw error;
}
}
/**
* Get branch graph data for visualization
*/
async function getBranchGraph(folderPath, limit = 50) {
const git = gitFor(folderPath);
try {
// Get all branches
const branches = await git.branchLocal();
const allBranches = branches.all;
// Get graph structure
const log = await git.log({
maxCount: limit,
'--all': null,
'--graph': null,
'--decorate': null,
'--oneline': null
});
return {
branches: allBranches,
current: branches.current,
commits: log.all
};
} catch (error) {
console.error('Error getting branch graph:', error);
return { branches: [], current: '', commits: [] };
}
}
/**
* Search commits by message, author, or content
*/
async function searchCommits(folderPath, query, options = {}) {
const git = gitFor(folderPath);
const logOptions = {
maxCount: options.limit || 100,
'--all': null
};
// Search in commit message
if (options.searchMessage !== false) {
logOptions['--grep'] = query;
}
// Search by author
if (options.author) {
logOptions['--author'] = options.author;
}
// Case insensitive
if (options.caseInsensitive !== false) {
logOptions['--regexp-ignore-case'] = null;
}
try {
const log = await git.log(logOptions);
return log.all.map(commit => ({
hash: commit.hash,
shortHash: commit.hash.substring(0, 7),
author: commit.author_name,
authorEmail: commit.author_email,
date: commit.date,
message: commit.message,
body: commit.body,
refs: commit.refs || ''
}));
} catch (error) {
console.error('Error searching commits:', error);
return [];
}
}
/**
* Get commit statistics
*/
async function getCommitStats(folderPath, since = '1 month ago') {
const git = gitFor(folderPath);
try {
const log = await git.log({
'--since': since,
'--all': null
});
const authorStats = {};
const dailyStats = {};
log.all.forEach(commit => {
// Author stats
const author = commit.author_name;
if (!authorStats[author]) {
authorStats[author] = { commits: 0, email: commit.author_email };
}
authorStats[author].commits++;
// Daily stats
const date = new Date(commit.date).toISOString().split('T')[0];
if (!dailyStats[date]) {
dailyStats[date] = 0;
}
dailyStats[date]++;
});
return {
totalCommits: log.all.length,
authors: authorStats,
daily: dailyStats
};
} catch (error) {
console.error('Error getting commit stats:', error);
return { totalCommits: 0, authors: {}, daily: {} };
}
}
module.exports = {
initRepo,
commitAndPush,
getBranches,
getCommitLogs,
getDetailedCommitHistory,
getCommitDiff,
getCommitFileChanges,
getCommitDetails,
getBranchGraph,
searchCommits,
getCommitStats
};