git-blame-ignore 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const simple_git_1 = __importDefault(require("simple-git"));
10
+ const promises_1 = require("fs/promises");
11
+ const path_1 = require("path");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('git-blame-ignore')
15
+ .description('Auto-detects bulk-change commits and manages .git-blame-ignore-revs file')
16
+ .version('1.0.0');
17
+ program
18
+ .command('scan')
19
+ .description('Scan repository for bulk-change commits')
20
+ .option('-n, --number <number>', 'Number of commits to check (default: 50)', '50')
21
+ .option('-t, --threshold <threshold>', 'Threshold for bulk changes (default: 10)', '10')
22
+ .action(async (options) => {
23
+ try {
24
+ await scanBulkCommits(parseInt(options.number), parseInt(options.threshold));
25
+ }
26
+ catch (error) {
27
+ console.error(chalk_1.default.red('Error:'), error.message);
28
+ process.exit(1);
29
+ }
30
+ });
31
+ program
32
+ .command('ignore')
33
+ .description('Add bulk-change commits to .git-blame-ignore-revs')
34
+ .option('-c, --commits <commits>', 'Comma-separated list of commit hashes to ignore')
35
+ .option('-a, --auto', 'Auto-scan and add all detected bulk commits')
36
+ .action(async (options) => {
37
+ try {
38
+ if (options.auto) {
39
+ const bulkCommits = await scanBulkCommits(50, 10);
40
+ if (bulkCommits.length > 0) {
41
+ await addToIgnoreFile(bulkCommits.map(commit => commit.hash));
42
+ }
43
+ }
44
+ else if (options.commits) {
45
+ const commitHashes = options.commits.split(',').map((hash) => hash.trim());
46
+ await addToIgnoreFile(commitHashes);
47
+ }
48
+ else {
49
+ console.log(chalk_1.default.yellow('Please specify either --commits or --auto'));
50
+ }
51
+ }
52
+ catch (error) {
53
+ console.error(chalk_1.default.red('Error:'), error.message);
54
+ process.exit(1);
55
+ }
56
+ });
57
+ program
58
+ .command('list')
59
+ .description('List commits currently ignored in .git-blame-ignore-revs')
60
+ .action(async () => {
61
+ try {
62
+ await listIgnoredCommits();
63
+ }
64
+ catch (error) {
65
+ console.error(chalk_1.default.red('Error:'), error.message);
66
+ process.exit(1);
67
+ }
68
+ });
69
+ program
70
+ .command('remove')
71
+ .description('Remove commits from .git-blame-ignore-revs')
72
+ .option('-c, --commits <commits>', 'Comma-separated list of commit hashes to remove')
73
+ .option('-a, --all', 'Remove all ignored commits')
74
+ .action(async (options) => {
75
+ try {
76
+ if (options.all) {
77
+ await removeAllIgnoredCommits();
78
+ }
79
+ else if (options.commits) {
80
+ const commitHashes = options.commits.split(',').map((hash) => hash.trim());
81
+ await removeFromIgnoreFile(commitHashes);
82
+ }
83
+ else {
84
+ console.log(chalk_1.default.yellow('Please specify either --commits or --all'));
85
+ }
86
+ }
87
+ catch (error) {
88
+ console.error(chalk_1.default.red('Error:'), error.message);
89
+ process.exit(1);
90
+ }
91
+ });
92
+ async function scanBulkCommits(limit, threshold) {
93
+ const git = (0, simple_git_1.default)();
94
+ // Check if we're in a git repository
95
+ try {
96
+ await git.revparse(['--is-inside-work-tree']);
97
+ }
98
+ catch (error) {
99
+ throw new Error('Not a git repository');
100
+ }
101
+ console.log(chalk_1.default.blue(`Scanning last ${limit} commits for bulk changes...`));
102
+ const logOutput = await git.log(['--pretty=format:%H %s %an %ad', `--max-count=${limit}`, '--date=short']);
103
+ const commits = logOutput.all;
104
+ const bulkCommits = [];
105
+ for (const commit of commits) {
106
+ try {
107
+ // Get number of changed files in this commit
108
+ const diffSummary = await git.diffSummary([`${commit.hash}^`, commit.hash]);
109
+ const changesCount = diffSummary.files.length;
110
+ if (changesCount >= threshold) {
111
+ bulkCommits.push({
112
+ hash: commit.hash,
113
+ subject: commit.message.split('\n')[0],
114
+ author: commit.author_name,
115
+ date: commit.date,
116
+ changes: changesCount
117
+ });
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.warn(chalk_1.default.yellow(`Warning: Could not analyze commit ${commit.hash}: ${error.message}`));
122
+ }
123
+ }
124
+ if (bulkCommits.length === 0) {
125
+ console.log(chalk_1.default.green('āœ… No bulk-change commits found'));
126
+ return [];
127
+ }
128
+ console.log(chalk_1.default.blue('\nšŸ” Bulk-change commits detected:'));
129
+ console.table(bulkCommits.map(commit => ({
130
+ Hash: commit.hash.substring(0, 8),
131
+ Subject: commit.subject,
132
+ Author: commit.author,
133
+ Date: commit.date,
134
+ Changes: commit.changes
135
+ })));
136
+ return bulkCommits;
137
+ }
138
+ async function addToIgnoreFile(commitHashes) {
139
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
140
+ let existingContent = '';
141
+ try {
142
+ existingContent = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
143
+ }
144
+ catch (error) {
145
+ // File doesn't exist, that's okay
146
+ }
147
+ const newCommits = commitHashes.filter(hash => !existingContent.includes(hash));
148
+ if (newCommits.length === 0) {
149
+ console.log(chalk_1.default.green('āœ… All specified commits are already ignored'));
150
+ return;
151
+ }
152
+ const updatedContent = existingContent + (existingContent ? '\n' : '') + newCommits.join('\n') + '\n';
153
+ try {
154
+ await (0, promises_1.writeFile)(gitignorePath, updatedContent, 'utf-8');
155
+ console.log(chalk_1.default.green(`āœ… Added ${newCommits.length} commit(s) to .git-blame-ignore-revs`));
156
+ console.log(chalk_1.default.blue('šŸ’” Run `git blame --ignore-revs` to use the ignore file'));
157
+ }
158
+ catch (error) {
159
+ throw new Error(`Failed to write .git-blame-ignore-revs: ${error.message}`);
160
+ }
161
+ }
162
+ async function listIgnoredCommits() {
163
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
164
+ try {
165
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
166
+ const commits = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
167
+ if (commits.length === 0) {
168
+ console.log(chalk_1.default.yellow('No commits are currently ignored'));
169
+ return;
170
+ }
171
+ console.log(chalk_1.default.blue('šŸ“ Currently ignored commits:'));
172
+ commits.forEach((commit, index) => {
173
+ console.log(`${index + 1}. ${commit}`);
174
+ });
175
+ }
176
+ catch (error) {
177
+ throw new Error('.git-blame-ignore-revs file not found');
178
+ }
179
+ }
180
+ async function removeFromIgnoreFile(commitHashes) {
181
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
182
+ try {
183
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
184
+ const lines = content.split('\n');
185
+ const filteredLines = lines.filter(line => {
186
+ return !commitHashes.includes(line.trim());
187
+ });
188
+ const updatedContent = filteredLines.join('\n');
189
+ if (updatedContent === content) {
190
+ console.log(chalk_1.default.yellow('None of the specified commits are currently ignored'));
191
+ return;
192
+ }
193
+ await (0, promises_1.writeFile)(gitignorePath, updatedContent, 'utf-8');
194
+ console.log(chalk_1.default.green(`āœ… Removed ${commitHashes.length} commit(s) from .git-blame-ignore-revs`));
195
+ }
196
+ catch (error) {
197
+ throw new Error('.git-blame-ignore-revs file not found');
198
+ }
199
+ }
200
+ async function removeAllIgnoredCommits() {
201
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
202
+ try {
203
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
204
+ const commits = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
205
+ if (commits.length === 0) {
206
+ console.log(chalk_1.default.yellow('No commits are currently ignored'));
207
+ return;
208
+ }
209
+ // Create a backup
210
+ const backupPath = gitignorePath + '.backup';
211
+ await (0, promises_1.writeFile)(backupPath, content, 'utf-8');
212
+ // Clear the file but keep the structure
213
+ await (0, promises_1.writeFile)(gitignorePath, '# Git blame ignore file - auto-generated by git-blame-ignore\n', 'utf-8');
214
+ console.log(chalk_1.default.green(`āœ… Removed all ${commits.length} ignored commits`));
215
+ console.log(chalk_1.default.blue(`šŸ’” Backup saved to: ${backupPath}`));
216
+ }
217
+ catch (error) {
218
+ throw new Error('.git-blame-ignore-revs file not found');
219
+ }
220
+ }
221
+ program.parse();
222
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { BulkCommit } from './types';
2
+ export declare class BulkCommitScanner {
3
+ private git;
4
+ private config;
5
+ constructor(config?: {
6
+ minFilesChanged?: number;
7
+ minBulkScore?: number;
8
+ whitespaceThreshold?: number;
9
+ });
10
+ scan(): Promise<BulkCommit[]>;
11
+ private analyzeCommit;
12
+ private createEmptyCommit;
13
+ private parseLinesChanged;
14
+ private calculateWhitespaceRatio;
15
+ private getCommitMessage;
16
+ private getCommitDate;
17
+ private calculateBulkScore;
18
+ }
19
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,MAAM,CAIZ;gBAEU,MAAM,CAAC,EAAE;QACnB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B;IASK,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAwBrB,aAAa;IA2B3B,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,iBAAiB;YASX,wBAAwB;YAgBxB,gBAAgB;YAShB,aAAa;IAS3B,OAAO,CAAC,kBAAkB;CA4B3B"}
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BulkCommitScanner = void 0;
7
+ const simple_git_1 = __importDefault(require("simple-git"));
8
+ class BulkCommitScanner {
9
+ constructor(config) {
10
+ this.git = (0, simple_git_1.default)();
11
+ this.config = {
12
+ minFilesChanged: config?.minFilesChanged || 20,
13
+ minBulkScore: config?.minBulkScore || 40,
14
+ whitespaceThreshold: config?.whitespaceThreshold || 0.8,
15
+ };
16
+ }
17
+ async scan() {
18
+ try {
19
+ const log = await this.git.log({
20
+ format: '%H|%s|%ai|%P',
21
+ file: null,
22
+ n: 100
23
+ });
24
+ const commits = [];
25
+ for (const commit of log.all) {
26
+ const [hash] = commit.split('|');
27
+ const bulkCommit = await this.analyzeCommit(hash);
28
+ if (bulkCommit.bulkScore >= this.config.minBulkScore) {
29
+ commits.push(bulkCommit);
30
+ }
31
+ }
32
+ return commits.sort((a, b) => b.bulkScore - a.bulkScore);
33
+ }
34
+ catch (error) {
35
+ throw new Error(`Failed to scan commits: ${error}`);
36
+ }
37
+ }
38
+ async analyzeCommit(sha) {
39
+ const diff = await this.git.diff([`${sha}^`, sha, '--name-only']);
40
+ const files = diff.split('\n').filter(f => f.trim() !== '');
41
+ if (files.length < this.config.minFilesChanged) {
42
+ return this.createEmptyCommit(sha, files.length);
43
+ }
44
+ const stats = await this.git.diff([`${sha}^`, sha, '--stat']);
45
+ const linesChanged = this.parseLinesChanged(stats);
46
+ const whitespaceRatio = await this.calculateWhitespaceRatio(sha);
47
+ const message = await this.getCommitMessage(sha);
48
+ const bulkScore = this.calculateBulkScore(files.length, linesChanged, whitespaceRatio, message);
49
+ return {
50
+ sha,
51
+ message,
52
+ filesChanged: files.length,
53
+ linesChanged,
54
+ whitespaceRatio,
55
+ bulkScore,
56
+ date: await this.getCommitDate(sha),
57
+ };
58
+ }
59
+ createEmptyCommit(sha, filesChanged) {
60
+ return {
61
+ sha,
62
+ message: 'Unknown',
63
+ filesChanged,
64
+ linesChanged: 0,
65
+ whitespaceRatio: 0,
66
+ bulkScore: 0,
67
+ date: 'Unknown',
68
+ };
69
+ }
70
+ parseLinesChanged(stats) {
71
+ const linesMatch = stats.match(/\d+ files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
72
+ if (!linesMatch)
73
+ return 0;
74
+ const insertions = linesMatch[1] ? parseInt(linesMatch[1]) : 0;
75
+ const deletions = linesMatch[2] ? parseInt(linesMatch[2]) : 0;
76
+ return insertions + deletions;
77
+ }
78
+ async calculateWhitespaceRatio(sha) {
79
+ try {
80
+ const diff = await this.git.diff([`${sha}^`, sha, '--']);
81
+ if (!diff)
82
+ return 0;
83
+ const lines = diff.split('\n');
84
+ const whitespaceLines = lines.filter(line => line.trim() === '' && line !== 'diff --git' && !line.startsWith('index') && !line.startsWith('---') && !line.startsWith('+++')).length;
85
+ return lines.length > 0 ? whitespaceLines / lines.length : 0;
86
+ }
87
+ catch {
88
+ return 0;
89
+ }
90
+ }
91
+ async getCommitMessage(sha) {
92
+ try {
93
+ const result = await this.git.show([sha, '--format=%s', '--no-patch']);
94
+ return result.trim();
95
+ }
96
+ catch {
97
+ return 'Unknown';
98
+ }
99
+ }
100
+ async getCommitDate(sha) {
101
+ try {
102
+ const result = await this.git.show([sha, '--format=%ai', '--no-patch']);
103
+ return result.trim();
104
+ }
105
+ catch {
106
+ return 'Unknown';
107
+ }
108
+ }
109
+ calculateBulkScore(filesChanged, linesChanged, whitespaceRatio, message) {
110
+ let score = 0;
111
+ // Files changed scoring
112
+ if (filesChanged >= 50)
113
+ score += 50;
114
+ else if (filesChanged >= 30)
115
+ score += 40;
116
+ else if (filesChanged >= 20)
117
+ score += 30;
118
+ // Message scoring
119
+ const lowerMessage = message.toLowerCase();
120
+ if (lowerMessage.includes('prettier') || lowerMessage.includes('format'))
121
+ score += 20;
122
+ if (lowerMessage.includes('eslint') || lowerMessage.includes('lint'))
123
+ score += 20;
124
+ if (lowerMessage.includes('rename') || lowerMessage.includes('refactor'))
125
+ score += 20;
126
+ // Whitespace scoring
127
+ if (whitespaceRatio >= this.config.whitespaceThreshold)
128
+ score += 20;
129
+ // Lines per file scoring (if many changes but few lines per file, likely formatting)
130
+ const linesPerFile = filesChanged > 0 ? linesChanged / filesChanged : 0;
131
+ if (linesPerFile < 5)
132
+ score += 10;
133
+ return Math.min(score, 100);
134
+ }
135
+ }
136
+ exports.BulkCommitScanner = BulkCommitScanner;
137
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const simple_git_1 = __importDefault(require("simple-git"));
10
+ const promises_1 = require("fs/promises");
11
+ const path_1 = require("path");
12
+ const url_1 = require("url");
13
+ const __filename = (0, url_1.fileURLToPath)(import.meta.url);
14
+ const __dirname = (0, path_1.dirname)(__filename);
15
+ const program = new commander_1.Command();
16
+ program
17
+ .name('git-blame-ignore')
18
+ .description('Auto-detects bulk-change commits and manages .git-blame-ignore-revs file')
19
+ .version('1.0.0');
20
+ program
21
+ .command('scan')
22
+ .description('Scan repository for bulk-change commits')
23
+ .option('-n, --number <number>', 'Number of commits to check (default: 50)', '50')
24
+ .option('-t, --threshold <threshold>', 'Threshold for bulk changes (default: 10)', '10')
25
+ .action(async (options) => {
26
+ try {
27
+ await scanBulkCommits(parseInt(options.number), parseInt(options.threshold));
28
+ }
29
+ catch (error) {
30
+ console.error(chalk_1.default.red('Error:'), error.message);
31
+ process.exit(1);
32
+ }
33
+ });
34
+ program
35
+ .command('ignore')
36
+ .description('Add bulk-change commits to .git-blame-ignore-revs')
37
+ .option('-c, --commits <commits>', 'Comma-separated list of commit hashes to ignore')
38
+ .option('-a, --auto', 'Auto-scan and add all detected bulk commits')
39
+ .action(async (options) => {
40
+ try {
41
+ if (options.auto) {
42
+ const bulkCommits = await scanBulkCommits(50, 10);
43
+ if (bulkCommits.length > 0) {
44
+ await addToIgnoreFile(bulkCommits.map(commit => commit.hash));
45
+ }
46
+ }
47
+ else if (options.commits) {
48
+ const commitHashes = options.commits.split(',').map(hash => hash.trim());
49
+ await addToIgnoreFile(commitHashes);
50
+ }
51
+ else {
52
+ console.log(chalk_1.default.yellow('Please specify either --commits or --auto'));
53
+ }
54
+ }
55
+ catch (error) {
56
+ console.error(chalk_1.default.red('Error:'), error.message);
57
+ process.exit(1);
58
+ }
59
+ });
60
+ program
61
+ .command('list')
62
+ .description('List commits currently ignored in .git-blame-ignore-revs')
63
+ .action(async () => {
64
+ try {
65
+ await listIgnoredCommits();
66
+ }
67
+ catch (error) {
68
+ console.error(chalk_1.default.red('Error:'), error.message);
69
+ process.exit(1);
70
+ }
71
+ });
72
+ program
73
+ .command('remove')
74
+ .description('Remove commits from .git-blame-ignore-revs')
75
+ .option('-c, --commits <commits>', 'Comma-separated list of commit hashes to remove')
76
+ .option('-a, --all', 'Remove all ignored commits')
77
+ .action(async (options) => {
78
+ try {
79
+ if (options.all) {
80
+ await removeAllIgnoredCommits();
81
+ }
82
+ else if (options.commits) {
83
+ const commitHashes = options.commits.split(',').map(hash => hash.trim());
84
+ await removeFromIgnoreFile(commitHashes);
85
+ }
86
+ else {
87
+ console.log(chalk_1.default.yellow('Please specify either --commits or --all'));
88
+ }
89
+ }
90
+ catch (error) {
91
+ console.error(chalk_1.default.red('Error:'), error.message);
92
+ process.exit(1);
93
+ }
94
+ });
95
+ async function scanBulkCommits(limit, threshold) {
96
+ const git = (0, simple_git_1.default)();
97
+ try {
98
+ await git.revparse(['--is-inside-work-tree']);
99
+ }
100
+ catch (error) {
101
+ throw new Error('Not a git repository');
102
+ }
103
+ console.log(chalk_1.default.blue(`Scanning last ${limit} commits for bulk changes...`));
104
+ const logOutput = await git.log(['--pretty=format:%H %s %an %ad', `--max-count=${limit}`, '--date=short']);
105
+ const commits = logOutput.all;
106
+ const bulkCommits = [];
107
+ for (const commit of commits) {
108
+ try {
109
+ const diffSummary = await git.diffSummary([`${commit.hash}^`, commit.hash]);
110
+ const changesCount = diffSummary.files.length;
111
+ if (changesCount >= threshold) {
112
+ bulkCommits.push({
113
+ hash: commit.hash,
114
+ subject: commit.message.split('\n')[0],
115
+ author: commit.author_name,
116
+ date: commit.date,
117
+ changes: changesCount
118
+ });
119
+ }
120
+ }
121
+ catch (error) {
122
+ console.warn(chalk_1.default.yellow(`Warning: Could not analyze commit ${commit.hash}: ${error.message}`));
123
+ }
124
+ }
125
+ if (bulkCommits.length === 0) {
126
+ console.log(chalk_1.default.green('āœ… No bulk-change commits found'));
127
+ return [];
128
+ }
129
+ console.log(chalk_1.default.blue('\nšŸ” Bulk-change commits detected:'));
130
+ console.table(bulkCommits.map(commit => ({
131
+ Hash: commit.hash.substring(0, 8),
132
+ Subject: commit.subject,
133
+ Author: commit.author,
134
+ Date: commit.date,
135
+ Changes: commit.changes
136
+ })));
137
+ return bulkCommits;
138
+ }
139
+ async function addToIgnoreFile(commitHashes) {
140
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
141
+ let existingContent = '';
142
+ try {
143
+ existingContent = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
144
+ }
145
+ catch (error) {
146
+ }
147
+ const newCommits = commitHashes.filter(hash => !existingContent.includes(hash));
148
+ if (newCommits.length === 0) {
149
+ console.log(chalk_1.default.green('āœ… All specified commits are already ignored'));
150
+ return;
151
+ }
152
+ const updatedContent = existingContent + (existingContent ? '\n' : '') + newCommits.join('\n') + '\n';
153
+ try {
154
+ await (0, promises_1.writeFile)(gitignorePath, updatedContent, 'utf-8');
155
+ console.log(chalk_1.default.green(`āœ… Added ${newCommits.length} commit(s) to .git-blame-ignore-revs`));
156
+ console.log(chalk_1.default.blue('šŸ’” Run `git blame --ignore-revs` to use the ignore file'));
157
+ }
158
+ catch (error) {
159
+ throw new Error(`Failed to write .git-blame-ignore-revs: ${error.message}`);
160
+ }
161
+ }
162
+ async function listIgnoredCommits() {
163
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
164
+ try {
165
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
166
+ const commits = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
167
+ if (commits.length === 0) {
168
+ console.log(chalk_1.default.yellow('No commits are currently ignored'));
169
+ return;
170
+ }
171
+ console.log(chalk_1.default.blue('šŸ“ Currently ignored commits:'));
172
+ commits.forEach((commit, index) => {
173
+ console.log(`${index + 1}. ${commit}`);
174
+ });
175
+ }
176
+ catch (error) {
177
+ throw new Error('.git-blame-ignore-revs file not found');
178
+ }
179
+ }
180
+ async function removeFromIgnoreFile(commitHashes) {
181
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
182
+ try {
183
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
184
+ const lines = content.split('\n');
185
+ const filteredLines = lines.filter(line => {
186
+ return !commitHashes.includes(line.trim());
187
+ });
188
+ const updatedContent = filteredLines.join('\n');
189
+ if (updatedContent === content) {
190
+ console.log(chalk_1.default.yellow('None of the specified commits are currently ignored'));
191
+ return;
192
+ }
193
+ await (0, promises_1.writeFile)(gitignorePath, updatedContent, 'utf-8');
194
+ console.log(chalk_1.default.green(`āœ… Removed ${commitHashes.length} commit(s) from .git-blame-ignore-revs`));
195
+ }
196
+ catch (error) {
197
+ throw new Error('.git-blame-ignore-revs file not found');
198
+ }
199
+ }
200
+ async function removeAllIgnoredCommits() {
201
+ const gitignorePath = (0, path_1.join)(process.cwd(), '.git-blame-ignore-revs');
202
+ try {
203
+ const content = await (0, promises_1.readFile)(gitignorePath, 'utf-8');
204
+ const commits = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
205
+ if (commits.length === 0) {
206
+ console.log(chalk_1.default.yellow('No commits are currently ignored'));
207
+ return;
208
+ }
209
+ const backupPath = gitignorePath + '.backup';
210
+ await (0, promises_1.writeFile)(backupPath, content, 'utf-8');
211
+ await (0, promises_1.writeFile)(gitignorePath, '# Git blame ignore file - auto-generated by git-blame-ignore\n', 'utf-8');
212
+ console.log(chalk_1.default.green(`āœ… Removed all ${commits.length} ignored commits`));
213
+ console.log(chalk_1.default.blue(`šŸ’” Backup saved to: ${backupPath}`));
214
+ }
215
+ catch (error) {
216
+ throw new Error('.git-blame-ignore-revs file not found');
217
+ }
218
+ }
219
+ program.parse();
220
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}