Skip to content

✨ feat(worktree): add support for shared resources across worktrees#35

Merged
samzong merged 2 commits intomainfrom
feat-wt-shared-files
Jan 7, 2026
Merged

✨ feat(worktree): add support for shared resources across worktrees#35
samzong merged 2 commits intomainfrom
feat-wt-shared-files

Conversation

@samzong
Copy link
Owner

@samzong samzong commented Jan 7, 2026

No description provided.

Signed-off-by: samzong <samzong.lu@gmail.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @samzong, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a robust mechanism for managing shared resources across Git worktrees. It enables users to define specific files or directories that should be automatically synchronized to all worktrees, either by copying them or creating symbolic links. This feature streamlines development workflows by ensuring consistent environments and simplifying the management of common assets like configuration files or large data directories, reducing manual setup and potential inconsistencies.

Highlights

  • New gmc worktree share command: Introduces a new top-level command gmc worktree share with subcommands to manage shared resources across worktrees. This includes add, remove, list, and sync operations, as well as an interactive mode.
  • Shared Resource Strategies: Supports two strategies for sharing resources: copy (creates an independent copy in each worktree, ideal for configuration files like .env) and link (creates a symbolic link, suitable for large assets like model directories to save space).
  • Automatic Syncing: Shared resources are now automatically synced to new worktrees when they are created using gmc worktree add or duplicated via gmc worktree dup, ensuring consistency across development environments.
  • Configuration Management: Shared resources are configured via a .gmc-shared.yml (or .gmc-shared.yaml) file at the repository root, allowing for easy definition and version control of shared assets.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Signed-off-by: samzong <samzong.lu@gmail.com>
@samzong samzong merged commit 0c6aa0f into main Jan 7, 2026
1 check passed
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature for sharing resources across worktrees, complete with CLI commands and an interactive mode. The implementation is well-structured, but I've identified a few areas for improvement to enhance its robustness and maintainability. My feedback includes fixing a critical bug that could cause a panic, improving error handling in the interactive prompts, addressing code duplication, and ensuring tests are platform-independent. I've also suggested a minor change to follow logging conventions. Overall, great work on this new functionality.

Comment on lines +99 to +105
info, err := os.Stat(srcPath)
if os.IsNotExist(err) {
if c.verbose {
fmt.Printf("Shared resource source not found: %s\n", srcPath)
}
return nil
}

Choose a reason for hiding this comment

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

critical

There's a potential nil pointer dereference here. os.Stat(srcPath) can return an error other than os.IsNotExist. In that case, the error is not handled, and execution continues. Later, on line 130, info.IsDir() would cause a panic because info would be nil. You should handle all non-nil errors from os.Stat.

    info, err := os.Stat(srcPath)
    if err != nil {
        if os.IsNotExist(err) {
            if c.verbose {
                fmt.Printf("Shared resource source not found: %s\n", srcPath)
            }
            return nil // Not an error, just nothing to sync
        }
        return fmt.Errorf("failed to stat source resource %s: %w", srcPath, err)
    }

}

func promptAddResource(c *worktree.Client, reader *bufio.Reader) {
root, _ := c.GetWorktreeRoot()

Choose a reason for hiding this comment

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

high

The error returned by c.GetWorktreeRoot() is ignored. If this call fails, root will be an empty string. This will cause strings.HasPrefix(cwd, root) on line 183 to always evaluate to true, leading to incorrect path manipulation logic later on. You should handle this error to prevent unexpected behavior.

    root, err := c.GetWorktreeRoot()
    if err != nil {
        fmt.Printf("Error: could not determine project root: %v\n", err)
        return
    }

Comment on lines +46 to +59
if !cmd.Flags().Changed("strategy") {
reader := bufio.NewReader(os.Stdin)
fmt.Println("Strategy:")
fmt.Println(" 1. copy - each worktree gets its own copy")
fmt.Println(" 2. link - symlink to shared source")
fmt.Print("Select [1/2, default: 1]: ")
strategyStr, _ := reader.ReadString('\n')
strategyStr = strings.TrimSpace(strings.ToLower(strategyStr))
if strategyStr == "2" || strategyStr == "link" || strategyStr == "l" {
strategy = worktree.StrategySymlink
} else {
strategy = worktree.StrategyCopy
}
}

Choose a reason for hiding this comment

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

medium

The logic for selecting a strategy interactively is also present in promptAddResource (lines 208-220). To avoid duplication and improve maintainability, you could extract this logic into a helper function, for example: func promptForStrategy(reader *bufio.Reader) worktree.ResourceStrategy. This would centralize the prompt text and input parsing.

fmt.Println(" 1. copy - each worktree gets its own copy")
fmt.Println(" 2. link - symlink to shared source")
fmt.Print("Select [1/2, default: 1]: ")
strategyStr, _ := reader.ReadString('\n')

Choose a reason for hiding this comment

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

medium

The error from reader.ReadString('\n') is ignored. If an error occurs (e.g., io.EOF if the user presses Ctrl+D), the program will continue with a potentially empty or partial strategyStr, leading to incorrect behavior. This pattern of ignoring errors from ReadString is repeated throughout the file (e.g., lines 154, 196, 212, 228, 241). It's best practice to handle these errors.

            strategyStr, err := reader.ReadString('\n')
            if err != nil {
                return fmt.Errorf("failed to read strategy input: %w", err)
            }

target, err := os.Readlink(filepath.Join(wtPath, "models"))
require.NoError(t, err)
// On Darwin/Linux it should be relative
assert.Equal(t, "../models", target)

Choose a reason for hiding this comment

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

medium

The test hardcodes the expected symlink target as "../models". This will fail on Windows, where the path separator is \ and the relative path would be ..\models. To make this test platform-independent, you should use a helper from the path/filepath package to construct the expected path.

Suggested change
assert.Equal(t, "../models", target)
assert.Equal(t, filepath.FromSlash("../models"), target)


// Sync shared resources
if err := c.SyncSharedResources(name); err != nil {
fmt.Printf("Warning: failed to sync shared resources: %v\n", err)

Choose a reason for hiding this comment

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

medium

The warning message is printed to standard output using fmt.Printf. It's conventional for warnings and errors to be printed to standard error (stderr). This allows users to redirect normal output (stdout) without losing visibility of warnings. You should use fmt.Fprintf(os.Stderr, ...) instead.

Suggested change
fmt.Printf("Warning: failed to sync shared resources: %v\n", err)
fmt.Fprintf(os.Stderr, "Warning: failed to sync shared resources: %v\n", err)


// Sync shared resources
if err := c.SyncSharedResources(dirName); err != nil {
fmt.Printf("Warning: failed to sync shared resources for %s: %v\n", dirName, err)

Choose a reason for hiding this comment

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

medium

The warning message is printed to standard output using fmt.Printf. It's conventional for warnings and errors to be printed to standard error (stderr). This allows users to redirect normal output (stdout) without losing visibility of warnings. You should use fmt.Fprintf(os.Stderr, ...) instead.

Suggested change
fmt.Printf("Warning: failed to sync shared resources for %s: %v\n", dirName, err)
fmt.Fprintf(os.Stderr, "Warning: failed to sync shared resources for %s: %v\n", dirName, err)

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.

1 participant