tmuxp-plugin-worktree 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robbert Helling
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: tmuxp-plugin-worktree
3
+ Version: 0.1.0
4
+ Summary: tmuxp plugin: pick the git worktree a session starts in
5
+ Author: Robbert Helling
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rhelling/tmuxp-plugin-worktree
8
+ Project-URL: Issues, https://github.com/rhelling/tmuxp-plugin-worktree/issues
9
+ Project-URL: Changelog, https://github.com/rhelling/tmuxp-plugin-worktree/releases
10
+ Keywords: tmux,tmuxp,git,worktree,plugin
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Plugins
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Topic :: Software Development :: Version Control :: Git
20
+ Classifier: Topic :: Terminals
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: tmuxp>=1.73
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest>=7; extra == "test"
28
+ Dynamic: license-file
29
+
30
+ # tmuxp-plugin-worktree
31
+
32
+ A [tmuxp](https://github.com/tmux-python/tmuxp) plugin that lets you pick the git
33
+ worktree a session starts in.
34
+
35
+ When the repository of a session's `start_directory` has more than one worktree,
36
+ `tmuxp load <session>` first shows a picker with the configured directory
37
+ preselected:
38
+
39
+ ```text
40
+ worktree>
41
+ Session myapp: pick a worktree (Enter = start, Esc = cancel)
42
+ > myrepo [main] (default)
43
+ myrepo-feature-x [feature/x]
44
+ myrepo-hotfix [hotfix/login]
45
+ ```
46
+
47
+ Picking another worktree:
48
+
49
+ - moves every session, window and pane `start_directory` inside the repository
50
+ into that worktree (relative `cd` commands in your panes keep working), and a
51
+ `before_script` that lives in the repository;
52
+ - renames the session to `<session>-<worktree>` (for example `myapp-feature-x`),
53
+ so it can run next to the default session.
54
+
55
+ A branch may not have every directory your workspace uses. A directory that
56
+ exists in the default worktree but is missing in the chosen worktree is replaced
57
+ by its nearest existing parent, with a note on stderr (tmux would otherwise
58
+ silently start the pane in `$HOME`). Window and pane directories are checked
59
+ after `before_script`, so setup can create them first. The session directory is
60
+ resolved earlier to provide setup with a working directory.
61
+
62
+ A `before_script` the chosen worktree does not have, such as an untracked file,
63
+ keeps running from the default worktree. Its arguments are preserved, including
64
+ quoting and spaces; only the executable's path is rewritten.
65
+
66
+ With a single worktree, or when the start directory is not a git repository,
67
+ nothing changes and no picker is shown.
68
+
69
+ ## Requirements
70
+
71
+ - tmuxp 1.73 or newer for the no-install setup (`workspace_builder_paths`);
72
+ tested with tmuxp 1.73, 1.74 and 1.76
73
+ - git
74
+ - fzf (optional; without it you get a numbered menu)
75
+ - Python 3.10 or newer (the Python that tmuxp runs on)
76
+
77
+ ## Installation
78
+
79
+ ### Option A: install from PyPI (recommended)
80
+
81
+ Install the package into the Python environment tmuxp runs in; then only the
82
+ `plugins` key is needed in your workspace files.
83
+
84
+ ```bash
85
+ # tmuxp installed with pipx
86
+ pipx inject tmuxp tmuxp-plugin-worktree
87
+
88
+ # tmuxp installed with uv
89
+ uv tool install tmuxp --with tmuxp-plugin-worktree
90
+
91
+ # tmuxp installed with pip in a virtualenv (activate it first)
92
+ python -m pip install tmuxp-plugin-worktree
93
+ ```
94
+
95
+ ```yaml
96
+ session_name: myapp
97
+ start_directory: ~/code/myrepo
98
+ plugins:
99
+ - tmuxp_plugin_worktree.WorktreePlugin
100
+ windows:
101
+ - window_name: editor
102
+ panes:
103
+ - nvim
104
+ ```
105
+
106
+ ### Option B: no install (works with Homebrew's tmuxp)
107
+
108
+ Homebrew installs tmuxp in a private virtualenv without pip. Since 1.73, tmuxp
109
+ can add import paths per workspace with `workspace_builder_paths`, so you can
110
+ point it at a checkout instead:
111
+
112
+ ```bash
113
+ git clone https://github.com/rhelling/tmuxp-plugin-worktree.git ~/Documents/Projects/tmuxp-plugin-worktree
114
+ ```
115
+
116
+ ```yaml
117
+ session_name: myapp
118
+ start_directory: ~/code/myrepo
119
+ workspace_builder_paths:
120
+ - ~/Documents/Projects/tmuxp-plugin-worktree/src
121
+ plugins:
122
+ - tmuxp_plugin_worktree.WorktreePlugin
123
+ windows:
124
+ - window_name: editor
125
+ panes:
126
+ - nvim
127
+ ```
128
+
129
+ Relative entries in `workspace_builder_paths` are resolved against the directory
130
+ of the workspace file.
131
+
132
+ ### Check that it works
133
+
134
+ ```bash
135
+ tmuxp load myapp # picker when the repo has 2+ worktrees
136
+ WT_PATH=myrepo-feature-x tmuxp load -d myapp # straight into that worktree, detached
137
+ ```
138
+
139
+ ## Usage
140
+
141
+ - **fzf picker:** Enter starts the highlighted entry (the default is preselected),
142
+ typing filters the list, Esc or Ctrl-C cancels without starting anything.
143
+ `FZF_DEFAULT_OPTS` and `FZF_DEFAULT_OPTS_FILE` are ignored for this picker to
144
+ keep its output format predictable.
145
+ - **Without fzf:** type a number and press Enter, or press Enter for the default.
146
+ Esc, Ctrl-C or Ctrl-D cancels.
147
+ - **No picker:** `WT_PATH=myrepo-feature-x tmuxp load myapp`. A relative
148
+ `WT_PATH` is resolved against the directory that contains the default
149
+ repository; absolute paths and `~/...` work too. An unknown worktree aborts
150
+ with the list of valid choices. A session whose start directory is not in a
151
+ git repository (or that has no `start_directory`) ignores `WT_PATH`, with a
152
+ note.
153
+ - **No terminal** (scripts, cron, CI): the default worktree is used unless
154
+ `WT_PATH` is set.
155
+ - Prunable worktrees (their directory is gone) and bare repositories are not
156
+ offered.
157
+
158
+ ## How it works
159
+
160
+ tmuxp creates plugins after it has expanded the workspace file, but before it
161
+ checks for an existing session and builds the windows. The plugin uses that
162
+ moment to rewrite the expanded configuration: every path inside the default
163
+ repository is moved into the chosen worktree and the session name gets the
164
+ worktree suffix. tmuxp does not pass the configuration to plugins, so the plugin
165
+ finds it in the calling frames; this is verified against tmuxp 1.73, 1.74 and 1.76.
166
+
167
+ When a directory fallback needs to wait for `before_script`, the plugin runs
168
+ setup once through tmuxp's script runner in its `before_workspace_builder` hook,
169
+ then finalizes the window and pane paths. Existing sessions do not rerun setup.
170
+ For this case, tmuxp's script-progress callbacks are bypassed. If using other
171
+ plugins, list this plugin last so their preparation hooks still run before setup.
172
+
173
+ ## Limitations
174
+
175
+ - Absolute paths inside `shell_command` or `shell_command_before` are not
176
+ rewritten; use `start_directory` and relative `cd` commands instead.
177
+ - The session-name suffix comes from the worktree's directory name:
178
+ `myrepo-feature-x` becomes `feature-x`, any other name is used as is. Dots and
179
+ colons become `-`, because tmux does not allow them in session names. If
180
+ multiple worktrees produce the same session name, selecting one aborts with
181
+ a list of the conflicting paths. Rename those worktree directories rather
182
+ than silently reusing another worktree's session.
183
+
184
+ ## Development
185
+
186
+ ```bash
187
+ python3 -m venv .venv
188
+ .venv/bin/pip install -e '.[test]'
189
+ .venv/bin/pytest
190
+ ```
191
+
192
+ The end-to-end tests need `tmux` and `git`. They create throwaway repositories
193
+ and run tmuxp against a private tmux server, so your own sessions are never
194
+ touched. The fzf tests are skipped when fzf is not installed.
195
+
196
+ See [TESTING.md](TESTING.md) for what the tests cover, running a subset or
197
+ another tmuxp version, a manual test checklist and troubleshooting.
198
+
199
+ ## Releasing
200
+
201
+ 1. Bump `__version__` in `src/tmuxp_plugin_worktree.py` and commit.
202
+ 2. Tag and push: `git tag v0.1.0 && git push origin main v0.1.0`.
203
+ 3. The `publish` workflow builds the package and uploads it to PyPI with
204
+ trusted publishing; no API token is needed.
205
+
206
+ ## License
207
+
208
+ [MIT](LICENSE).
@@ -0,0 +1,179 @@
1
+ # tmuxp-plugin-worktree
2
+
3
+ A [tmuxp](https://github.com/tmux-python/tmuxp) plugin that lets you pick the git
4
+ worktree a session starts in.
5
+
6
+ When the repository of a session's `start_directory` has more than one worktree,
7
+ `tmuxp load <session>` first shows a picker with the configured directory
8
+ preselected:
9
+
10
+ ```text
11
+ worktree>
12
+ Session myapp: pick a worktree (Enter = start, Esc = cancel)
13
+ > myrepo [main] (default)
14
+ myrepo-feature-x [feature/x]
15
+ myrepo-hotfix [hotfix/login]
16
+ ```
17
+
18
+ Picking another worktree:
19
+
20
+ - moves every session, window and pane `start_directory` inside the repository
21
+ into that worktree (relative `cd` commands in your panes keep working), and a
22
+ `before_script` that lives in the repository;
23
+ - renames the session to `<session>-<worktree>` (for example `myapp-feature-x`),
24
+ so it can run next to the default session.
25
+
26
+ A branch may not have every directory your workspace uses. A directory that
27
+ exists in the default worktree but is missing in the chosen worktree is replaced
28
+ by its nearest existing parent, with a note on stderr (tmux would otherwise
29
+ silently start the pane in `$HOME`). Window and pane directories are checked
30
+ after `before_script`, so setup can create them first. The session directory is
31
+ resolved earlier to provide setup with a working directory.
32
+
33
+ A `before_script` the chosen worktree does not have, such as an untracked file,
34
+ keeps running from the default worktree. Its arguments are preserved, including
35
+ quoting and spaces; only the executable's path is rewritten.
36
+
37
+ With a single worktree, or when the start directory is not a git repository,
38
+ nothing changes and no picker is shown.
39
+
40
+ ## Requirements
41
+
42
+ - tmuxp 1.73 or newer for the no-install setup (`workspace_builder_paths`);
43
+ tested with tmuxp 1.73, 1.74 and 1.76
44
+ - git
45
+ - fzf (optional; without it you get a numbered menu)
46
+ - Python 3.10 or newer (the Python that tmuxp runs on)
47
+
48
+ ## Installation
49
+
50
+ ### Option A: install from PyPI (recommended)
51
+
52
+ Install the package into the Python environment tmuxp runs in; then only the
53
+ `plugins` key is needed in your workspace files.
54
+
55
+ ```bash
56
+ # tmuxp installed with pipx
57
+ pipx inject tmuxp tmuxp-plugin-worktree
58
+
59
+ # tmuxp installed with uv
60
+ uv tool install tmuxp --with tmuxp-plugin-worktree
61
+
62
+ # tmuxp installed with pip in a virtualenv (activate it first)
63
+ python -m pip install tmuxp-plugin-worktree
64
+ ```
65
+
66
+ ```yaml
67
+ session_name: myapp
68
+ start_directory: ~/code/myrepo
69
+ plugins:
70
+ - tmuxp_plugin_worktree.WorktreePlugin
71
+ windows:
72
+ - window_name: editor
73
+ panes:
74
+ - nvim
75
+ ```
76
+
77
+ ### Option B: no install (works with Homebrew's tmuxp)
78
+
79
+ Homebrew installs tmuxp in a private virtualenv without pip. Since 1.73, tmuxp
80
+ can add import paths per workspace with `workspace_builder_paths`, so you can
81
+ point it at a checkout instead:
82
+
83
+ ```bash
84
+ git clone https://github.com/rhelling/tmuxp-plugin-worktree.git ~/Documents/Projects/tmuxp-plugin-worktree
85
+ ```
86
+
87
+ ```yaml
88
+ session_name: myapp
89
+ start_directory: ~/code/myrepo
90
+ workspace_builder_paths:
91
+ - ~/Documents/Projects/tmuxp-plugin-worktree/src
92
+ plugins:
93
+ - tmuxp_plugin_worktree.WorktreePlugin
94
+ windows:
95
+ - window_name: editor
96
+ panes:
97
+ - nvim
98
+ ```
99
+
100
+ Relative entries in `workspace_builder_paths` are resolved against the directory
101
+ of the workspace file.
102
+
103
+ ### Check that it works
104
+
105
+ ```bash
106
+ tmuxp load myapp # picker when the repo has 2+ worktrees
107
+ WT_PATH=myrepo-feature-x tmuxp load -d myapp # straight into that worktree, detached
108
+ ```
109
+
110
+ ## Usage
111
+
112
+ - **fzf picker:** Enter starts the highlighted entry (the default is preselected),
113
+ typing filters the list, Esc or Ctrl-C cancels without starting anything.
114
+ `FZF_DEFAULT_OPTS` and `FZF_DEFAULT_OPTS_FILE` are ignored for this picker to
115
+ keep its output format predictable.
116
+ - **Without fzf:** type a number and press Enter, or press Enter for the default.
117
+ Esc, Ctrl-C or Ctrl-D cancels.
118
+ - **No picker:** `WT_PATH=myrepo-feature-x tmuxp load myapp`. A relative
119
+ `WT_PATH` is resolved against the directory that contains the default
120
+ repository; absolute paths and `~/...` work too. An unknown worktree aborts
121
+ with the list of valid choices. A session whose start directory is not in a
122
+ git repository (or that has no `start_directory`) ignores `WT_PATH`, with a
123
+ note.
124
+ - **No terminal** (scripts, cron, CI): the default worktree is used unless
125
+ `WT_PATH` is set.
126
+ - Prunable worktrees (their directory is gone) and bare repositories are not
127
+ offered.
128
+
129
+ ## How it works
130
+
131
+ tmuxp creates plugins after it has expanded the workspace file, but before it
132
+ checks for an existing session and builds the windows. The plugin uses that
133
+ moment to rewrite the expanded configuration: every path inside the default
134
+ repository is moved into the chosen worktree and the session name gets the
135
+ worktree suffix. tmuxp does not pass the configuration to plugins, so the plugin
136
+ finds it in the calling frames; this is verified against tmuxp 1.73, 1.74 and 1.76.
137
+
138
+ When a directory fallback needs to wait for `before_script`, the plugin runs
139
+ setup once through tmuxp's script runner in its `before_workspace_builder` hook,
140
+ then finalizes the window and pane paths. Existing sessions do not rerun setup.
141
+ For this case, tmuxp's script-progress callbacks are bypassed. If using other
142
+ plugins, list this plugin last so their preparation hooks still run before setup.
143
+
144
+ ## Limitations
145
+
146
+ - Absolute paths inside `shell_command` or `shell_command_before` are not
147
+ rewritten; use `start_directory` and relative `cd` commands instead.
148
+ - The session-name suffix comes from the worktree's directory name:
149
+ `myrepo-feature-x` becomes `feature-x`, any other name is used as is. Dots and
150
+ colons become `-`, because tmux does not allow them in session names. If
151
+ multiple worktrees produce the same session name, selecting one aborts with
152
+ a list of the conflicting paths. Rename those worktree directories rather
153
+ than silently reusing another worktree's session.
154
+
155
+ ## Development
156
+
157
+ ```bash
158
+ python3 -m venv .venv
159
+ .venv/bin/pip install -e '.[test]'
160
+ .venv/bin/pytest
161
+ ```
162
+
163
+ The end-to-end tests need `tmux` and `git`. They create throwaway repositories
164
+ and run tmuxp against a private tmux server, so your own sessions are never
165
+ touched. The fzf tests are skipped when fzf is not installed.
166
+
167
+ See [TESTING.md](TESTING.md) for what the tests cover, running a subset or
168
+ another tmuxp version, a manual test checklist and troubleshooting.
169
+
170
+ ## Releasing
171
+
172
+ 1. Bump `__version__` in `src/tmuxp_plugin_worktree.py` and commit.
173
+ 2. Tag and push: `git tag v0.1.0 && git push origin main v0.1.0`.
174
+ 3. The `publish` workflow builds the package and uploads it to PyPI with
175
+ trusted publishing; no API token is needed.
176
+
177
+ ## License
178
+
179
+ [MIT](LICENSE).
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tmuxp-plugin-worktree"
7
+ dynamic = ["version"]
8
+ description = "tmuxp plugin: pick the git worktree a session starts in"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "Robbert Helling" }]
14
+ dependencies = ["tmuxp>=1.73"]
15
+ keywords = ["tmux", "tmuxp", "git", "worktree", "plugin"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Environment :: Plugins",
20
+ "Intended Audience :: Developers",
21
+ "Operating System :: MacOS",
22
+ "Operating System :: POSIX :: Linux",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3 :: Only",
25
+ "Topic :: Software Development :: Version Control :: Git",
26
+ "Topic :: Terminals",
27
+ "Topic :: Utilities",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/rhelling/tmuxp-plugin-worktree"
32
+ Issues = "https://github.com/rhelling/tmuxp-plugin-worktree/issues"
33
+ Changelog = "https://github.com/rhelling/tmuxp-plugin-worktree/releases"
34
+
35
+ [project.optional-dependencies]
36
+ test = ["pytest>=7"]
37
+
38
+ [tool.setuptools]
39
+ package-dir = { "" = "src" }
40
+ py-modules = ["tmuxp_plugin_worktree"]
41
+
42
+ [tool.setuptools.dynamic]
43
+ version = { attr = "tmuxp_plugin_worktree.__version__" }
44
+
45
+ [tool.pytest.ini_options]
46
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: tmuxp-plugin-worktree
3
+ Version: 0.1.0
4
+ Summary: tmuxp plugin: pick the git worktree a session starts in
5
+ Author: Robbert Helling
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rhelling/tmuxp-plugin-worktree
8
+ Project-URL: Issues, https://github.com/rhelling/tmuxp-plugin-worktree/issues
9
+ Project-URL: Changelog, https://github.com/rhelling/tmuxp-plugin-worktree/releases
10
+ Keywords: tmux,tmuxp,git,worktree,plugin
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Plugins
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Topic :: Software Development :: Version Control :: Git
20
+ Classifier: Topic :: Terminals
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: tmuxp>=1.73
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest>=7; extra == "test"
28
+ Dynamic: license-file
29
+
30
+ # tmuxp-plugin-worktree
31
+
32
+ A [tmuxp](https://github.com/tmux-python/tmuxp) plugin that lets you pick the git
33
+ worktree a session starts in.
34
+
35
+ When the repository of a session's `start_directory` has more than one worktree,
36
+ `tmuxp load <session>` first shows a picker with the configured directory
37
+ preselected:
38
+
39
+ ```text
40
+ worktree>
41
+ Session myapp: pick a worktree (Enter = start, Esc = cancel)
42
+ > myrepo [main] (default)
43
+ myrepo-feature-x [feature/x]
44
+ myrepo-hotfix [hotfix/login]
45
+ ```
46
+
47
+ Picking another worktree:
48
+
49
+ - moves every session, window and pane `start_directory` inside the repository
50
+ into that worktree (relative `cd` commands in your panes keep working), and a
51
+ `before_script` that lives in the repository;
52
+ - renames the session to `<session>-<worktree>` (for example `myapp-feature-x`),
53
+ so it can run next to the default session.
54
+
55
+ A branch may not have every directory your workspace uses. A directory that
56
+ exists in the default worktree but is missing in the chosen worktree is replaced
57
+ by its nearest existing parent, with a note on stderr (tmux would otherwise
58
+ silently start the pane in `$HOME`). Window and pane directories are checked
59
+ after `before_script`, so setup can create them first. The session directory is
60
+ resolved earlier to provide setup with a working directory.
61
+
62
+ A `before_script` the chosen worktree does not have, such as an untracked file,
63
+ keeps running from the default worktree. Its arguments are preserved, including
64
+ quoting and spaces; only the executable's path is rewritten.
65
+
66
+ With a single worktree, or when the start directory is not a git repository,
67
+ nothing changes and no picker is shown.
68
+
69
+ ## Requirements
70
+
71
+ - tmuxp 1.73 or newer for the no-install setup (`workspace_builder_paths`);
72
+ tested with tmuxp 1.73, 1.74 and 1.76
73
+ - git
74
+ - fzf (optional; without it you get a numbered menu)
75
+ - Python 3.10 or newer (the Python that tmuxp runs on)
76
+
77
+ ## Installation
78
+
79
+ ### Option A: install from PyPI (recommended)
80
+
81
+ Install the package into the Python environment tmuxp runs in; then only the
82
+ `plugins` key is needed in your workspace files.
83
+
84
+ ```bash
85
+ # tmuxp installed with pipx
86
+ pipx inject tmuxp tmuxp-plugin-worktree
87
+
88
+ # tmuxp installed with uv
89
+ uv tool install tmuxp --with tmuxp-plugin-worktree
90
+
91
+ # tmuxp installed with pip in a virtualenv (activate it first)
92
+ python -m pip install tmuxp-plugin-worktree
93
+ ```
94
+
95
+ ```yaml
96
+ session_name: myapp
97
+ start_directory: ~/code/myrepo
98
+ plugins:
99
+ - tmuxp_plugin_worktree.WorktreePlugin
100
+ windows:
101
+ - window_name: editor
102
+ panes:
103
+ - nvim
104
+ ```
105
+
106
+ ### Option B: no install (works with Homebrew's tmuxp)
107
+
108
+ Homebrew installs tmuxp in a private virtualenv without pip. Since 1.73, tmuxp
109
+ can add import paths per workspace with `workspace_builder_paths`, so you can
110
+ point it at a checkout instead:
111
+
112
+ ```bash
113
+ git clone https://github.com/rhelling/tmuxp-plugin-worktree.git ~/Documents/Projects/tmuxp-plugin-worktree
114
+ ```
115
+
116
+ ```yaml
117
+ session_name: myapp
118
+ start_directory: ~/code/myrepo
119
+ workspace_builder_paths:
120
+ - ~/Documents/Projects/tmuxp-plugin-worktree/src
121
+ plugins:
122
+ - tmuxp_plugin_worktree.WorktreePlugin
123
+ windows:
124
+ - window_name: editor
125
+ panes:
126
+ - nvim
127
+ ```
128
+
129
+ Relative entries in `workspace_builder_paths` are resolved against the directory
130
+ of the workspace file.
131
+
132
+ ### Check that it works
133
+
134
+ ```bash
135
+ tmuxp load myapp # picker when the repo has 2+ worktrees
136
+ WT_PATH=myrepo-feature-x tmuxp load -d myapp # straight into that worktree, detached
137
+ ```
138
+
139
+ ## Usage
140
+
141
+ - **fzf picker:** Enter starts the highlighted entry (the default is preselected),
142
+ typing filters the list, Esc or Ctrl-C cancels without starting anything.
143
+ `FZF_DEFAULT_OPTS` and `FZF_DEFAULT_OPTS_FILE` are ignored for this picker to
144
+ keep its output format predictable.
145
+ - **Without fzf:** type a number and press Enter, or press Enter for the default.
146
+ Esc, Ctrl-C or Ctrl-D cancels.
147
+ - **No picker:** `WT_PATH=myrepo-feature-x tmuxp load myapp`. A relative
148
+ `WT_PATH` is resolved against the directory that contains the default
149
+ repository; absolute paths and `~/...` work too. An unknown worktree aborts
150
+ with the list of valid choices. A session whose start directory is not in a
151
+ git repository (or that has no `start_directory`) ignores `WT_PATH`, with a
152
+ note.
153
+ - **No terminal** (scripts, cron, CI): the default worktree is used unless
154
+ `WT_PATH` is set.
155
+ - Prunable worktrees (their directory is gone) and bare repositories are not
156
+ offered.
157
+
158
+ ## How it works
159
+
160
+ tmuxp creates plugins after it has expanded the workspace file, but before it
161
+ checks for an existing session and builds the windows. The plugin uses that
162
+ moment to rewrite the expanded configuration: every path inside the default
163
+ repository is moved into the chosen worktree and the session name gets the
164
+ worktree suffix. tmuxp does not pass the configuration to plugins, so the plugin
165
+ finds it in the calling frames; this is verified against tmuxp 1.73, 1.74 and 1.76.
166
+
167
+ When a directory fallback needs to wait for `before_script`, the plugin runs
168
+ setup once through tmuxp's script runner in its `before_workspace_builder` hook,
169
+ then finalizes the window and pane paths. Existing sessions do not rerun setup.
170
+ For this case, tmuxp's script-progress callbacks are bypassed. If using other
171
+ plugins, list this plugin last so their preparation hooks still run before setup.
172
+
173
+ ## Limitations
174
+
175
+ - Absolute paths inside `shell_command` or `shell_command_before` are not
176
+ rewritten; use `start_directory` and relative `cd` commands instead.
177
+ - The session-name suffix comes from the worktree's directory name:
178
+ `myrepo-feature-x` becomes `feature-x`, any other name is used as is. Dots and
179
+ colons become `-`, because tmux does not allow them in session names. If
180
+ multiple worktrees produce the same session name, selecting one aborts with
181
+ a list of the conflicting paths. Rename those worktree directories rather
182
+ than silently reusing another worktree's session.
183
+
184
+ ## Development
185
+
186
+ ```bash
187
+ python3 -m venv .venv
188
+ .venv/bin/pip install -e '.[test]'
189
+ .venv/bin/pytest
190
+ ```
191
+
192
+ The end-to-end tests need `tmux` and `git`. They create throwaway repositories
193
+ and run tmuxp against a private tmux server, so your own sessions are never
194
+ touched. The fzf tests are skipped when fzf is not installed.
195
+
196
+ See [TESTING.md](TESTING.md) for what the tests cover, running a subset or
197
+ another tmuxp version, a manual test checklist and troubleshooting.
198
+
199
+ ## Releasing
200
+
201
+ 1. Bump `__version__` in `src/tmuxp_plugin_worktree.py` and commit.
202
+ 2. Tag and push: `git tag v0.1.0 && git push origin main v0.1.0`.
203
+ 3. The `publish` workflow builds the package and uploads it to PyPI with
204
+ trusted publishing; no API token is needed.
205
+
206
+ ## License
207
+
208
+ [MIT](LICENSE).
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/tmuxp_plugin_worktree.py
5
+ src/tmuxp_plugin_worktree.egg-info/PKG-INFO
6
+ src/tmuxp_plugin_worktree.egg-info/SOURCES.txt
7
+ src/tmuxp_plugin_worktree.egg-info/dependency_links.txt
8
+ src/tmuxp_plugin_worktree.egg-info/requires.txt
9
+ src/tmuxp_plugin_worktree.egg-info/top_level.txt
10
+ tests/test_e2e.py
11
+ tests/test_helpers.py
@@ -0,0 +1,4 @@
1
+ tmuxp>=1.73
2
+
3
+ [test]
4
+ pytest>=7