+
- Follow: ${worktree.branch}
+ Follow: ${worktree.branch.replace(/^refs\/heads\//, '')}
- ${worktree.path}
+ ${formatPathForDisplay(worktree.path)}
${followMode === worktree.branch ? html`
✓` : ''}
@@ -582,6 +588,8 @@ export class SessionList extends LitElement {
if (response.ok) {
const data = await response.json();
this.repoWorktrees.set(repoPath, data.worktrees || []);
+ // Also set follow mode from the worktrees API response
+ this.repoFollowMode.set(repoPath, data.followBranch);
} else {
logger.error(`Failed to load worktrees for ${repoPath}`);
}
diff --git a/web/src/client/components/session-list/repository-header.ts b/web/src/client/components/session-list/repository-header.ts
index 7a650ef3..6f604711 100644
--- a/web/src/client/components/session-list/repository-header.ts
+++ b/web/src/client/components/session-list/repository-header.ts
@@ -30,14 +30,16 @@ export class RepositoryHeader extends LitElement {
private renderFollowModeIndicator() {
if (!this.followMode) return '';
+ const cleanBranchName = this.followMode.replace(/^refs\/heads\//, '');
+
return html`
+ title="Following worktree: ${cleanBranchName}">
- ${this.followMode}
+ ${cleanBranchName}
`;
}
diff --git a/web/src/client/components/worktree-manager.ts b/web/src/client/components/worktree-manager.ts
index fbc51f1c..6b8c0cd0 100644
--- a/web/src/client/components/worktree-manager.ts
+++ b/web/src/client/components/worktree-manager.ts
@@ -81,19 +81,17 @@ export class WorktreeManager extends LitElement {
return;
}
- try {
- await this.gitService.switchBranch(this.repoPath, branch);
- this.dispatchEvent(new CustomEvent('back'));
- } catch (err) {
- logger.error('Failed to switch branch:', err);
- this.dispatchEvent(
- new CustomEvent('error', {
- detail: {
- message: `Failed to switch to ${branch}: ${err instanceof Error ? err.message : 'Unknown error'}`,
- },
- })
- );
- }
+ // Direct branch switching without worktrees is no longer supported
+ logger.log(
+ `Branch switching to ${branch} requested, but direct branch switching is not supported. Use worktrees instead.`
+ );
+ this.dispatchEvent(
+ new CustomEvent('error', {
+ detail: {
+ message: `Direct branch switching is no longer supported. Create a worktree for branch '${branch}' instead.`,
+ },
+ })
+ );
}
private async handleDeleteWorktree(branch: string, hasChanges: boolean) {
diff --git a/web/src/client/services/git-service.test.ts b/web/src/client/services/git-service.test.ts
index f21934f7..5c153a16 100644
--- a/web/src/client/services/git-service.test.ts
+++ b/web/src/client/services/git-service.test.ts
@@ -327,42 +327,6 @@ describe('GitService', () => {
});
});
- describe('switchBranch', () => {
- it('should switch to a branch', async () => {
- const mockFetch = vi.fn(async () => ({
- ok: true,
- status: 200,
- json: async () => ({}),
- }));
- global.fetch = mockFetch as typeof global.fetch;
-
- await gitService.switchBranch('/home/user/project', 'develop');
-
- const call = mockFetch.mock.calls[0];
- expect(call[0]).toBe('/api/worktrees/switch');
- expect(call[1]?.method).toBe('POST');
-
- const requestBody = JSON.parse(call[1]?.body as string);
- expect(requestBody).toEqual({
- repoPath: '/home/user/project',
- branch: 'develop',
- });
- });
-
- it('should handle switch errors', async () => {
- const mockFetch = vi.fn(async () => ({
- ok: false,
- status: 404,
- json: async () => ({ error: 'Branch not found' }),
- }));
- global.fetch = mockFetch as typeof global.fetch;
-
- await expect(gitService.switchBranch('/home/user/project', 'nonexistent')).rejects.toThrow(
- 'Branch not found'
- );
- });
- });
-
describe('setFollowMode', () => {
it('should enable follow mode', async () => {
const mockFetch = vi.fn(async () => ({
@@ -451,7 +415,6 @@ describe('GitService', () => {
() => gitService.createWorktree('/repo', 'branch', '/path'),
() => gitService.deleteWorktree('/repo', 'branch'),
() => gitService.pruneWorktrees('/repo'),
- () => gitService.switchBranch('/repo', 'branch'),
() => gitService.setFollowMode('/repo', 'branch', true),
];
diff --git a/web/src/client/services/git-service.ts b/web/src/client/services/git-service.ts
index e2b7fc5a..2b35d7e9 100644
--- a/web/src/client/services/git-service.ts
+++ b/web/src/client/services/git-service.ts
@@ -344,61 +344,6 @@ export class GitService {
}
}
- /**
- * Switch to a branch and enable follow mode
- *
- * Performs a Git checkout to switch the main repository to a different branch
- * and enables follow mode for that branch. This operation affects the main
- * repository, not worktrees.
- *
- * **What this does:**
- * 1. Attempts to checkout the specified branch in the main repository
- * 2. If successful, enables follow mode for that branch
- * 3. If checkout fails (e.g., uncommitted changes), the operation is aborted
- *
- * **Follow mode behavior:**
- * - Once enabled, the main repository will automatically follow any checkout
- * operations performed in worktrees of the followed branch
- * - Follow mode state is stored in Git config as `vibetunnel.followBranch`
- *
- * @param repoPath - Absolute path to the repository root
- * @param branch - Branch name to switch to (must exist in the repository)
- *
- * @example
- * ```typescript
- * // Switch main repository to feature branch and enable follow mode
- * await gitService.switchBranch('/path/to/repo', 'feature/new-ui');
- *
- * // Now the main repository is on 'feature/new-ui' branch
- * // and will follow any checkout operations in its worktrees
- * ```
- *
- * @throws Error if:
- * - The branch doesn't exist
- * - There are uncommitted changes preventing the switch
- * - The repository path is invalid
- * - The API request fails
- */
- async switchBranch(repoPath: string, branch: string): Promise
{
- try {
- const response = await fetch('/api/worktrees/switch', {
- method: HttpMethod.POST,
- headers: {
- 'Content-Type': 'application/json',
- ...this.authClient.getAuthHeader(),
- },
- body: JSON.stringify({ repoPath, branch }),
- });
- if (!response.ok) {
- const error = await response.json().catch(() => ({ error: 'Unknown error' }));
- throw new Error(error.error || `Failed to switch branch: ${response.statusText}`);
- }
- } catch (error) {
- logger.error('Failed to switch branch:', error);
- throw error;
- }
- }
-
/**
* Enable or disable follow mode
*
@@ -407,7 +352,7 @@ export class GitService {
* checkout that branch whenever any of its worktrees perform a checkout operation.
*
* This feature uses Git hooks (post-checkout, post-commit) and stores state in
- * the Git config as `vibetunnel.followBranch`.
+ * the Git config as `vibetunnel.followWorktree`.
*
* **Important behaviors:**
* - Only one branch can have follow mode enabled at a time
diff --git a/web/src/server/api-socket-server.ts b/web/src/server/api-socket-server.ts
index 33c7fe6a..9509afec 100644
--- a/web/src/server/api-socket-server.ts
+++ b/web/src/server/api-socket-server.ts
@@ -231,22 +231,7 @@ export class ApiSocketServer {
};
}
} catch (_e) {
- // Check for legacy follow mode
- try {
- const { stdout } = await execGit(['config', 'vibetunnel.followBranch'], {
- cwd: mainRepoPath,
- });
- const followBranch = stdout.trim();
- if (followBranch) {
- followMode = {
- enabled: true,
- branch: followBranch,
- repoPath: prettifyPath(mainRepoPath),
- };
- }
- } catch (_e2) {
- // No follow mode configured
- }
+ // No follow mode configured
}
} catch (_error) {
// Not in a git repo
@@ -430,15 +415,6 @@ export class ApiSocketServer {
cwd: absoluteMainRepo,
});
- // Also try to unset the old config for backward compatibility
- try {
- await execGit(['config', '--local', '--unset', 'vibetunnel.followBranch'], {
- cwd: absoluteMainRepo,
- });
- } catch {
- // Ignore if it doesn't exist
- }
-
// Get the worktree path that was being followed
let followedWorktree: string | undefined;
try {
diff --git a/web/src/server/routes/git.ts b/web/src/server/routes/git.ts
index 9fd37cca..e5f2a383 100644
--- a/web/src/server/routes/git.ts
+++ b/web/src/server/routes/git.ts
@@ -528,83 +528,6 @@ export function createGitRoutes(): Router {
}
});
- /**
- * GET /api/git/follow
- * Check follow mode status for a repository
- */
- router.get('/git/follow', async (req, res) => {
- try {
- const { path: queryPath } = req.query;
-
- if (!queryPath || typeof queryPath !== 'string') {
- return res.status(400).json({
- error: 'Missing or invalid path parameter',
- });
- }
-
- // Resolve the path to absolute
- const absolutePath = resolveAbsolutePath(queryPath);
- logger.debug(`Checking follow mode for path: ${absolutePath}`);
-
- // First check if it's a git repository
- let repoPath: string;
- try {
- const { stdout } = await execGit(['rev-parse', '--show-toplevel'], {
- cwd: absolutePath,
- });
- repoPath = stdout.trim();
- } catch (error) {
- if (isNotGitRepositoryError(error)) {
- return res.json({
- isGitRepo: false,
- followMode: false,
- });
- }
- throw error;
- }
-
- // Get follow mode configuration
- let followBranch: string | undefined;
- let followMode = false;
-
- try {
- const { stdout } = await execGit(['config', 'vibetunnel.followBranch'], {
- cwd: repoPath,
- });
- followBranch = stdout.trim();
- followMode = !!followBranch;
- } catch (_error) {
- // Config not set - follow mode is disabled
- logger.debug('Follow branch not configured');
- }
-
- // Get current branch
- let currentBranch: string | undefined;
- try {
- const { stdout } = await execGit(['branch', '--show-current'], {
- cwd: repoPath,
- });
- currentBranch = stdout.trim();
- } catch (_error) {
- logger.debug('Could not get current branch');
- }
-
- return res.json({
- isGitRepo: true,
- repoPath,
- followMode,
- followBranch: followBranch || null,
- currentBranch: currentBranch || null,
- });
- } catch (error) {
- logger.error('Error checking follow mode:', error);
- return res.status(500).json({
- error: 'Failed to check follow mode',
- message: error instanceof Error ? error.message : String(error),
- });
- }
- });
-
/**
* GET /api/git/notifications
* Get pending notifications for the web UI
diff --git a/web/src/server/routes/repositories.ts b/web/src/server/routes/repositories.ts
index ef279b0d..89abaca0 100644
--- a/web/src/server/routes/repositories.ts
+++ b/web/src/server/routes/repositories.ts
@@ -94,75 +94,6 @@ export function createRepositoryRoutes(): Router {
}
});
- // Get follow mode status for a repository
- router.get('/repositories/follow-mode', async (req, res) => {
- try {
- const repoPath = req.query.path as string;
-
- if (!repoPath || typeof repoPath !== 'string') {
- return res.status(400).json({
- error: 'Missing or invalid path parameter',
- });
- }
-
- const expandedPath = resolveAbsolutePath(repoPath);
- logger.debug(`[GET /repositories/follow-mode] Getting follow mode for: ${expandedPath}`);
-
- try {
- const { stdout } = await execAsync('git config vibetunnel.followBranch', {
- cwd: expandedPath,
- });
- const followBranch = stdout.trim();
- res.json({ followBranch: followBranch || undefined });
- } catch {
- // Config not set - follow mode is disabled
- res.json({ followBranch: undefined });
- }
- } catch (error) {
- logger.error('[GET /repositories/follow-mode] Error getting follow mode:', error);
- res.status(500).json({ error: 'Failed to get follow mode' });
- }
- });
-
- // Set follow mode for a repository
- router.post('/repositories/follow-mode', async (req, res) => {
- try {
- const { repoPath, followBranch } = req.body;
-
- if (!repoPath || typeof repoPath !== 'string') {
- return res.status(400).json({
- error: 'Missing or invalid repoPath parameter',
- });
- }
-
- const expandedPath = resolveAbsolutePath(repoPath);
- logger.debug(
- `[POST /repositories/follow-mode] Setting follow mode for ${expandedPath} to: ${followBranch}`
- );
-
- if (followBranch) {
- // Set follow mode
- await execAsync(`git config vibetunnel.followBranch "${followBranch}"`, {
- cwd: expandedPath,
- });
- } else {
- // Clear follow mode
- try {
- await execAsync('git config --unset vibetunnel.followBranch', {
- cwd: expandedPath,
- });
- } catch {
- // Config might not exist, that's okay
- }
- }
-
- res.json({ success: true });
- } catch (error) {
- logger.error('[POST /repositories/follow-mode] Error setting follow mode:', error);
- res.status(500).json({ error: 'Failed to set follow mode' });
- }
- });
-
return router;
}
diff --git a/web/src/server/routes/worktrees.test.ts b/web/src/server/routes/worktrees.test.ts
index d26173ba..97036e04 100644
--- a/web/src/server/routes/worktrees.test.ts
+++ b/web/src/server/routes/worktrees.test.ts
@@ -320,7 +320,7 @@ branch refs/heads/feature
);
expect(mockExecFile).toHaveBeenCalledWith(
'git',
- ['config', '--local', 'vibetunnel.followBranch', 'develop'],
+ ['config', '--local', 'vibetunnel.followWorktree', '/path/to/worktree'],
expect.objectContaining({ cwd: '/home/user/project' })
);
});
@@ -369,12 +369,12 @@ branch refs/heads/feature
});
it('should handle config unset when already disabled', async () => {
- const error = new Error('error: key "vibetunnel.followBranch" not found') as Error & {
+ const error = new Error('error: key "vibetunnel.followWorktree" not found') as Error & {
exitCode: number;
stderr: string;
};
error.exitCode = 5;
- error.stderr = 'error: key "vibetunnel.followBranch" not found';
+ error.stderr = 'error: key "vibetunnel.followWorktree" not found';
mockExecFile.mockRejectedValueOnce(error);
const response = await request(app).post('/api/worktrees/follow').send({
diff --git a/web/src/server/routes/worktrees.ts b/web/src/server/routes/worktrees.ts
index a5c52310..dfc2acfc 100644
--- a/web/src/server/routes/worktrees.ts
+++ b/web/src/server/routes/worktrees.ts
@@ -267,15 +267,31 @@ export function createWorktreeRoutes(): Router {
const baseBranch = await detectDefaultBranch(absoluteRepoPath);
logger.debug(`Using base branch: ${baseBranch}`);
- // Get follow branch if configured
+ // Get follow worktree if configured
let followBranch: string | undefined;
try {
- const { stdout } = await execGit(['config', 'vibetunnel.followBranch'], {
+ const { stdout } = await execGit(['config', 'vibetunnel.followWorktree'], {
cwd: absoluteRepoPath,
});
- followBranch = stdout.trim() || undefined;
+ const followWorktreePath = stdout.trim();
+
+ if (followWorktreePath) {
+ // Find the branch for this worktree path - we need to parse worktrees first
+ // This is a bit of a circular dependency, so let's get minimal worktree info
+ const { stdout: worktreeListOutput } = await execGit(
+ ['worktree', 'list', '--porcelain'],
+ {
+ cwd: absoluteRepoPath,
+ }
+ );
+ const allWorktrees = parseWorktreePorcelain(worktreeListOutput);
+ const followWorktree = allWorktrees.find((w: Worktree) => w.path === followWorktreePath);
+ if (followWorktree) {
+ followBranch = followWorktree.branch.replace(/^refs\/heads\//, '');
+ }
+ }
} catch {
- // No follow branch configured
+ // No follow worktree configured
}
// Get worktree list
@@ -444,63 +460,6 @@ export function createWorktreeRoutes(): Router {
}
});
- /**
- * POST /api/worktrees/switch
- * Switch main repository to a branch and enable follow mode
- */
- router.post('/worktrees/switch', async (req, res) => {
- try {
- const { repoPath, branch } = req.body;
-
- if (!repoPath || typeof repoPath !== 'string') {
- return res.status(400).json({
- error: 'Missing or invalid repoPath in request body',
- });
- }
-
- if (!branch || typeof branch !== 'string') {
- return res.status(400).json({
- error: 'Missing or invalid branch in request body',
- });
- }
-
- const absoluteRepoPath = path.resolve(repoPath);
- logger.debug(`Switching to branch: ${branch} in repo: ${absoluteRepoPath}`);
-
- // Check for uncommitted changes before switching
- const hasChanges = await hasUncommittedChanges(absoluteRepoPath);
- if (hasChanges) {
- return res.status(400).json({
- error: 'Cannot switch branches with uncommitted changes',
- details: 'Please commit or stash your changes before switching branches',
- });
- }
-
- // Switch to the branch
- await execGit(['checkout', branch], { cwd: absoluteRepoPath });
-
- // Enable follow mode for the switched branch
- await execGit(['config', '--local', 'vibetunnel.followBranch', branch], {
- cwd: absoluteRepoPath,
- });
-
- logger.info(`Successfully switched to branch: ${branch} with follow mode enabled`);
- return res.json({
- success: true,
- message: 'Switched to branch and enabled follow mode',
- branch,
- currentBranch: branch,
- });
- } catch (error) {
- logger.error('Error switching branch:', error);
- const gitError = error as GitError;
- return res.status(500).json({
- error: 'Failed to switch branch',
- details: gitError.stderr || gitError.message,
- });
- }
- });
-
/**
* POST /api/worktrees
* Create a new worktree
@@ -616,13 +575,63 @@ export function createWorktreeRoutes(): Router {
logger.info('Git hooks installed successfully');
}
- // Set the follow mode config to the branch name
- await execGit(['config', '--local', 'vibetunnel.followBranch', branch], {
+ // Get worktree information to find the path for this branch
+ const { stdout: worktreeListOutput } = await execGit(['worktree', 'list', '--porcelain'], {
+ cwd: absoluteRepoPath,
+ });
+ const allWorktrees = parseWorktreePorcelain(worktreeListOutput);
+ const worktree = allWorktrees.find(
+ (w) =>
+ w.branch === branch ||
+ w.branch === `refs/heads/${branch}` ||
+ w.branch.replace(/^refs\/heads\//, '') === branch
+ );
+
+ if (!worktree) {
+ return res.status(400).json({
+ error: `No worktree found for branch: ${branch}`,
+ });
+ }
+
+ // Set the follow worktree path (not branch name)
+ await execGit(['config', '--local', 'vibetunnel.followWorktree', worktree.path], {
cwd: absoluteRepoPath,
});
logger.info(`Follow mode enabled for branch: ${branch}`);
+ // Immediately sync main repository to the followed branch
+ try {
+ // Strip refs/heads/ prefix if present
+ const cleanBranch = branch.replace(/^refs\/heads\//, '');
+
+ // Check if the branch exists locally
+ const { stdout: branchList } = await execGit(['branch', '--list', cleanBranch], {
+ cwd: absoluteRepoPath,
+ });
+
+ if (branchList.trim()) {
+ // Branch exists locally, switch to it
+ await execGit(['checkout', cleanBranch], { cwd: absoluteRepoPath });
+ logger.info(`Main repository switched to branch: ${cleanBranch}`);
+ } else {
+ // Branch doesn't exist locally, try to fetch and create it
+ try {
+ await execGit(['fetch', 'origin', `${cleanBranch}:${cleanBranch}`], {
+ cwd: absoluteRepoPath,
+ });
+ await execGit(['checkout', cleanBranch], { cwd: absoluteRepoPath });
+ logger.info(`Fetched and switched to branch: ${cleanBranch}`);
+ } catch (error) {
+ logger.warn(`Could not fetch/switch to branch ${cleanBranch}:`, error);
+ // Don't fail follow mode enable if branch switch fails
+ }
+ }
+ } catch (error) {
+ logger.warn(`Could not immediately switch to branch ${branch}:`, error);
+ // Don't fail follow mode enable if branch switch fails
+ }
+
// Send notification to Mac app
if (controlUnixHandler.isMacAppConnected()) {
const notification = createControlEvent('system', 'notification', {
@@ -642,8 +651,8 @@ export function createWorktreeRoutes(): Router {
hooksInstallResult: hooksInstallResult,
});
} else {
- // Unset the follow branch config
- await execGit(['config', '--local', '--unset', 'vibetunnel.followBranch'], {
+ // Unset the follow worktree config
+ await execGit(['config', '--local', '--unset', 'vibetunnel.followWorktree'], {
cwd: absoluteRepoPath,
});
diff --git a/web/src/server/utils/git-utils.ts b/web/src/server/utils/git-utils.ts
index c5435d36..21cfbb4f 100644
--- a/web/src/server/utils/git-utils.ts
+++ b/web/src/server/utils/git-utils.ts
@@ -86,21 +86,3 @@ export async function isWorktree(gitPath: string): Promise {
return false;
}
}
-
-/**
- * Get follow mode status for a repository
- * @param repoPath Repository path
- * @returns Current follow branch or undefined
- */
-export async function getFollowBranch(repoPath: string): Promise {
- try {
- const { stdout } = await execFile('git', ['config', 'vibetunnel.followBranch'], {
- cwd: repoPath,
- });
- const followBranch = stdout.trim();
- return followBranch || undefined;
- } catch {
- // Config not set - follow mode is disabled
- return undefined;
- }
-}
diff --git a/web/src/test/e2e/follow-mode.test.ts b/web/src/test/e2e/follow-mode.test.ts
index 491f57e9..518f23d3 100644
--- a/web/src/test/e2e/follow-mode.test.ts
+++ b/web/src/test/e2e/follow-mode.test.ts
@@ -194,9 +194,9 @@ describe.skip('Follow Mode End-to-End Tests', () => {
expect(response.body.enabled).toBe(true);
expect(response.body.branch).toBe('develop');
- // Verify git config was set
- const { stdout: configOutput } = await gitExec(['config', 'vibetunnel.followBranch']);
- expect(configOutput).toBe('develop');
+ // Verify git config was set (should contain worktree path, not branch name)
+ const { stdout: configOutput } = await gitExec(['config', 'vibetunnel.followWorktree']);
+ expect(configOutput).toBe(worktreePath); // Should be the worktree path, not branch name
// Verify hooks were installed
const postCommitExists = await fs
@@ -271,7 +271,7 @@ describe.skip('Follow Mode End-to-End Tests', () => {
// Check that follow mode was disabled (config should not exist)
try {
- await gitExec(['config', 'vibetunnel.followBranch']);
+ await gitExec(['config', 'vibetunnel.followWorktree']);
// If we get here, the config still exists
expect(true).toBe(false); // Fail the test
} catch (error) {
@@ -299,7 +299,7 @@ describe.skip('Follow Mode End-to-End Tests', () => {
// Verify git config was removed
try {
- await gitExec(['config', 'vibetunnel.followBranch']);
+ await gitExec(['config', 'vibetunnel.followWorktree']);
// If we get here, the config still exists
expect(true).toBe(false); // Fail the test
} catch (error) {
diff --git a/web/src/test/integration/worktree-workflows.test.ts b/web/src/test/integration/worktree-workflows.test.ts
index 0e23d9dc..024f8497 100644
--- a/web/src/test/integration/worktree-workflows.test.ts
+++ b/web/src/test/integration/worktree-workflows.test.ts
@@ -93,42 +93,6 @@ describe('Worktree Workflows Integration Tests', () => {
expect(featureWorktree.path).toContain('worktree-feature-test-feature');
});
- it('should switch branches in main worktree', async () => {
- // Switch to bugfix branch (not used by any worktree)
- const switchResponse = await request(testServer.app).post('/api/worktrees/switch').send({
- repoPath: gitRepo.repoPath,
- branch: 'bugfix/critical-fix',
- });
-
- expect(switchResponse.status).toBe(200);
- expect(switchResponse.body.success).toBe(true);
- expect(switchResponse.body.currentBranch).toBe('bugfix/critical-fix');
-
- // Verify the branch was actually switched
- const { stdout } = await gitRepo.gitExec(['branch', '--show-current']);
- expect(stdout).toBe('bugfix/critical-fix');
-
- // Switch back to main
- await gitRepo.gitExec(['checkout', 'main']);
- });
-
- it('should handle uncommitted changes when switching branches', async () => {
- // Create uncommitted changes
- await fs.writeFile(path.join(gitRepo.repoPath, 'uncommitted.txt'), 'test content');
-
- // Try to switch branch (should fail)
- const switchResponse = await request(testServer.app).post('/api/worktrees/switch').send({
- repoPath: gitRepo.repoPath,
- branch: 'develop',
- });
-
- expect(switchResponse.status).toBe(400);
- expect(switchResponse.body.error).toContain('uncommitted changes');
-
- // Clean up
- await fs.unlink(path.join(gitRepo.repoPath, 'uncommitted.txt'));
- });
-
it('should delete worktree', async () => {
// Create a temporary worktree to delete
const tempBranch = 'temp/delete-test';
@@ -202,31 +166,47 @@ describe('Worktree Workflows Integration Tests', () => {
});
describe('Follow Mode', () => {
- it('should enable follow mode', async () => {
+ it('should enable follow mode for existing worktree', async () => {
+ // Use the existing worktree for feature/test-feature
const response = await request(testServer.app).post('/api/worktrees/follow').send({
repoPath: gitRepo.repoPath,
- branch: 'develop',
+ branch: 'feature/test-feature',
enable: true,
});
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.enabled).toBe(true);
- expect(response.body.branch).toBe('develop');
+ expect(response.body.branch).toBe('feature/test-feature');
- // Verify git config was set
- const { stdout } = await gitRepo.gitExec(['config', 'vibetunnel.followBranch']);
- expect(stdout).toBe('develop');
+ // Verify git config was set (should contain worktree path, not branch name)
+ const { stdout } = await gitRepo.gitExec(['config', 'vibetunnel.followWorktree']);
+ // The worktree path should end with the branch slug
+ expect(stdout).toContain('worktree-feature-test-feature');
});
it('should disable follow mode', async () => {
+ // First, get the list of worktrees to find the correct path
+ const worktreesResponse = await request(testServer.app)
+ .get('/api/worktrees')
+ .query({ repoPath: gitRepo.repoPath });
+
+ const featureWorktree = worktreesResponse.body.worktrees.find((w: { branch: string }) =>
+ w.branch.includes('feature/test-feature')
+ );
+
// First enable follow mode
- await gitRepo.gitExec(['config', '--local', 'vibetunnel.followBranch', 'develop']);
+ await gitRepo.gitExec([
+ 'config',
+ '--local',
+ 'vibetunnel.followWorktree',
+ featureWorktree.path,
+ ]);
// Disable it
const response = await request(testServer.app).post('/api/worktrees/follow').send({
repoPath: gitRepo.repoPath,
- branch: 'develop',
+ branch: 'feature/test-feature',
enable: false,
});
@@ -236,7 +216,7 @@ describe('Worktree Workflows Integration Tests', () => {
// Verify git config was removed
try {
- await gitRepo.gitExec(['config', 'vibetunnel.followBranch']);
+ await gitRepo.gitExec(['config', 'vibetunnel.followWorktree']);
expect(true).toBe(false); // Should not reach here
} catch (error) {
// Expected - config should not exist