Skip to content

Commit 4ece664

Browse files
✨ Alpha 7: Added HistoryManager for commit visualization and comparison
1 parent 63fc666 commit 4ece664

File tree

2 files changed

+234
-5
lines changed

2 files changed

+234
-5
lines changed

src/config/commandsList.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,21 +331,70 @@ export const COMMANDS_LIST: PlainGitCommand[] = [
331331
handler: 'RemoteManager.syncAll',
332332
},
333333

334-
// 🕓 History & Diff
334+
// 🕓 History & Insights
335335
{
336336
category: 'History',
337-
name: '🕓 View commit history (graph)',
337+
name: '📜 View commit history (graph)',
338338
command: 'git log --oneline --graph --decorate',
339-
description: 'Show commits with visual branch structure.',
339+
description: 'View commit history in various formats (compact, detailed, graph).',
340340
handler: 'HistoryManager.showHistoryGraph',
341341
},
342342
{
343343
category: 'History',
344-
name: '🔍 Compare changes (diff)',
344+
name: '🧾 View reflog (actions history)',
345+
command: 'git reflog',
346+
description: 'View reference log of all actions like reset, merge, rebase, etc.',
347+
handler: 'HistoryManager.showReflog',
348+
},
349+
{
350+
category: 'History',
351+
name: '🔍 View specific commit details',
352+
command: 'git show <commit-hash>',
353+
description: 'Inspect a specific commit in detail.',
354+
handler: 'HistoryManager.showCommitDetails',
355+
},
356+
{
357+
category: 'History',
358+
name: '🔁 Compare two commits (diff)',
359+
command: 'git diff <commit1> <commit2>',
360+
description: 'Compare changes between two commits interactively.',
361+
handler: 'HistoryManager.compareCommits',
362+
},
363+
{
364+
category: 'History',
365+
name: '🔍 View working directory diff',
345366
command: 'git diff',
346367
description: 'Compare working directory with last commit.',
347368
handler: 'HistoryManager.showDiff',
348369
},
370+
{
371+
category: 'History',
372+
name: '🧩 View diff for a specific file',
373+
command: 'git diff <file>',
374+
description: 'View differences for a specific tracked file.',
375+
handler: 'HistoryManager.showFileDiff',
376+
},
377+
{
378+
category: 'History',
379+
name: '📂 View commit history for a file',
380+
command: 'git log --oneline -- <file>',
381+
description: 'Show commits that affected a specific file.',
382+
handler: 'HistoryManager.showFileHistory',
383+
},
384+
{
385+
category: 'History',
386+
name: '👤 Blame a file (line history)',
387+
command: 'git blame <file>',
388+
description: 'Show who last modified each line of a file.',
389+
handler: 'HistoryManager.blameFile',
390+
},
391+
{
392+
category: 'History',
393+
name: '🧑‍💻 Show author summary (shortlog)',
394+
command: 'git shortlog -sn --all',
395+
description: 'Display commit counts by each contributor.',
396+
handler: 'HistoryManager.showAuthorSummary',
397+
},
349398

350399
// 🧹 Reset & Cleanup
351400
{

src/managers/HistoryManager.ts

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,181 @@
1-
export const HistoryManager = {}
1+
/**
2+
* 🕓 HistoryManager.ts
3+
* -------------------------------------------------------------
4+
* Provides detailed insights into commit history, diffs,
5+
* authorship, and file evolution.
6+
* -------------------------------------------------------------
7+
*/
8+
9+
import inquirer from 'inquirer';
10+
import chalk from 'chalk';
11+
import { execSync } from 'child_process';
12+
import { GitExecutor } from '../core/GitExecutor';
13+
import { Logger } from '../utils/Logger';
14+
15+
16+
/**
17+
* Helper: fetch recent commits (for interactive selection)
18+
*/
19+
function getRecentCommits(limit = 20): string[] {
20+
try {
21+
const out = execSync(`git log --oneline -n ${limit}`, { encoding: 'utf-8' });
22+
return out.split('\n').filter(Boolean);
23+
} catch {
24+
return [];
25+
}
26+
}
27+
28+
/**
29+
* Helper: get tracked files
30+
*/
31+
function getTrackedFiles(): string[] {
32+
try {
33+
const out = execSync('git ls-files', { encoding: 'utf-8' });
34+
return out.split('\n').filter(Boolean);
35+
} catch {
36+
return [];
37+
}
38+
}
39+
40+
export const HistoryManager = {
41+
/**
42+
* 📜 View commit history
43+
*/
44+
async showHistoryGraph() {
45+
const { format } = await inquirer.prompt([
46+
{
47+
type: 'list',
48+
name: 'format',
49+
message: 'Select log format:',
50+
choices: [
51+
{ name: 'Compact view (oneline)', value: '--oneline' },
52+
{ name: 'Graph view', value: '--oneline --graph --decorate' },
53+
{ name: 'Detailed view', value: '' },
54+
{ name: 'Include author and date', value: "--pretty=format:'%h - %an, %ar : %s'" },
55+
],
56+
},
57+
]);
58+
59+
const cmd = `git log ${format}`;
60+
Logger.info('🕓 Showing commit history...');
61+
await GitExecutor.run(cmd);
62+
},
63+
64+
/**
65+
* 🧾 View reflog (actions like reset, merge, etc.)
66+
*/
67+
async showReflog() {
68+
Logger.info('🧾 Viewing Git reflog...');
69+
await GitExecutor.run('git reflog --date=relative');
70+
},
71+
72+
/**
73+
* 🔍 Show commit details
74+
*/
75+
async showCommitDetails() {
76+
const commits = getRecentCommits();
77+
if (!commits.length) {
78+
Logger.info('⚠️ No commits found.');
79+
return;
80+
}
81+
82+
const { commit } = await inquirer.prompt([
83+
{ type: 'list', name: 'commit', message: 'Select commit to view:', choices: commits },
84+
]);
85+
86+
const commitHash = commit.split(' ')[0];
87+
Logger.info(`🔍 Showing details for commit ${chalk.bold(commitHash)}...`);
88+
await GitExecutor.run(`git show ${commitHash} --stat`);
89+
},
90+
91+
/**
92+
* 🔁 Compare changes between two commits
93+
*/
94+
async compareCommits() {
95+
const commits = getRecentCommits(30);
96+
if (commits.length < 2) {
97+
Logger.info('⚠️ Need at least two commits to compare.');
98+
return;
99+
}
100+
101+
const { commit1, commit2 } = await inquirer.prompt([
102+
{ type: 'list', name: 'commit1', message: 'Select first commit:', choices: commits },
103+
{ type: 'list', name: 'commit2', message: 'Select second commit:', choices: commits },
104+
]);
105+
106+
const hash1 = commit1.split(' ')[0];
107+
const hash2 = commit2.split(' ')[0];
108+
Logger.info(`🔁 Comparing commits ${hash1}${hash2}...`);
109+
await GitExecutor.run(`git diff ${hash1} ${hash2}`);
110+
},
111+
112+
/**
113+
* 🔍 Compare working directory with last commit
114+
*/
115+
async showDiff() {
116+
Logger.info('🔍 Comparing working directory with last commit...');
117+
await GitExecutor.run('git diff');
118+
},
119+
120+
/**
121+
* 🧩 Show diff for a specific file
122+
*/
123+
async showFileDiff() {
124+
const files = getTrackedFiles();
125+
if (!files.length) {
126+
Logger.info('⚠️ No tracked files found.');
127+
return;
128+
}
129+
130+
const { file } = await inquirer.prompt([
131+
{ type: 'list', name: 'file', message: 'Select file to view diff:', choices: files },
132+
]);
133+
134+
Logger.info(`🧩 Showing changes for file '${file}'...`);
135+
await GitExecutor.run(`git diff ${file}`);
136+
},
137+
138+
/**
139+
* 📂 Show history for a specific file
140+
*/
141+
async showFileHistory() {
142+
const files = getTrackedFiles();
143+
if (!files.length) {
144+
Logger.info('⚠️ No tracked files found.');
145+
return;
146+
}
147+
148+
const { file } = await inquirer.prompt([
149+
{ type: 'list', name: 'file', message: 'Select file to view history:', choices: files },
150+
]);
151+
152+
Logger.info(`📂 Showing commit history for '${file}'...`);
153+
await GitExecutor.run(`git log --oneline --graph --decorate -- ${file}`);
154+
},
155+
156+
/**
157+
* 👤 Blame a file (see who changed each line)
158+
*/
159+
async blameFile() {
160+
const files = getTrackedFiles();
161+
if (!files.length) {
162+
Logger.info('⚠️ No tracked files found.');
163+
return;
164+
}
165+
166+
const { file } = await inquirer.prompt([
167+
{ type: 'list', name: 'file', message: 'Select file to blame:', choices: files },
168+
]);
169+
170+
Logger.info(`👤 Blaming file '${file}'...`);
171+
await GitExecutor.run(`git blame ${file}`);
172+
},
173+
174+
/**
175+
* 🧑‍💻 Shortlog by author
176+
*/
177+
async showAuthorSummary() {
178+
Logger.info('🧑‍💻 Generating author commit summary...');
179+
await GitExecutor.run('git shortlog -sn --all');
180+
},
181+
};

0 commit comments

Comments
 (0)