@harryisfish/gitt 1.3.0 → 1.4.1
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/README.md +60 -1
- package/dist/commands/clean.js +61 -17
- package/dist/commands/config.js +33 -0
- package/dist/index.js +83 -2
- package/dist/utils/config.js +83 -0
- package/dist/utils/git.js +76 -0
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -19,12 +19,71 @@ pnpm add -g @harryisfish/gitt
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
+
# Default behavior (auto-clean)
|
|
22
23
|
gitt
|
|
24
|
+
|
|
25
|
+
# Interactive mode (select branches to delete)
|
|
26
|
+
gitt -i
|
|
27
|
+
# or
|
|
28
|
+
gitt --interactive
|
|
29
|
+
|
|
30
|
+
# Dry run (preview what would be deleted)
|
|
31
|
+
gitt -d
|
|
32
|
+
# or
|
|
33
|
+
gitt --dry-run
|
|
23
34
|
```
|
|
24
35
|
|
|
25
36
|
## Configuration
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
### Main Branch Detection
|
|
39
|
+
|
|
40
|
+
Gitt automatically detects your main branch in the following order:
|
|
41
|
+
1. **`.gitt` configuration file** (Project level)
|
|
42
|
+
2. **Git config** `gitt.mainBranch` (User/System level)
|
|
43
|
+
3. **Remote HEAD** (e.g., `origin/HEAD`)
|
|
44
|
+
4. **Common names** (`main`, `master`)
|
|
45
|
+
|
|
46
|
+
### Setting the Main Branch
|
|
47
|
+
|
|
48
|
+
You can explicitly set the main branch for your project using the command:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
gitt set-main <branch-name>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
```bash
|
|
56
|
+
gitt set-main master
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
gitt set-main master
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This will create a `.gitt` file in your project root with your preference.
|
|
63
|
+
|
|
64
|
+
### Branch Protection
|
|
65
|
+
|
|
66
|
+
You can prevent specific branches from being deleted by adding them to the ignore list.
|
|
67
|
+
|
|
68
|
+
**Using command (Recommended):**
|
|
69
|
+
```bash
|
|
70
|
+
gitt ignore "release/*"
|
|
71
|
+
gitt ignore "test-branch"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Manual Configuration:**
|
|
75
|
+
You can also manually edit the `.gitt` configuration file:
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mainBranch": "main",
|
|
79
|
+
"ignoreBranches": [
|
|
80
|
+
"release/*",
|
|
81
|
+
"test-branch",
|
|
82
|
+
"feature/important-*"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
Supports glob patterns (e.g., `*`).
|
|
28
87
|
|
|
29
88
|
## Documentation
|
|
30
89
|
|
package/dist/commands/clean.js
CHANGED
|
@@ -3,26 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.cleanDeletedBranches = cleanDeletedBranches;
|
|
4
4
|
const simple_git_1 = require("simple-git");
|
|
5
5
|
const listr2_1 = require("listr2");
|
|
6
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
7
|
+
const minimatch_1 = require("minimatch");
|
|
6
8
|
const errors_1 = require("../errors");
|
|
7
9
|
const errors_2 = require("../errors");
|
|
10
|
+
const git_1 = require("../utils/git");
|
|
11
|
+
const config_1 = require("../utils/config");
|
|
8
12
|
const git = (0, simple_git_1.simpleGit)();
|
|
9
13
|
/**
|
|
10
14
|
* Clean up local branches that have been deleted on the remote
|
|
11
15
|
* @throws {GitError} When cleaning operation fails
|
|
12
16
|
*/
|
|
13
|
-
async function cleanDeletedBranches() {
|
|
17
|
+
async function cleanDeletedBranches(options = {}) {
|
|
14
18
|
try {
|
|
15
|
-
const
|
|
19
|
+
const state = {
|
|
20
|
+
mainBranch: '',
|
|
21
|
+
deletedBranches: []
|
|
22
|
+
};
|
|
23
|
+
// Phase 1: Discovery
|
|
24
|
+
const discoveryTasks = new listr2_1.Listr([
|
|
16
25
|
{
|
|
17
26
|
title: 'Fetch main from remote',
|
|
18
|
-
task: async () => {
|
|
19
|
-
await
|
|
27
|
+
task: async (ctx) => {
|
|
28
|
+
const mainBranch = await (0, git_1.getMainBranch)();
|
|
29
|
+
ctx.mainBranch = mainBranch;
|
|
30
|
+
await git.fetch(['origin', mainBranch]);
|
|
20
31
|
}
|
|
21
32
|
},
|
|
22
33
|
{
|
|
23
34
|
title: 'Switch to main branch',
|
|
24
|
-
task: async () => {
|
|
25
|
-
await git.checkout(
|
|
35
|
+
task: async (ctx) => {
|
|
36
|
+
await git.checkout(ctx.mainBranch);
|
|
26
37
|
}
|
|
27
38
|
},
|
|
28
39
|
{
|
|
@@ -36,24 +47,57 @@ async function cleanDeletedBranches() {
|
|
|
36
47
|
task: async (ctx) => {
|
|
37
48
|
await git.fetch(['--prune']);
|
|
38
49
|
const branchSummary = await git.branch(['-vv']);
|
|
39
|
-
const
|
|
50
|
+
const config = await (0, config_1.readConfigFile)();
|
|
51
|
+
const ignorePatterns = config.ignoreBranches || [];
|
|
52
|
+
let deletedBranches = branchSummary.all.filter(branch => {
|
|
40
53
|
const branchInfo = branchSummary.branches[branch];
|
|
41
54
|
return branchInfo.label && branchInfo.label.includes(': gone]');
|
|
42
55
|
});
|
|
56
|
+
// Filter out ignored branches
|
|
57
|
+
if (ignorePatterns.length > 0) {
|
|
58
|
+
deletedBranches = deletedBranches.filter(branch => {
|
|
59
|
+
const isIgnored = ignorePatterns.some(pattern => (0, minimatch_1.minimatch)(branch, pattern));
|
|
60
|
+
return !isIgnored;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
43
63
|
ctx.deletedBranches = deletedBranches;
|
|
44
64
|
}
|
|
45
|
-
}
|
|
65
|
+
}
|
|
66
|
+
]);
|
|
67
|
+
await discoveryTasks.run(state);
|
|
68
|
+
// Phase 2: Interaction / Filtering
|
|
69
|
+
if (state.deletedBranches.length === 0) {
|
|
70
|
+
(0, errors_2.printSuccess)('No branches need to be cleaned up');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (options.interactive) {
|
|
74
|
+
try {
|
|
75
|
+
const selected = await (0, prompts_1.checkbox)({
|
|
76
|
+
message: 'Select branches to delete:',
|
|
77
|
+
choices: state.deletedBranches.map(b => ({ name: b, value: b, checked: true })),
|
|
78
|
+
});
|
|
79
|
+
state.deletedBranches = selected;
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
// User cancelled
|
|
83
|
+
throw new Error('Operation cancelled');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (state.deletedBranches.length === 0) {
|
|
87
|
+
(0, errors_2.printSuccess)('No branches selected for deletion');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (options.dryRun) {
|
|
91
|
+
console.log('\nDry Run: The following branches would be deleted:');
|
|
92
|
+
state.deletedBranches.forEach(b => console.log(` - ${b}`));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Phase 3: Execution
|
|
96
|
+
const deleteTasks = new listr2_1.Listr([
|
|
46
97
|
{
|
|
47
98
|
title: 'Delete branches removed on remote',
|
|
48
|
-
enabled: (ctx) => Array.isArray(ctx.deletedBranches),
|
|
49
|
-
skip: (ctx) => {
|
|
50
|
-
if (!ctx.deletedBranches || ctx.deletedBranches.length === 0) {
|
|
51
|
-
return 'No branches need to be cleaned up';
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
},
|
|
55
99
|
task: (ctx) => {
|
|
56
|
-
return new listr2_1.Listr(
|
|
100
|
+
return new listr2_1.Listr(state.deletedBranches.map(branch => ({
|
|
57
101
|
title: `Delete ${branch}`,
|
|
58
102
|
task: async () => {
|
|
59
103
|
await git.branch(['-D', branch]);
|
|
@@ -62,7 +106,7 @@ async function cleanDeletedBranches() {
|
|
|
62
106
|
}
|
|
63
107
|
}
|
|
64
108
|
]);
|
|
65
|
-
await
|
|
109
|
+
await deleteTasks.run(state);
|
|
66
110
|
(0, errors_2.printSuccess)('Branch cleanup completed');
|
|
67
111
|
}
|
|
68
112
|
catch (error) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configMainBranch = configMainBranch;
|
|
4
|
+
exports.configIgnoreBranch = configIgnoreBranch;
|
|
5
|
+
const git_1 = require("../utils/git");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const config_1 = require("../utils/config");
|
|
8
|
+
async function configMainBranch(branch) {
|
|
9
|
+
try {
|
|
10
|
+
await (0, git_1.setMainBranch)(branch);
|
|
11
|
+
(0, errors_1.printSuccess)(`Successfully set main branch to '${branch}'`);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
(0, errors_1.handleError)(error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async function configIgnoreBranch(pattern) {
|
|
18
|
+
try {
|
|
19
|
+
const config = await (0, config_1.readConfigFile)();
|
|
20
|
+
const ignoreBranches = config.ignoreBranches || [];
|
|
21
|
+
if (!ignoreBranches.includes(pattern)) {
|
|
22
|
+
ignoreBranches.push(pattern);
|
|
23
|
+
await (0, config_1.writeConfigFile)({ ignoreBranches });
|
|
24
|
+
(0, errors_1.printSuccess)(`Successfully added '${pattern}' to ignore list`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
(0, errors_1.printSuccess)(`'${pattern}' is already in the ignore list`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
(0, errors_1.handleError)(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
37
|
const simple_git_1 = require("simple-git");
|
|
5
38
|
const errors_1 = require("./errors");
|
|
@@ -41,12 +74,60 @@ async function checkGitRepo() {
|
|
|
41
74
|
throw new errors_1.GitError('Cannot access remote repository, please check network connection or repository permissions');
|
|
42
75
|
}
|
|
43
76
|
}
|
|
77
|
+
function printHelp() {
|
|
78
|
+
console.log(`
|
|
79
|
+
Usage: gitt [command] [options]
|
|
80
|
+
|
|
81
|
+
Commands:
|
|
82
|
+
(default) Clean up local branches that have been deleted on remote
|
|
83
|
+
set-main <branch> Set the main branch for the current project
|
|
84
|
+
ignore <pattern> Add a branch pattern to the ignore list (e.g., "release/*")
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
-i, --interactive Interactive mode: Select branches to delete
|
|
88
|
+
-d, --dry-run Dry run: Show what would be deleted without deleting
|
|
89
|
+
-h, --help Show this help message
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
gitt # Auto-clean deleted branches
|
|
93
|
+
gitt -i # Select branches to delete interactively
|
|
94
|
+
gitt -d # Preview deletion
|
|
95
|
+
gitt ignore "temp/*" # Ignore branches matching "temp/*"
|
|
96
|
+
gitt set-main master # Set main branch to 'master'
|
|
97
|
+
`);
|
|
98
|
+
}
|
|
44
99
|
async function main() {
|
|
45
100
|
try {
|
|
101
|
+
const args = process.argv.slice(2);
|
|
102
|
+
const command = args[0];
|
|
103
|
+
// Check for help command
|
|
104
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
105
|
+
printHelp();
|
|
106
|
+
process.exit(0);
|
|
107
|
+
}
|
|
46
108
|
// 检查 Git 仓库
|
|
47
109
|
await checkGitRepo();
|
|
48
|
-
|
|
49
|
-
|
|
110
|
+
if (command === 'set-main') {
|
|
111
|
+
const branch = args[1];
|
|
112
|
+
if (!branch) {
|
|
113
|
+
throw new Error('Please specify a branch name');
|
|
114
|
+
}
|
|
115
|
+
await Promise.resolve().then(() => __importStar(require('./commands/config'))).then(m => m.configMainBranch(branch));
|
|
116
|
+
}
|
|
117
|
+
else if (command === 'ignore') {
|
|
118
|
+
const pattern = args[1];
|
|
119
|
+
if (!pattern) {
|
|
120
|
+
throw new Error('Please specify a branch pattern to ignore');
|
|
121
|
+
}
|
|
122
|
+
await Promise.resolve().then(() => __importStar(require('./commands/config'))).then(m => m.configIgnoreBranch(pattern));
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Parse options
|
|
126
|
+
const isInteractive = args.includes('-i') || args.includes('--interactive');
|
|
127
|
+
const isDryRun = args.includes('-d') || args.includes('--dry-run');
|
|
128
|
+
// 默认执行清理操作
|
|
129
|
+
await (0, clean_1.cleanDeletedBranches)({ interactive: isInteractive, dryRun: isDryRun });
|
|
130
|
+
}
|
|
50
131
|
// 退出程序
|
|
51
132
|
process.exit(0);
|
|
52
133
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getProjectRoot = getProjectRoot;
|
|
37
|
+
exports.readConfigFile = readConfigFile;
|
|
38
|
+
exports.writeConfigFile = writeConfigFile;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const simple_git_1 = require("simple-git");
|
|
42
|
+
const CONFIG_FILE_NAME = '.gitt';
|
|
43
|
+
/**
|
|
44
|
+
* Get the project root directory (where .git is located).
|
|
45
|
+
*/
|
|
46
|
+
async function getProjectRoot() {
|
|
47
|
+
const git = (0, simple_git_1.simpleGit)();
|
|
48
|
+
try {
|
|
49
|
+
const root = await git.revparse(['--show-toplevel']);
|
|
50
|
+
return root.trim();
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
return process.cwd();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Read the .gitt configuration file.
|
|
58
|
+
*/
|
|
59
|
+
async function readConfigFile() {
|
|
60
|
+
try {
|
|
61
|
+
const root = await getProjectRoot();
|
|
62
|
+
const configPath = path.join(root, CONFIG_FILE_NAME);
|
|
63
|
+
if (!fs.existsSync(configPath)) {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
67
|
+
return JSON.parse(content);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Write to the .gitt configuration file.
|
|
75
|
+
*/
|
|
76
|
+
async function writeConfigFile(config) {
|
|
77
|
+
const root = await getProjectRoot();
|
|
78
|
+
const configPath = path.join(root, CONFIG_FILE_NAME);
|
|
79
|
+
// Read existing config to merge
|
|
80
|
+
const currentConfig = await readConfigFile();
|
|
81
|
+
const newConfig = { ...currentConfig, ...config };
|
|
82
|
+
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
|
|
83
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMainBranch = getMainBranch;
|
|
4
|
+
exports.setMainBranch = setMainBranch;
|
|
5
|
+
const simple_git_1 = require("simple-git");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
const git = (0, simple_git_1.simpleGit)();
|
|
9
|
+
/**
|
|
10
|
+
* Get the main branch name for the current repository.
|
|
11
|
+
* Priority:
|
|
12
|
+
* 1. User config (gitt.mainBranch)
|
|
13
|
+
* 2. Remote HEAD (origin/HEAD)
|
|
14
|
+
* 3. Common names (main, master)
|
|
15
|
+
*/
|
|
16
|
+
async function getMainBranch() {
|
|
17
|
+
try {
|
|
18
|
+
// 1. Check .gitt config file
|
|
19
|
+
const fileConfig = await (0, config_1.readConfigFile)();
|
|
20
|
+
if (fileConfig.mainBranch) {
|
|
21
|
+
return fileConfig.mainBranch;
|
|
22
|
+
}
|
|
23
|
+
// 2. Check user config (legacy/fallback)
|
|
24
|
+
const configMain = await git.getConfig('gitt.mainBranch');
|
|
25
|
+
if (configMain.value) {
|
|
26
|
+
return configMain.value;
|
|
27
|
+
}
|
|
28
|
+
// 3. Try to detect from remote HEAD
|
|
29
|
+
try {
|
|
30
|
+
const remotes = await git.listRemote(['--symref', 'origin', 'HEAD']);
|
|
31
|
+
// Output format example: "ref: refs/heads/main\tHEAD"
|
|
32
|
+
const match = remotes.match(/ref: refs\/heads\/([^\s]+)\s+HEAD/);
|
|
33
|
+
if (match && match[1]) {
|
|
34
|
+
return match[1];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
// Ignore network/remote errors during detection
|
|
39
|
+
}
|
|
40
|
+
// 4. Check for common local branches
|
|
41
|
+
const localBranches = await git.branchLocal();
|
|
42
|
+
if (localBranches.all.includes('main'))
|
|
43
|
+
return 'main';
|
|
44
|
+
if (localBranches.all.includes('master'))
|
|
45
|
+
return 'master';
|
|
46
|
+
// Default fallback
|
|
47
|
+
return 'main';
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
throw new errors_1.GitError('Failed to detect main branch');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set the preferred main branch for the current repository.
|
|
55
|
+
*/
|
|
56
|
+
async function setMainBranch(branch) {
|
|
57
|
+
try {
|
|
58
|
+
// Verify branch exists locally or remotely
|
|
59
|
+
const localBranches = await git.branchLocal();
|
|
60
|
+
if (!localBranches.all.includes(branch)) {
|
|
61
|
+
// If not local, check if we can fetch it
|
|
62
|
+
try {
|
|
63
|
+
await git.fetch(['origin', branch]);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
throw new errors_1.GitError(`Branch '${branch}' does not exist locally or on remote`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await (0, config_1.writeConfigFile)({ mainBranch: branch });
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (error instanceof errors_1.GitError)
|
|
73
|
+
throw error;
|
|
74
|
+
throw new errors_1.GitError('Failed to set main branch configuration');
|
|
75
|
+
}
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harryisfish/gitt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "A command-line tool to help you manage Git repositories and remote repositories, such as keeping in sync, pushing, pulling, etc.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -38,8 +38,10 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@inquirer/prompts": "^3.3.0",
|
|
41
|
-
"
|
|
42
|
-
"listr2": "^8.0.0"
|
|
41
|
+
"@types/minimatch": "^6.0.0",
|
|
42
|
+
"listr2": "^8.0.0",
|
|
43
|
+
"minimatch": "^10.1.1",
|
|
44
|
+
"simple-git": "^3.22.0"
|
|
43
45
|
},
|
|
44
46
|
"engines": {
|
|
45
47
|
"node": ">=14.0.0"
|
|
@@ -50,4 +52,4 @@
|
|
|
50
52
|
"README.md",
|
|
51
53
|
"LICENSE"
|
|
52
54
|
]
|
|
53
|
-
}
|
|
55
|
+
}
|