
Git Worktrees
The git worktree functionality allows you to check out multiple branches of a repository in separate working directories simultaneously. This is particularly useful for:
- Working on multiple features or branches concurrently
- Reviewing pull requests without switching contexts
- Running tests on different branches
- Comparing implementations across branches
Methods
Section titled “Methods”listWorktrees
Section titled “listWorktrees”Lists all existing worktrees in the repository with their metadata.
const worktrees = await git.listWorktrees();console.log(worktrees);// [// {// path: "/path/to/main",// branch: "main",// head: "abc123def456",// bare: false,// detached: false// },// {// path: "/path/to/feature",// branch: "feature/new-api",// head: "def456abc123",// bare: false,// detached: false// }// ]
Returns: Promise<GitWorktree[]>
Each GitWorktree
object contains:
path
- Absolute path to the worktree directorybranch
- Branch name (if on a branch)head
- Current commit SHAbare?
- Whether the worktree is bare (no working directory)detached?
- Whether HEAD is detached (not on a branch)
addWorktree
Section titled “addWorktree”Creates a new worktree at the specified path and returns a Git client for that worktree.
// Create worktree from existing branchconst featureGit = await git.addWorktree("./feature-workspace", "feature/new-api");
// Create worktree with new branchconst newFeatureGit = await git.addWorktree("./new-feature", "main", { branch: "feature/awesome-feature"});
// Create detached worktree at specific commitconst commitGit = await git.addWorktree("./commit-review", "abc123", { detach: true});
Parameters:
path: string
- Path where the worktree should be createdcommitish?: string
- Branch, tag, or commit to check out (defaults to HEAD)options?: GitWorktreeAddOptions
- Additional options
Options (GitWorktreeAddOptions
):
branch?: string
- Create a new branch with this nameforce?: boolean
- Force creation even if target existscheckout?: boolean
- Whether to checkout files (default: true)orphan?: boolean
- Create an orphan branch (no commit history)detach?: boolean
- Detach HEAD at the specified commit
Returns: Promise<Git>
- A Git client instance for the new worktree
removeWorktree
Section titled “removeWorktree”Removes an existing worktree and cleans up its administrative files.
// Remove worktree (fails if there are uncommitted changes)await git.removeWorktree("./feature-workspace");
// Force remove worktree (removes even with uncommitted changes)await git.removeWorktree("./feature-workspace", { force: true });
Parameters:
path: string
- Path to the worktree to removeoptions?: { force?: boolean }
- Whether to force removal
GitHub Integration
Section titled “GitHub Integration”addWorktreeForPullRequest
Section titled “addWorktreeForPullRequest”Creates a worktree specifically for reviewing or working on a GitHub pull request. This method automatically fetches the PR branch and sets up the worktree.
// Create worktree for PR #123const prGit = await github.addWorktreeForPullRequest(123);
// Create worktree at specific pathconst prGit = await github.addWorktreeForPullRequest(456, "./pr-456-review");
// Create worktree with additional optionsconst prGit = await github.addWorktreeForPullRequest(789, "./pr-789", { checkout: false, // Don't checkout files initially force: true // Force creation if path exists});
Parameters:
pullNumber: number | string
- Pull request numberpath?: string
- Path for the worktree (defaults toworktree-pr-{number}
)options?: GitWorktreeAddOptions
- Additional worktree options
Returns: Promise<Git>
- A Git client instance for the PR worktree
This method:
- Fetches the pull request details from GitHub
- Attempts to fetch the PR branch locally
- Creates a worktree with the PR branch
- Returns a Git client for the new worktree
Usage Examples
Section titled “Usage Examples”Multi-branch Development
Section titled “Multi-branch Development”// List current worktreesconst existing = await git.listWorktrees();console.log(`Found ${existing.length} existing worktrees`);
// Create worktrees for different featuresconst mainGit = git; // Current repositoryconst featureGit = await git.addWorktree("../feature-a", "feature/feature-a");const bugfixGit = await git.addWorktree("../hotfix", "main", { branch: "hotfix/critical-bug"});
// Work in different contextsconst mainFiles = await mainGit.listFiles();const featureFiles = await featureGit.listFiles();
// Clean up when doneawait git.removeWorktree("../feature-a");await git.removeWorktree("../hotfix");
Pull Request Review Workflow
Section titled “Pull Request Review Workflow”// Create worktree for PR reviewconst prGit = await github.addWorktreeForPullRequest(123, "./pr-review");
// Check the PR's changed filesconst changedFiles = await prGit.changedFiles();console.log("Files changed in PR:", changedFiles);
// Run tests in the PR contextconst testFiles = await prGit.listFiles("**/*.test.js");
// Get diff to understand changesconst diff = await prGit.diff({ base: "main" });
// Clean up after reviewawait git.removeWorktree("./pr-review");
Parallel Development
Section titled “Parallel Development”// Set up multiple worktrees for parallel workconst worktrees = await Promise.all([ git.addWorktree("./feature-1", "feature/authentication"), git.addWorktree("./feature-2", "feature/api-endpoints"), git.addWorktree("./testing", "main", { branch: "testing/integration" })]);
// Each worktree can be used independentlyfor (const [index, worktreeGit] of worktrees.entries()) { const branch = await worktreeGit.branch(); const status = await worktreeGit.exec(["status", "--porcelain"]); console.log(`Worktree ${index + 1} (${branch}): ${status ? 'has changes' : 'clean'}`);}
Best Practices
Section titled “Best Practices”Naming Conventions
Section titled “Naming Conventions”Use descriptive paths that indicate the purpose:
// Good: Clear purpose and contextawait git.addWorktree("./pr-123-review", "main");await git.addWorktree("./feature-auth", "feature/authentication");await git.addWorktree("./hotfix-v1.2.3", "v1.2.2", { branch: "hotfix/v1.2.3" });
// Avoid: Generic or unclear namesawait git.addWorktree("./temp", "some-branch");await git.addWorktree("./test", "main");
Resource Management
Section titled “Resource Management”Always clean up worktrees when finished:
try { const prGit = await github.addWorktreeForPullRequest(123); // Do work with the PR await processFiles(prGit);} finally { // Clean up even if work fails await git.removeWorktree("./worktree-pr-123");}
Checking Existing Worktrees
Section titled “Checking Existing Worktrees”Before creating new worktrees, check what already exists:
const existing = await git.listWorktrees();const prWorktree = existing.find(w => w.path.includes("pr-123"));
if (prWorktree) { console.log(`PR 123 worktree already exists at ${prWorktree.path}`); // Use existing worktree const prGit = git.client(prWorktree.path);} else { // Create new worktree const prGit = await github.addWorktreeForPullRequest(123);}
- Worktrees share the same Git history and objects, saving disk space compared to separate clones
- Each worktree maintains its own index and working directory state
- You cannot check out the same branch in multiple worktrees simultaneously
- Administrative files are stored in the main repository’s
.git/worktrees/
directory - Worktrees are automatically removed from Git’s records when their directories are deleted