@desplega.ai/wts 0.2.0 → 0.2.2

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.
Files changed (2) hide show
  1. package/dist/index.js +60 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1877,7 +1877,7 @@ var {
1877
1877
  // package.json
1878
1878
  var package_default = {
1879
1879
  name: "@desplega.ai/wts",
1880
- version: "0.2.0",
1880
+ version: "0.2.2",
1881
1881
  description: "Git worktree manager with tmux integration",
1882
1882
  type: "module",
1883
1883
  bin: {
@@ -3337,7 +3337,12 @@ function printWorktreeTable(worktrees, projectName) {
3337
3337
  }
3338
3338
 
3339
3339
  // src/commands/merge.ts
3340
- var mergeCommand = new Command2("merge").description("Merge a worktree branch into main").argument("[alias]", "Alias of the worktree to merge").option("--no-cleanup", "Skip cleanup prompt").option("-f, --force", "Skip confirmations (except cleanup)").action(async (alias, options) => {
3340
+ async function getCommitsToMerge(branch, baseBranch, cwd) {
3341
+ const result = await Bun.$`git log ${baseBranch}..${branch} --oneline`.cwd(cwd).quiet();
3342
+ return result.stdout.toString().trim().split(`
3343
+ `).filter(Boolean);
3344
+ }
3345
+ var mergeCommand = new Command2("merge").description("Merge a worktree branch into main").argument("[alias]", "Alias of the worktree to merge").option("--no-cleanup", "Skip cleanup prompt").option("--no-pull", "Skip pulling latest main").option("-f, --force", "Skip confirmations (except cleanup)").action(async (alias, options) => {
3341
3346
  const gitRoot = await getGitRoot();
3342
3347
  if (!gitRoot) {
3343
3348
  console.error(source_default.red("Error: Not in a git repository"));
@@ -3345,6 +3350,12 @@ var mergeCommand = new Command2("merge").description("Merge a worktree branch in
3345
3350
  }
3346
3351
  const config = await resolveConfig(gitRoot);
3347
3352
  const worktrees = await listWorktrees(gitRoot, config.projectName);
3353
+ const mainWorktree = worktrees.find((wt) => wt.isMain);
3354
+ if (!mainWorktree) {
3355
+ console.error(source_default.red("Error: Could not find main worktree"));
3356
+ process.exit(1);
3357
+ }
3358
+ const mainPath = mainWorktree.path;
3348
3359
  let worktree;
3349
3360
  if (alias) {
3350
3361
  worktree = await findWorktreeByAlias(alias, gitRoot);
@@ -3381,16 +3392,37 @@ Merging ${source_default.cyan(branchToMerge)} into ${source_default.cyan(default
3381
3392
  }
3382
3393
  }
3383
3394
  console.log(source_default.dim(`Switching to ${defaultBranch}...`));
3384
- await Bun.$`git checkout ${defaultBranch}`.cwd(gitRoot);
3385
- if (!options.force) {
3386
- const proceed = await confirm(`Pull latest ${defaultBranch}?`, true);
3387
- if (!proceed) {
3388
- console.log(source_default.dim("Cancelled"));
3389
- return;
3395
+ await Bun.$`git checkout ${defaultBranch}`.cwd(mainPath);
3396
+ if (options.pull !== false) {
3397
+ if (!options.force) {
3398
+ const proceed = await confirm(`Pull latest ${defaultBranch}?`, true);
3399
+ if (!proceed) {
3400
+ console.log(source_default.dim("Skipped pull"));
3401
+ } else {
3402
+ console.log(source_default.dim(`Pulling latest...`));
3403
+ await Bun.$`git pull`.cwd(mainPath);
3404
+ }
3405
+ } else {
3406
+ console.log(source_default.dim(`Pulling latest...`));
3407
+ await Bun.$`git pull`.cwd(mainPath);
3390
3408
  }
3391
3409
  }
3392
- console.log(source_default.dim(`Pulling latest...`));
3393
- await Bun.$`git pull`.cwd(gitRoot);
3410
+ const commitsToMerge = await getCommitsToMerge(branchToMerge, defaultBranch, mainPath);
3411
+ if (commitsToMerge.length === 0) {
3412
+ console.log(source_default.yellow(`
3413
+ No commits to merge - ${branchToMerge} has no new commits compared to ${defaultBranch}`));
3414
+ console.log(source_default.dim("The branch may need to be rebased on latest main first."));
3415
+ console.log(source_default.dim("Aborting to prevent accidental data loss."));
3416
+ process.exit(1);
3417
+ }
3418
+ console.log(source_default.dim(`
3419
+ Commits to merge (${commitsToMerge.length}):`));
3420
+ for (const commit of commitsToMerge.slice(0, 5)) {
3421
+ console.log(source_default.dim(` ${commit}`));
3422
+ }
3423
+ if (commitsToMerge.length > 5) {
3424
+ console.log(source_default.dim(` ... and ${commitsToMerge.length - 5} more`));
3425
+ }
3394
3426
  if (!options.force) {
3395
3427
  const proceed = await confirm(`Merge ${branchToMerge}?`, true);
3396
3428
  if (!proceed) {
@@ -3399,18 +3431,26 @@ Merging ${source_default.cyan(branchToMerge)} into ${source_default.cyan(default
3399
3431
  }
3400
3432
  }
3401
3433
  console.log(source_default.dim(`Merging ${branchToMerge}...`));
3402
- await Bun.$`git merge ${branchToMerge}`.cwd(gitRoot);
3434
+ const mergeResult = await Bun.$`git merge ${branchToMerge}`.cwd(mainPath).quiet();
3435
+ const mergeOutput = mergeResult.stdout.toString();
3436
+ console.log(source_default.dim(mergeOutput.trim()));
3437
+ if (mergeOutput.includes("Already up to date")) {
3438
+ console.log(source_default.yellow(`
3439
+ Merge reported 'Already up to date' - no changes were made`));
3440
+ console.log(source_default.red("Aborting cleanup to prevent data loss"));
3441
+ process.exit(1);
3442
+ }
3403
3443
  if (!options.force) {
3404
3444
  const proceed = await confirm(`Push to origin?`, true);
3405
3445
  if (!proceed) {
3406
3446
  console.log(source_default.dim("Skipped push"));
3407
3447
  } else {
3408
3448
  console.log(source_default.dim(`Pushing...`));
3409
- await Bun.$`git push`.cwd(gitRoot);
3449
+ await Bun.$`git push`.cwd(mainPath);
3410
3450
  }
3411
3451
  } else {
3412
3452
  console.log(source_default.dim(`Pushing...`));
3413
- await Bun.$`git push`.cwd(gitRoot);
3453
+ await Bun.$`git push`.cwd(mainPath);
3414
3454
  }
3415
3455
  console.log(source_default.green(`
3416
3456
  ✓ Merged ${branchToMerge} into ${defaultBranch}`));
@@ -3419,9 +3459,14 @@ Merging ${source_default.cyan(branchToMerge)} into ${source_default.cyan(default
3419
3459
  Clean up worktree and branch?`, false);
3420
3460
  if (cleanup) {
3421
3461
  console.log(source_default.dim(`Removing worktree...`));
3422
- await removeWorktree(worktree.path, true, gitRoot);
3462
+ await removeWorktree(worktree.path, true, mainPath);
3423
3463
  console.log(source_default.dim(`Deleting branch ${branchToMerge}...`));
3424
- await deleteBranch(branchToMerge, true, gitRoot);
3464
+ try {
3465
+ await deleteBranch(branchToMerge, false, mainPath);
3466
+ } catch {
3467
+ console.error(source_default.red("Branch not fully merged - keeping branch for safety"));
3468
+ console.log(source_default.dim("Use 'git branch -D <branch>' to force delete if intended"));
3469
+ }
3425
3470
  console.log(source_default.green(`✓ Cleaned up`));
3426
3471
  }
3427
3472
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/wts",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Git worktree manager with tmux integration",
5
5
  "type": "module",
6
6
  "bin": {