yggtree 1.1.0 โ 1.1.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/dist/commands/wt/create-branch.js +16 -2
- package/dist/commands/wt/create-multi.js +22 -7
- package/dist/index.js +1 -1
- package/dist/lib/git.js +33 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch } from '../../lib/git.js';
|
|
4
|
+
import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch, ensureCorrectUpstream } from '../../lib/git.js';
|
|
5
5
|
import { runBootstrap } from '../../lib/config.js';
|
|
6
6
|
import { WORKTREES_ROOT } from '../../lib/paths.js';
|
|
7
7
|
import { log, ui, createSpinner } from '../../lib/ui.js';
|
|
@@ -110,7 +110,6 @@ export async function createCommandNew(options) {
|
|
|
110
110
|
else {
|
|
111
111
|
await execa('git', ['worktree', 'add', '-b', branchName, wtPath, baseRef]);
|
|
112
112
|
}
|
|
113
|
-
spinner.succeed('Worktree created.');
|
|
114
113
|
}
|
|
115
114
|
catch (e) {
|
|
116
115
|
spinner.fail('Failed to create worktree.');
|
|
@@ -125,6 +124,21 @@ export async function createCommandNew(options) {
|
|
|
125
124
|
]);
|
|
126
125
|
return;
|
|
127
126
|
}
|
|
127
|
+
try {
|
|
128
|
+
// Strong Safety Mode: Ensure upstream is origin/<branchName> and publish
|
|
129
|
+
spinner.text = 'Safely publishing branch...';
|
|
130
|
+
await ensureCorrectUpstream(wtPath, branchName);
|
|
131
|
+
spinner.succeed('Worktree created and branch published.');
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
spinner.fail('Worktree created, but branch publication failed.');
|
|
135
|
+
log.actionableError(e.message, 'git push -u origin HEAD', wtPath, [
|
|
136
|
+
`cd ${wtPath}`,
|
|
137
|
+
'Attempt to push manually: git push -u origin HEAD',
|
|
138
|
+
'Check if the remote branch already exists or if you have push permissions'
|
|
139
|
+
]);
|
|
140
|
+
// We don't return here because the worktree IS created, we just failed to publish
|
|
141
|
+
}
|
|
128
142
|
if (shouldBootstrap) {
|
|
129
143
|
await runBootstrap(wtPath, repoRoot);
|
|
130
144
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch } from '../../lib/git.js';
|
|
4
|
+
import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch, ensureCorrectUpstream } from '../../lib/git.js';
|
|
5
5
|
import { runBootstrap } from '../../lib/config.js';
|
|
6
6
|
import { WORKTREES_ROOT } from '../../lib/paths.js';
|
|
7
7
|
import { log, ui, createSpinner } from '../../lib/ui.js';
|
|
@@ -84,12 +84,6 @@ export async function createCommandMulti(options) {
|
|
|
84
84
|
else {
|
|
85
85
|
await execa('git', ['worktree', 'add', '-b', branchName, wtPath, baseRef]);
|
|
86
86
|
}
|
|
87
|
-
wtSpinner.succeed(`Worktree for ${chalk.cyan(branchName)} created.`);
|
|
88
|
-
createdWorktrees.push(wtPath);
|
|
89
|
-
// 4. Bootstrap
|
|
90
|
-
if (shouldBootstrap) {
|
|
91
|
-
await runBootstrap(wtPath, repoRoot);
|
|
92
|
-
}
|
|
93
87
|
}
|
|
94
88
|
catch (error) {
|
|
95
89
|
wtSpinner.fail(`Failed to create worktree for ${branchName}.`);
|
|
@@ -102,6 +96,27 @@ export async function createCommandMulti(options) {
|
|
|
102
96
|
'Try pruning stale worktrees: yggtree wt prune',
|
|
103
97
|
`Run manually: ${cmd}`
|
|
104
98
|
]);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
// Strong Safety Mode: Ensure upstream is origin/<branchName> and publish
|
|
103
|
+
wtSpinner.text = `Safely publishing branch ${branchName}...`;
|
|
104
|
+
await ensureCorrectUpstream(wtPath, branchName);
|
|
105
|
+
wtSpinner.succeed(`Worktree for ${chalk.cyan(branchName)} created and published.`);
|
|
106
|
+
createdWorktrees.push(wtPath);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
wtSpinner.fail(`Worktree for ${branchName} created, but publication failed.`);
|
|
110
|
+
log.actionableError(error.message, 'git push -u origin HEAD', wtPath, [
|
|
111
|
+
`cd ${wtPath}`,
|
|
112
|
+
'Attempt to push manually: git push -u origin HEAD',
|
|
113
|
+
'Check if the remote branch already exists or if you have push permissions'
|
|
114
|
+
]);
|
|
115
|
+
createdWorktrees.push(wtPath); // Still added to list since wt exists
|
|
116
|
+
}
|
|
117
|
+
// 4. Bootstrap
|
|
118
|
+
if (shouldBootstrap) {
|
|
119
|
+
await runBootstrap(wtPath, repoRoot);
|
|
105
120
|
}
|
|
106
121
|
}
|
|
107
122
|
// 5. Final Output
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ program
|
|
|
31
31
|
{ name: '๐ณ Create multiple worktrees', value: 'create-multi' },
|
|
32
32
|
{ name: '๐ฑ Create new worktree (Manual Slug)', value: 'create-slug' },
|
|
33
33
|
{ name: '๐ List worktrees', value: 'list' },
|
|
34
|
-
{ name: '๐๏ธ
|
|
34
|
+
{ name: '๐๏ธ Delete worktree', value: 'delete' },
|
|
35
35
|
{ name: '๐ Bootstrap worktree', value: 'bootstrap' },
|
|
36
36
|
{ name: '๐งน Prune stale worktrees', value: 'prune' },
|
|
37
37
|
{ name: '๐ Exec command', value: 'exec' },
|
package/dist/lib/git.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import { log } from './ui.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
4
6
|
export async function getRepoRoot() {
|
|
5
7
|
try {
|
|
6
8
|
const { stdout } = await execa('git', ['rev-parse', '--show-toplevel']);
|
|
@@ -83,3 +85,34 @@ export async function isGitClean(cwd) {
|
|
|
83
85
|
return false;
|
|
84
86
|
}
|
|
85
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Ensures the branch in the given worktree path tracks origin/<branchName>.
|
|
90
|
+
* If it tracks a different base branch (e.g. origin/main), it unsets it and publishes to origin.
|
|
91
|
+
* Fails if origin/<branchName> already exists on remote and is not already the upstream.
|
|
92
|
+
*/
|
|
93
|
+
export async function ensureCorrectUpstream(wtPath, branchName) {
|
|
94
|
+
const desiredUpstream = `origin/${branchName}`;
|
|
95
|
+
let currentUpstream = '';
|
|
96
|
+
try {
|
|
97
|
+
const { stdout } = await execa('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], { cwd: wtPath });
|
|
98
|
+
currentUpstream = stdout.trim();
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// No upstream set
|
|
102
|
+
}
|
|
103
|
+
if (currentUpstream === desiredUpstream) {
|
|
104
|
+
return; // Already correct
|
|
105
|
+
}
|
|
106
|
+
// If it's set to something else, unset it
|
|
107
|
+
if (currentUpstream) {
|
|
108
|
+
log.info(`Incorrect upstream detected: ${currentUpstream}. Unsetting...`);
|
|
109
|
+
await execa('git', ['branch', '--unset-upstream'], { cwd: wtPath });
|
|
110
|
+
}
|
|
111
|
+
// Check if remote branch already exists
|
|
112
|
+
const remoteExists = await verifyRef(desiredUpstream);
|
|
113
|
+
if (remoteExists) {
|
|
114
|
+
throw new Error(`Remote branch '${desiredUpstream}' already exists. Cannot publish safely without more info. Use 'git push -u origin HEAD' manually if you want to link them.`);
|
|
115
|
+
}
|
|
116
|
+
log.info(`Publishing branch ${chalk.cyan(branchName)} to ${chalk.cyan(desiredUpstream)}...`);
|
|
117
|
+
await execa('git', ['push', '-u', 'origin', 'HEAD'], { cwd: wtPath });
|
|
118
|
+
}
|