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
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ nav:
- Getting Started: tutorials/getting-started.md
- Advanced Usage: tutorials/advanced-usage.md
- Troubleshooting: tutorials/troubleshooting.md
- Worktrees: tutorials/worktrees.md
- Migrating to V6: tutorials/migrating-from-v5-to-v6.md
- Concepts:
- Overview: concepts/overview.md
133 changes: 133 additions & 0 deletions src/tutorials/worktrees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
layout: default
title: Working with Linked Worktrees
---
# Working with Linked Worktrees

Git worktrees allow you to check out multiple branches simultaneously, each
in its own working directory. go-git supports creating and opening linked
worktrees through the experimental `x/plumbing/worktree` package.

## Overview

A Git repository has one **main worktree** (created by `git init` or
`git clone`) and zero or more **linked worktrees**. Each linked worktree
has its own checked-out branch and working directory, while sharing the
same object database and refs with the main repository.

Common use cases:

- Running tests on one branch while developing on another
- Comparing behavior across branches side by side
- Building a release while continuing feature work

## Creating a Linked Worktree

To create a linked worktree, you need:

1. A `storage.Storer` that implements `WorktreeStorer` (e.g. `filesystem.Storage`)
2. A `billy.Filesystem` for the new worktree's working directory
3. The commit hash to check out

```go
package main

import (
"fmt"
"os"
"path/filepath"

"github.com/go-git/go-billy/v6/osfs"
"github.com/go-git/go-git/v6"
"github.com/go-git/go-git/v6/plumbing"
"github.com/go-git/go-git/v6/storage/filesystem"

xworktree "github.com/go-git/go-git/v6/x/plumbing/worktree"
)

func main() {
repoPath := "/path/to/repo"
worktreePath := "/path/to/new-worktree"
commitHash := "abc123..."

// Open the repository's .git storage
dotgitFs := osfs.New(filepath.Join(repoPath, ".git"), osfs.WithChrootOS())
store := filesystem.NewStorageWithOptions(dotgitFs, nil, filesystem.Options{})

// Create a worktree manager
wt, err := xworktree.New(store)
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}

// Create the linked worktree filesystem
worktreeFs := osfs.New(worktreePath)
name := filepath.Base(worktreePath)

// Add the worktree at the given commit
err = wt.Add(worktreeFs, name,
xworktree.WithCommit(plumbing.NewHash(commitHash)))
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}

fmt.Printf("Worktree %q created at %s\n", name, worktreePath)
}
```

## Opening an Existing Linked Worktree

Once a linked worktree exists on disk, open it like any other repository
using `git.Open` with the shared storage and the worktree filesystem:

```go
r, err := git.Open(store, worktreeFs)
if err != nil {
log.Fatal(err)
}

ref, err := r.Head()
if err != nil {
log.Fatal(err)
}

commit, err := r.CommitObject(ref.Hash())
if err != nil {
log.Fatal(err)
}

fmt.Println(commit)
```

## Worktree Configuration Extension

When `extensions.worktreeConfig` is enabled in the repository config,
each linked worktree can have its own `config.worktree` file at
`.git/worktrees/<name>/config.worktree`. go-git's filesystem storage
reads these files and overlays them on the shared repository config,
matching the behavior of upstream Git.

This is useful for per-worktree settings such as `core.sparseCheckout`
or custom configuration that should differ between worktrees.

Reference: [git-worktree configuration file](https://git-scm.com/docs/git-worktree#_configuration_file)

## Worktree Naming

Worktree names must match the pattern `[a-zA-Z0-9\-]+`. Typically the
name is derived from the base directory name of the worktree path (e.g.
`/tmp/hotfix` produces the name `hotfix`).

## Limitations

- Only `add` is fully supported for creating worktrees. Not all flags
or subcommands from `git worktree` are implemented.
- The worktree package lives in `x/plumbing/worktree`, meaning its API
is **experimental** and may change without notice.
- The storer must implement `WorktreeStorer` — currently only
`storage/filesystem` satisfies this.
- Worktree lock, move, and prune operations are not yet supported.

See the [full example](_examples/worktrees/main.go) in the go-git repository.