{"id":35591305,"url":"https://github.com/captainsafia/grove","last_synced_at":"2026-04-02T17:08:16.249Z","repository":{"id":320985635,"uuid":"1066087399","full_name":"captainsafia/grove","owner":"captainsafia","description":"CLI tool for managing git worktree-based workflows","archived":false,"fork":false,"pushed_at":"2026-03-28T23:14:29.000Z","size":2118,"stargazers_count":61,"open_issues_count":2,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-29T01:43:50.664Z","etag":null,"topics":["bun","cli","git","typescript","worktrees"],"latest_commit_sha":null,"homepage":"https://grove.safia.sh","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/captainsafia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-29T02:09:02.000Z","updated_at":"2026-03-28T23:05:52.000Z","dependencies_parsed_at":"2025-10-27T06:27:22.626Z","dependency_job_id":null,"html_url":"https://github.com/captainsafia/grove","commit_stats":null,"previous_names":["captainsafia/grove"],"tags_count":63,"template":false,"template_full_name":null,"purl":"pkg:github/captainsafia/grove","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/captainsafia%2Fgrove","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/captainsafia%2Fgrove/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/captainsafia%2Fgrove/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/captainsafia%2Fgrove/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/captainsafia","download_url":"https://codeload.github.com/captainsafia/grove/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/captainsafia%2Fgrove/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31311203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","cli","git","typescript","worktrees"],"created_at":"2026-01-04T23:15:42.638Z","updated_at":"2026-04-02T17:08:16.242Z","avatar_url":"https://github.com/captainsafia.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grove\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"site/logo.png\" alt=\"Grove Logo\" width=\"200\"/\u003e\n\u003c/div\u003e\n\nGrove is a CLI tool that encapsulates the patterns that I use for working with Git worktrees locally on my machine. To learn more about this pattern, you can check out [this blog post](https://blog.safia.rocks/2025/09/03/git-worktrees/).\n\n## Features\n\n- Initialize repos with a bare clone optimized for worktrees\n- Create, list, and remove worktrees\n- Sync with origin and prune stale worktrees\n- Run commands from anywhere within the project hierarchy\n- Shell integration for seamless directory navigation\n- Self-update to the latest version or PR build\n\n## Platform Support\n\n- Linux (x64, arm64)\n- macOS (x64, arm64)\n- Windows (x64)\n\n## Installation\n\n### Quick Install (Linux/macOS)\n\n```bash\ncurl https://i.safia.sh/captainsafia/grove | sh\n```\n\n### Quick Install (Windows PowerShell)\n\n```powershell\nirm https://i.safia.sh/captainsafia/grove.ps1 | iex\n```\n\nThis will download the appropriate binary for your system and install it to `~/.grove/bin`.\n\nTo install a specific version:\n\n```bash\ncurl https://i.safia.sh/captainsafia/grove/v1.0.0 | sh\n```\n\nFor Windows PowerShell:\n\n```powershell\nirm https://i.safia.sh/captainsafia/grove/v1.0.0.ps1 | iex\n```\n\n## Usage\n\n### Initialize a new worktree setup\n\nCreate a new directory structure optimized for git worktree workflows:\n\n```bash\ngrove init https://github.com/user/repo.git\n```\n\nThis command will:\n\n- Create a directory named after the repository (e.g., `repo/`)\n- Clone the repository as a bare clone into `repo/repo.git/`\n- Configure the remote fetch to support all branches\n- Provide instructions for creating worktrees\n\nAfter initialization, you can create worktrees:\n\n```bash\ncd repo\ngrove add main\ngrove add feature/new-feature\n```\n\n### Add a new worktree\n\nCreate a new worktree for a branch:\n\n```bash\ngrove add feature/new-feature\n```\n\nCreate a new worktree with an auto-generated adjective-noun name:\n\n```bash\ngrove add\n# Example generated name: quiet-meadow\n# If .groverc sets \"branchPrefix\": \"safia\", example: safia/quiet-meadow\n# Directory remains: quiet-meadow\n# branchPrefix only accepts alphanumeric characters\n```\n\nTrack a remote branch:\n\n```bash\ngrove add feature/new-feature --track origin/feature/new-feature\n```\n\nBootstrap a newly created worktree with project-scoped commands:\n\n```json\n{\n  \"branchPrefix\": \"safia\",\n  \"bootstrap\": {\n    \"commands\": [\n      { \"program\": \"npm\", \"args\": [\"install\"] },\n      { \"program\": \"cargo\", \"args\": [\"check\"] }\n    ]\n  }\n}\n```\n\nSave this as `.groverc` in your Grove project root (the directory that contains your bare clone, for example `repo/.groverc` next to `repo/repo.git`).\n\nWhen `grove add` is called without an explicit branch name, Grove generates an adjective-noun name and prepends `branchPrefix` to the branch name when configured. `branchPrefix` must be alphanumeric only (letters and numbers). The worktree directory keeps the generated base name.\n\nWhen `grove add` creates a worktree, it runs each bootstrap command in order inside that new worktree directory.\n\n- Commands must be portable across Linux/macOS/Windows.\n- Use executable + args only (no shell syntax like pipes, `\u0026\u0026`, or redirects).\n- If one command fails, Grove continues running the remaining commands and reports a partial bootstrap state.\n\n### Remove worktrees\n\nRemove a single worktree:\n\n```bash\ngrove remove feature/new-feature\n```\n\nRemove multiple worktrees at once:\n\n```bash\ngrove remove feature/new-feature bugfix/login-flake\n```\n\nForce removal even with uncommitted changes. When `--force` removes a dirty worktree, Grove skips the confirmation prompt and logs a warning after removal:\n\n```bash\ngrove remove feature/new-feature bugfix/login-flake --force\n```\n\nSkip the confirmation prompt for clean worktrees:\n\n```bash\ngrove remove feature/new-feature --yes\n```\n\n### Navigate to a worktree\n\nOpen a new shell session in a worktree directory:\n\n```bash\ngrove go feature-branch\n```\n\nThis spawns a new shell in the worktree directory. Exit the shell (Ctrl+D or `exit`) to return to your previous directory.\n\nYou can also navigate by partial branch name for nested branches:\n\n```bash\n# If you have a worktree for feature/my-feature\ngrove go my-feature\n```\n\nThe `GROVE_WORKTREE` environment variable is set to the branch name while in the worktree shell.\n\n#### Shell Integration\n\nFor a smoother experience, you can set up shell integration so `grove go` changes your current directory instead of spawning a new shell:\n\n**Bash:**\n```bash\necho 'eval \"$(grove shell-init bash)\"' \u003e\u003e ~/.bashrc\nsource ~/.bashrc\n```\n\n**Zsh:**\n```bash\necho 'eval \"$(grove shell-init zsh)\"' \u003e\u003e ~/.zshrc\nsource ~/.zshrc\n```\n\n**Fish:**\n```bash\necho 'eval \"$(grove shell-init fish)\"' \u003e\u003e ~/.config/fish/config.fish\nsource ~/.config/fish/config.fish\n```\n\nWith shell integration enabled, `grove go feature-branch` will directly change your working directory.\n\n### Run Commands from Anywhere\n\nGrove commands work from anywhere within your project hierarchy - you don't need to be in the bare clone directory. Whether you're deep inside a worktree's source code or at the project root, grove automatically discovers the repository:\n\n```bash\n# Works from inside a worktree\ncd ~/projects/myproject/feature-branch/src/components\ngrove list  # Discovers and lists all worktrees\n\n# Works from the worktree root\ncd ~/projects/myproject/feature-branch\ngrove add another-feature\n\n# Works from the bare clone\ncd ~/projects/myproject/myproject.git\ngrove sync\n```\n\nGrove caches the discovered repository path in the `GROVE_REPO` environment variable for faster subsequent commands.\n\n### List all worktrees\n\n```bash\ngrove list\n```\n\nShow detailed information:\n\n```bash\ngrove list --details\n```\n\nShow only dirty worktrees:\n\n```bash\ngrove list --dirty\n```\n\n### Sync with origin\n\nUpdate the bare clone with the latest changes from origin:\n\n```bash\ngrove sync\n```\n\nThis fetches the default branch (main or master) from origin and updates the local reference.\n\nSync a specific branch:\n\n```bash\ngrove sync --branch develop\n```\n\n### Prune merged worktrees\n\nPreview what would be removed:\n\n```bash\ngrove prune --dry-run\n```\n\nRemove worktrees for branches merged to main:\n\n```bash\ngrove prune\n```\n\nForce removal even if worktrees have uncommitted changes:\n\n```bash\ngrove prune --force\n```\n\nUse a different base branch:\n\n```bash\ngrove prune --base develop\n```\n\nRemove worktrees older than a specific duration (bypasses merge check):\n\n**Note:** When using `--older-than`, the merge status check is bypassed, and all worktrees older than the specified duration will be removed. The `--base` flag cannot be used with `--older-than`.\n\nYou can use human-friendly formats (e.g., `30d`, `2w`, `6M`, `1y`) or ISO 8601 duration format (e.g., `P30D`, `P2W`, `P6M`, `P1Y`):\n\n```bash\n# Remove worktrees older than 30 days\ngrove prune --older-than 30d\n\n# Remove worktrees older than 6 months\ngrove prune --older-than 6M\n\n# Remove worktrees older than 1 year\ngrove prune --older-than 1y\n\n# Preview what would be removed for worktrees older than 2 weeks\ngrove prune --older-than 2w --dry-run\n\n# ISO 8601 format is also supported\ngrove prune --older-than P30D\n```\n\n### Self-update\n\nUpdate grove to the latest version:\n\n```bash\ngrove self-update\n```\n\nUpdate to a specific version:\n\n```bash\ngrove self-update v1.0.0\n# or\ngrove self-update 1.0.0\n```\n\nUpdate to a specific PR build (requires GitHub CLI):\n\n```bash\ngrove self-update --pr 42\n```\n\n**Note:** The self-update command uses the same installation script as the initial installation. If you installed grove using the quick install method, this command will update the binary in `~/.grove/bin`. If you installed grove using a different method (e.g., manually downloading the binary), you may need to update it manually.\n\n## Commands\n\n- `grove init \u003cgit-url\u003e` - Create a new worktree setup\n- `grove add [name] [options]` - Create a new worktree\n- `grove go \u003cname\u003e` - Navigate to a worktree\n- `grove remove [names]... [options]` - Remove one or more worktrees\n- `grove list [options]` - List all worktrees\n- `grove sync [options]` - Sync the bare clone with origin\n- `grove prune [options]` - Remove worktrees for merged branches\n- `grove shell-init \u003cshell\u003e` - Output shell integration function (bash, zsh, or fish)\n- `grove self-update [version] [options]` - Update grove to a specific version or PR\n- `grove version` - Show version information\n- `grove help [command]` - Show help\n\n## Development\n\n### Prerequisites\n\n- [Rust](https://www.rust-lang.org/tools/install) (stable toolchain)\n- Git\n\n### Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/captainsafia/grove.git\ncd grove\n\n# Build the project\ncargo build\n\n# Build optimized release binary\ncargo build --release\n```\n\n### Development Commands\n\n```bash\n# Build debug binary\ncargo build\n\n# Build optimized release binary\ncargo build --release\n\n# Run directly in development\ncargo run -- \u003ccommand\u003e\n\n# Type check without building\ncargo check\n\n# Run all tests\ncargo test\n\n# Clean build artifacts\ncargo clean\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaptainsafia%2Fgrove","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcaptainsafia%2Fgrove","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaptainsafia%2Fgrove/lists"}