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.
@@ -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: '๐Ÿ—‘๏ธ Delete worktree', value: 'delete' },
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yggtree",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Interactive CLI for managing git worktrees and configs",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",