Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 51 additions & 20 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,4 @@
# Manual Test for CI Publish Workflow

1. Push a commit to the main branch (or merge the PR) to trigger the workflow.
2. Check the Actions tab in your GitHub repository to see that the "Publish to npm" workflow runs successfully.
3. Verify that the package is published to npm with the expected version (0.0.0-development) without any new commits from the workflow.

## Important Notes

- The CI workflow will not make any commits or version bumps
- Version updates should be handled manually outside of CI
- Make sure you have set up the `NPM_TOKEN` secret in your GitHub repository settings

## New Worktree Sibling Directory Test

1. In a test repository, run:
```bash
cwt new editor
```
2. Verify that a new sibling directory named `<currentDirectoryName>editor` is created.
3. Confirm that the worktree is added to the Git repository and that the Cursor editor opens the new directory.
# Manual Tests for cursor-worktree CLI

## Manual Test for CLI Command Name Change

Expand All @@ -43,6 +24,15 @@
cwt remove feature/test
```

## New Worktree Sibling Directory Test

1. In a test repository, run:
```bash
cwt new editor
```
2. Verify that a new sibling directory named `<currentDirectoryName>-editor` is created.
3. Confirm that the worktree is added to the Git repository and that the Cursor editor opens the new directory.

## Remove Worktree Force Flag Test

1. Create a test worktree:
Expand All @@ -61,3 +51,44 @@
```
This should succeed and remove the worktree regardless of its state
5. Verify that the worktree directory is removed and the Git worktree reference is cleaned up

## Manual Test for Merge Command

1. **Setup a Test Worktree:**
- Create a new worktree for a test branch:
```bash
cwt new test-merge
```
2. **Make Changes in the Test Worktree:**
- Navigate to the test worktree directory, edit a file, and save your changes.
3. **Run the Merge Command:**
- Go back to your main worktree (current branch) and execute:
```bash
cwt merge test-merge
```
4. **Verify the Merge:**
- Confirm that the changes from `test-merge` are merged into the current branch.
- Check that the test worktree is removed.
5. **Test with Force Flag:**
- Create another test worktree:
```bash
cwt new test-merge-force
```
- Make changes that would prevent normal removal (e.g., untracked files)
- Run the merge with force flag:
```bash
cwt merge test-merge-force --force
```
- Verify that the merge succeeds and the worktree is forcibly removed.

## Manual Test for CI Publish Workflow

1. Push a commit to the main branch (or merge the PR) to trigger the workflow.
2. Check the Actions tab in your GitHub repository to see that the "Publish to npm" workflow runs successfully.
3. Verify that the package is published to npm with the expected version (0.0.0-development) without any new commits from the workflow.

## Important Notes

- The CI workflow will not make any commits or version bumps
- Version updates should be handled manually outside of CI
- Make sure you have set up the `NPM_TOKEN` secret in your GitHub repository settings
95 changes: 95 additions & 0 deletions src/commands/merge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { execa } from "execa";
import chalk from "chalk";
import { stat, rm } from "node:fs/promises";
import { resolve } from "node:path";

export async function mergeWorktreeHandler(
branchName: string,
options: { force?: boolean }
) {
try {
// Validate that we're in a git repository
await execa("git", ["rev-parse", "--is-inside-work-tree"]);

// Get the current branch name (the target for merging)
const { stdout: currentBranch } = await execa("git", ["branch", "--show-current"]);
if (!currentBranch) {
console.error(chalk.red("Failed to determine the current branch."));
process.exit(1);
}

// Parse worktree list to find the worktree for the target branch
const { stdout } = await execa("git", ["worktree", "list", "--porcelain"]);
let targetPath = "";
let tempPath = "";
const lines = stdout.split("\n");
for (const line of lines) {
if (line.startsWith("worktree ")) {
tempPath = line.replace("worktree ", "").trim();
} else if (line.startsWith("branch ")) {
const fullBranchRef = line.replace("branch ", "").trim();
const shortBranch = fullBranchRef.replace("refs/heads/", "");
if (shortBranch === branchName) {
targetPath = tempPath;
break;
}
}
}

if (!targetPath) {
console.error(chalk.red(`Could not find a worktree for branch "${branchName}".`));
process.exit(1);
}

console.log(
chalk.blue(
`Merging changes from worktree branch "${branchName}" at ${targetPath} into current branch "${currentBranch}".`
)
);

// Step 1: Commit any pending changes in the target branch worktree
try {
await execa("git", ["-C", targetPath, "add", "."]);
await execa("git", [
"-C",
targetPath,
"commit",
"-m",
`Auto-commit changes before merging ${branchName}`,
]);
console.log(chalk.green("Committed pending changes in target branch worktree."));
} catch (commitError) {
console.log(
chalk.yellow("No pending changes to commit in the target branch or commit failed, proceeding with merge.")
);
}

// Step 2: Merge the target branch into the current branch
await execa("git", ["merge", branchName]);
console.log(chalk.green(`Merged branch "${branchName}" into "${currentBranch}".`));

// Step 3: Remove the worktree for the merged branch (similar to 'cwt remove')
console.log(chalk.blue(`Removing worktree for branch "${branchName}"...`));
const removeArgs = ["worktree", "remove", ...(options.force ? ["--force"] : []), targetPath];
await execa("git", removeArgs);
console.log(chalk.green(`Removed worktree at ${targetPath}.`));

// Optionally remove the physical directory if it still exists
try {
await stat(targetPath);
await rm(targetPath, { recursive: true, force: true });
console.log(chalk.green(`Deleted folder ${targetPath}.`));
} catch {
// If the directory does not exist, it's fine
}

console.log(chalk.green("Merge command completed successfully!"));
} catch (error) {
if (error instanceof Error) {
console.error(chalk.red("Failed to merge worktree:"), error.message);
} else {
console.error(chalk.red("Failed to merge worktree:"), error);
}
process.exit(1);
}
}
8 changes: 8 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import chalk from "chalk";
import { newWorktreeHandler } from "./commands/new.js";
import { listWorktreesHandler } from "./commands/list.js";
import { removeWorktreeHandler } from "./commands/remove.js";
import { mergeWorktreeHandler } from "./commands/merge.js";

const program = new Command();

Expand Down Expand Up @@ -35,4 +36,11 @@ program
.description("Remove a specified worktree. Cleans up the .git/worktrees references.")
.action(removeWorktreeHandler);

program
.command("merge")
.argument("<branchName>", "Name of the branch to merge from")
.option("-f, --force", "Force removal of worktree after merge", false)
.description("Commit changes in the target branch and merge them into the current branch, then remove the branch/worktree")
.action(mergeWorktreeHandler);

program.parse(process.argv);