Skip to content

Improved support for linked-worktrees (a.k.a. git worktree)#1808

Merged
pjbgf merged 13 commits intomainfrom
worktree
Dec 31, 2025
Merged

Improved support for linked-worktrees (a.k.a. git worktree)#1808
pjbgf merged 13 commits intomainfrom
worktree

Conversation

@pjbgf
Copy link
Member

@pjbgf pjbgf commented Dec 18, 2025

This PR improves the existing support to linked-worktrees, making it more reliable while also adding worktree management capabilities.

Opening linked-worktree repositories

PlainOpen():

Opening linked-worktree repositories using PlainOpen requires EnableDotGitCommonDir to be set to true:

PlainOpenWithOptions("/repo", &PlainOpenOptions{EnableDotGitCommonDir: true})

This PR does not change this. Before the V6 release, we may need to consider dropping off the use of EnableDotGitCommonDir and having that working behind the scenes as ideally users would not need to know they are dealing with a linked-worktree, especially when using PlainOpen.

Open()

Using Open requires the storer FS to be a wrapping between both gitDir and commonDir via dotgit.NewRepositoryFilesystem(gitDirFS, commonDirFS).
A new Worktree.Open helper was introduced in x/plumbing/worktree to abstract that logic, so that it automatically does that when it detects the repository being opened is a linked-worktree. Otherwise it falls back to the existing git.Open() logic.

go-git specific features

A new Worktree.Init has been introduced so that users can connect a new filesystem to an existing worktree metadata.
This is useful when the main repository is on disk, and the worktree is an empty in-memory filesystem - or vice-versa.
For example:

	// Setup repository storage on osfs pointing to existing dotgit which contains the feature-x worktree metadata.
	storerFS := osfs.New("/path/to/repo/.git")
	storer := filesystem.NewStorage(storerFS, cache.NewObjectLRUDefault())
	w, err := xworktree.New(storer)
	if err != nil {
		panic(err)
	}

	// Now connect a fresh memfs filesystem to the existing worktree metadata.
	// This is useful when you want the worktree on a different filesystem
	// or filesystem type.
	freshWtFS := memfs.New()
	err = w.Init(freshWtFS, "feature-x")
	if err != nil {
		panic(err)
	}

	// Open the worktree with the new filesystem.
	r, err := w.Open(freshWtFS)
	if err != nil {
		panic(err)
	}

	// The worktree is now connected and can be used.
	_, _ = r.Head()

Making changes to linked-worktrees

The RepositoryFilesystem had a bug that at times would return the incorrect FS during writing changes to a linked-worktree. This has been fixed as part of #1801 (thanks @Soph), I pulled that change into this PR as it is needed for this feature to be fully operational.

Worktree Management

Three core features from upstream are supported: add, remove and list. Note they may not be exposing exactly the same values as what the upstream CLI does, however, it provides enough information so that users can attain the same results - as per go-git/cli PR which implements those subcommand in a go-git native way.

Closes: #41 #1580
Supersedes: #1801 #1675 #396
Relates to: #285 #394

⚠️ The new code is being exposed under x, to avoid a potentially unstable API being a blocker for cutting the V6 release.

Copilot AI review requested due to automatic review settings December 18, 2025 22:18
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces comprehensive support for git worktrees (linked worktrees), enabling users to manage multiple working trees attached to a single repository. The functionality is placed under the experimental x/ namespace to allow API iteration before the V6 release.

Key Changes

  • Adds core worktree management operations: add, remove, list, open, and init
  • Fixes a bug in RepositoryFilesystem that could route operations to the wrong filesystem when using absolute paths from temp files
  • Introduces WorktreeStorer interface to expose filesystem access needed for worktree metadata management

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
x/storage/worktree_storer.go Defines the WorktreeStorer interface for accessing repository filesystem
x/plumbing/worktree/worktree.go Core implementation of worktree management with Add, Remove, List, Open, and Init operations
x/plumbing/worktree/worktree_options.go Functional options for configuring worktree operations (WithCommit, WithDetachedHead)
x/plumbing/worktree/worktree_test.go Comprehensive test suite including unit tests, integration tests, and fuzz tests
x/plumbing/worktree/doc.go Package documentation describing worktree concepts and usage
x/doc.go Documentation marking the x package as experimental
storage/filesystem/dotgit/repository_filesystem.go Fixes filesystem routing for absolute paths to support temp file operations in linked worktrees
storage/filesystem/dotgit/repository_filesystem_test.go Tests validating the filesystem routing fix for temp file rename operations
_examples/worktrees/main.go Example demonstrating how to create and open linked worktrees
_examples/common_test.go Adds test configuration for the worktrees example
_examples/README.md Documents the new worktrees example
COMPATIBILITY.md Updates git-worktree compatibility status from unsupported to partial support
.github/workflows/pr-validation.yml Updates commit message pattern to allow "x:" prefix
go.mod / go.sum Updates dependencies for go-billy and go-git-fixtures

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pjbgf pjbgf force-pushed the worktree branch 2 times, most recently from 4f6fdf5 to ede584d Compare December 18, 2025 22:43
pjbgf and others added 13 commits December 31, 2025 06:22
Previously the new worktrees were created detached by default, which
does not align with upstream behaviour. This option is opt-in, and
when not used it will default to a branch based on the worktree name.

Signed-off-by: Paulo Gomes <[email protected]>
This is a go-git concept, which adds flexibility to the way linked
worktrees work. It enables a fs to be connected to an existing metadata,
which is particularly useful cross-filesystem implementations.
For example, in-memory worktrees that are connected pre-existing worktree
metadata on disk - or vice versa.

Signed-off-by: Paulo Gomes <[email protected]>
The underlying oss-fuzz logic has issues when the Fuzz tests are in a
different package than the logic being tests, resulting in build failures.
This moves the test into the worktree package.

This commit also includes improvements based on feedback from the PR.

Signed-off-by: Paulo Gomes <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Checkout multiple branches

3 participants