Intertwined branches and sessions - Fish shell plugin for git worktree + tmux session management
Twine helps you seamlessly manage git worktrees and tmux sessions, making it easy to work on multiple branches simultaneously with dedicated terminal environments for each.
tw - Your main command for branch-based workflows
Jump between branches instantly, each in their own tmux session. Perfect for when you're juggling feature work, code review, and hotfixes.
# Pick from all your projects and branches interactively
tw
# Jump to a specific branch (creates worktree if needed)
tw my-project feature/login
# Start work on a remote branch you haven't checked out yet
tw my-project origin/hotfix/critical-bug
# Create a new branch and worktree from main/master
tw my-project feature/new-feature --create
# Create a new branch from a specific base branch
tw my-project feature/new-feature -c -f developReal scenario: You're coding in feature/payment when a critical bug is
reported. Run tw my-project hotfix/security-fix to instantly switch to a fresh
environment. Your payment feature work stays running with its dev server and
tests untouched. Need to start a new feature? Use tw my-project feature/login -c
to create a new branch and worktree in one command.
t - Fast switching between your projects
Switch to any project's main session without specifying a branch. Great for when you just need to jump into a project.
# Interactive selection of all your projects
t
# Jump directly to a project
t my-projectReal scenario: Need to quickly check something in your docs repo or run a
script? t docs gets you there instantly without the branch selection step.
init - Start fresh with the worktree pattern
Setting up a new repository for the first time? Get it configured correctly from the start.
# Clone and set up for multi-branch work
twine init my-project git@github.com:user/my-project.git
# Start with a specific branch
twine init my-project git@github.com:user/my-project.git developReal scenario: Starting a new job or project. Use init to clone the repo
as bare with worktree support, so you're ready to work on multiple features from
day one.
convert - Upgrade regular repos to use worktrees
Already have a repo? Convert it to the bare + worktree pattern to unlock parallel branch workflows.
# Convert your existing repo
twine convert my-projectReal scenario: You've been using a regular repo but now need to work on a feature branch while keeping main available for hotfixes. Convert it once and enjoy the worktree workflow.
ts - Start tmuxinator sessions
If you use tmuxinator for custom window/pane layouts, launch them in your current repo.
# From within any git repository
cd ~/src/my-project/feature-branch
tsReal scenario: You have a tmuxinator layout with editor, tests, and logs
panes. Jump into any worktree and run ts to get your preferred setup instantly.
Twine uses git's worktree feature to let you work on multiple branches at the same time. Here's how your repositories get organized:
~/src/work/
├── my-project.git/ # Bare repository (no working files)
│ ├── HEAD, config, objects/, refs/ # Git internals
│ ├── main/ # Worktree: main branch
│ │ ├── src/
│ │ ├── package.json
│ │ └── ... # Full working directory
│ ├── develop/ # Worktree: develop branch
│ │ ├── src/
│ │ └── ...
│ └── feature/
│ └── new-login/ # Worktree: feature/new-login branch
│ ├── src/
│ └── ...
How it works:
my-project.git/is the bare repository (just git data, no files to edit)- Each subdirectory (
main/,develop/, etc.) is a complete working directory - Each worktree is checked out to a different branch
- All worktrees share the same git history and objects (efficient!)
- Each worktree can have its own running processes, uncommitted changes, etc.
Tmux sessions match the structure:
my-project/main- tmux session for main worktreemy-project/develop- tmux session for develop worktreemy-project/feature/new-login- tmux session for feature worktree
~/src/work/
└── my-project/ # Regular git repository
├── .git/ # Git data
├── src/
└── package.json
Twine works with regular repos too, but you can only work on one branch at a time. When you try to work with multiple branches, twine will offer to convert it to the bare + worktree pattern.
Tell twine where to look for repositories:
set -gx TWINE_BASE_DIRS ~/src/work ~/src/personal ~/projectsTwine will search all these directories for repositories when you run tw or t.
- Interactive selection: Call
tortwwithout arguments for fzf-powered selection - Visual indicators: Running sessions marked with ▶, available repos with 📁
- Multi-directory support: Search for repositories across multiple base directories
- Auto-create worktrees: Automatically create git worktrees from remote branches
- Create new branches: Create new branches with worktrees using
--createflag - Smart session management: Create and switch between tmux sessions for each worktree
- Optional tmuxinator integration: Use custom layouts or fall back to basic tmux sessions
- Tab completion: Intelligent completion prioritizing active sessions over repos
Required:
- Fish shell 3.0+
- tmux - Terminal multiplexer
- git - Version control (with worktree support)
- fzf - Fuzzy finder for interactive selection
- Fisher - Fish plugin manager
Optional:
- tmuxinator - For custom tmux session layouts
Install via Fisher:
fisher install pean/twineAdd to ~/.config/fish/config.fish:
# Base directories to search for repositories
set -gx TWINE_BASE_DIRS ~/src/work ~/src/personal ~/projects# Tmuxinator layout to use (if tmuxinator is installed)
set -gx TWINE_TMUXINATOR_LAYOUT dev
# Session name prefix (e.g., "work-" for "work-repo/branch")
set -gx TWINE_SESSION_PREFIX ""
# Control tmuxinator usage: auto (default), true, or false
set -gx TWINE_USE_TMUXINATOR autoTmuxinator behavior:
auto(default): Use tmuxinator if installed andTWINE_TMUXINATOR_LAYOUTis settrue: Always use tmuxinator (error if not installed)false: Never use tmuxinator, create basic tmux sessions
tw [repo] [branch] [options] # Work on a specific branch (main command)
-c, --create # Create new branch if it doesn't exist
-f, --from BRANCH # Base branch for new branch
t [repo] # Switch to a project (no branch selection)
ts # Launch tmuxinator in current repo
twine init <name> <url> [branch] # Set up new repo
twine convert <repo> # Convert existing repo to worktreesGetting help:
twine --help # Overview of all actions
tw --help # Help for worktree commandBranch-focused workflow - creates worktrees and switches to branch-specific sessions.
tw [repo] [branch] [options]
twine worktree [repo] [branch] [options] # Verbose formOptions:
-c, --create- Create new branch if it doesn't exist-f, --from BRANCH- Base branch for new branch (default: main/master)
Examples:
tw my-project feature/login # Switch to existing branch
tw my-project feature/new -c # Create new branch from main/master
tw my-project feature/new -c -f develop # Create new branch from developFeatures:
- Without args: Interactive fzf selection of all repos and branches
- With repo only: Interactive branch selection for that repo
- With repo and branch: Direct switch (creates worktree if needed)
- Fetches latest remote branches before selection
- Auto-creates worktrees from remote branches
- Creates new branches with
--createflag - Auto-detects default branch (main/master) or use
--fromto specify - Visual indicators: ▶ for active, 📁 for available
Project-focused workflow - switches to main repo session without branch selection.
t [repo]
twine session [repo] # Verbose form- Without args: Interactive fzf selection of all repos
- With repo: Direct switch to that project
- Faster than
twwhen you don't need branch selection - Creates session if repo exists but session doesn't
- Prioritizes running sessions in completions
Launches tmuxinator with your configured layout in the current directory.
ts [args]
twine start [args] # Verbose form- Must be run from within a git repository
- Requires tmuxinator installation
- Uses layout specified in
TWINE_TMUXINATOR_LAYOUT
Sets up a new repository with bare + worktree structure from a remote URL.
twine init <repo-name> <git-url> [branch]Steps performed:
- Clones repository as bare (
repo-name.git) - Creates worktree for initial branch (default or specified)
- Repository is ready to use with
tw
Converts an existing regular repository to bare + worktree structure.
twine convert <repo>Steps performed:
- Clones regular repo as bare (
repo.git) - Creates worktree for current branch
- Optionally removes old regular repo directory
The tw command will also offer to convert when it detects a regular repo.
Low-level tmux session attach/switch (rarely needed directly).
twine attach <session-name>Used internally by tw and t. Use those commands instead for better
integration with git worktrees.
If you want to use custom tmux layouts, install tmuxinator and create a layout file:
-
Install tmuxinator:
gem install tmuxinator
-
Create a layout (e.g.,
~/.config/tmuxinator/dev.yml):name: <%= ENV["TMUX_SESSION_NAME"] || "dev" %> root: <%= ENV["PWD"] %> windows: - editor: layout: main-vertical panes: - nvim - - terminal:
-
Configure twine to use it:
set -gx TWINE_TMUXINATOR_LAYOUT dev
See templates/dev.yml.example for a full example.
- Start interactive: Call
tortwwithout arguments to see all options with visual indicators - Use tab completion: Running sessions appear first (▶), then available repos (📁)
- Choose the right command: Use
twwhen working with branches,tfor quick project navigation - Let it auto-create: When you
tw repo branch, worktrees are created automatically if needed - Multiple base dirs: Configure
TWINE_BASE_DIRSto search across work/personal/hobby projects - Convert when ready: Regular repos work fine, but
convertunlocks parallel branch workflows
Twine includes a comprehensive test suite using Fishtape.
Install Fishtape:
fisher install jorgebucaran/fishtapeRun tests:
./testTest coverage includes:
- Configuration validation
- Repository finding across multiple directories
- Worktree detection and creation logic
- Session management
- Tmuxinator integration
- Tab completions
Tests run automatically on GitHub Actions for every push and pull request.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Commit Message Format:
This project uses Conventional Commits:
<type>: <description>
[optional body]
Types:
feat:- New feature (bumps MINOR version)fix:- Bug fix (bumps PATCH version)docs:- Documentation changestest:- Test changeschore:- Maintenance tasksrefactor:- Code refactoringBREAKING CHANGE:- Breaking changes (bumps MAJOR version)
Examples:
git commit -m "feat: add interactive branch selection"
git commit -m "fix: resolve session switching issue"
git commit -m "docs: update installation instructions"Releases are managed automatically using release-please.
CHANGELOG: Maintained automatically based on conventional commits.
Creating a release:
- Ensure all changes are committed and pushed to master
- Trigger the release workflow:
gh workflow run release-please.yml
- Review and merge the automated Release PR
- Git tag and GitHub release are created automatically
Version scheme: Semantic Versioning (MAJOR.MINOR.PATCH)
fisher remove pean/twineRemove configuration from ~/.config/fish/config.fish.
MIT