ctree 0.5.3
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +63 -0
- data/LICENSE +21 -0
- data/README.md +491 -0
- data/bin/ctree +7 -0
- data/lib/ctree/cli.rb +402 -0
- data/lib/ctree/compose_config_cmd.rb +136 -0
- data/lib/ctree/config.rb +242 -0
- data/lib/ctree/config.yml +111 -0
- data/lib/ctree/create.rb +714 -0
- data/lib/ctree/delete.rb +313 -0
- data/lib/ctree/domain.rb +158 -0
- data/lib/ctree/env_cmd.rb +123 -0
- data/lib/ctree/free.rb +79 -0
- data/lib/ctree/list.rb +101 -0
- data/lib/ctree/rebase.rb +221 -0
- data/lib/ctree/sync.rb +17 -0
- data/lib/ctree/update.rb +354 -0
- data/lib/ctree/version.rb +5 -0
- data/lib/ctree.rb +935 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8abbf0956853273481c598fe775b0da106a06f6fdd9a49d54598bd16e08cf566
|
|
4
|
+
data.tar.gz: b663bf6b45e76e44fc67cf93a3d49a2b287c3f184a6bdbc9520a9ea757a81c5e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 37489240879d544d297168677500092b26e57d473af18b36ecdbdcc7bc68fa4d14600c0957f037ec24912fccb33129e8e351a1fb5ae849625fd084171731c274
|
|
7
|
+
data.tar.gz: 87db5c5490d551df4abba9572f1568d2fa4fd06e2474274e7c32338445931665114e3c9fcd56b62bad4220d0a6179fdd66ce8d5cf476f6642dedd5a10619e210
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.5.3] - 2026-10-12
|
|
11
|
+
|
|
12
|
+
- Added gemspec
|
|
13
|
+
- Added file/volume size to log file
|
|
14
|
+
- Cleaned up the codebase
|
|
15
|
+
|
|
16
|
+
## [0.5.2] - 2026-10-06
|
|
17
|
+
|
|
18
|
+
- Added default-branch detection
|
|
19
|
+
- Fixed flakey specs
|
|
20
|
+
|
|
21
|
+
## [0.5.1] - 2026-10-01
|
|
22
|
+
|
|
23
|
+
- Improved rebase and update log messages
|
|
24
|
+
- Removed summary blocks from log file
|
|
25
|
+
- Fixed duplicate "copied ..." lines in log file
|
|
26
|
+
- Removed display of spinner for post rebase/update hooks
|
|
27
|
+
- Fixed sync exiting after rebase without running update
|
|
28
|
+
- Added errors from post rebase/update hooks in log file
|
|
29
|
+
|
|
30
|
+
## [0.5.0] - 2026-09-25
|
|
31
|
+
|
|
32
|
+
- Removed double action lines from log file
|
|
33
|
+
- Removed the boundary marker from appended log files
|
|
34
|
+
- Removed DEBUG: prefix from log file entries
|
|
35
|
+
- Changed --log-file to append to an existing file instead of overwriting it
|
|
36
|
+
- Removed switch and shell-init commands
|
|
37
|
+
|
|
38
|
+
## [0.4.0] - 2026-09-18
|
|
39
|
+
|
|
40
|
+
- Fixed spinner in free command log
|
|
41
|
+
- Removed confirmation prompt from free command
|
|
42
|
+
- Added log prefix support for domain command
|
|
43
|
+
- Added no-current option for list command
|
|
44
|
+
- Added sync command and post-rebase hooks
|
|
45
|
+
- Added CTREE_LOG_PREFIX env var
|
|
46
|
+
- Added log prefix config option
|
|
47
|
+
|
|
48
|
+
## [0.3.0] - 2026-09-10
|
|
49
|
+
|
|
50
|
+
- Added support for equals syntax for --config and --log-file
|
|
51
|
+
- Added an option to redirect command output to a log file
|
|
52
|
+
- Removed interactive prompts from log in non-interactive mode
|
|
53
|
+
- Added an option to run commands non-interactively
|
|
54
|
+
|
|
55
|
+
## [0.2.0] - 2026-08-20
|
|
56
|
+
|
|
57
|
+
- Prevented creation of duplicate volumes for shared volumes
|
|
58
|
+
- Changed how .ctree is created in the worktree (it is no longer copied from the source repo)
|
|
59
|
+
- Added an option to use a custom config file during worktree creation
|
|
60
|
+
|
|
61
|
+
## [0.1.0] - 2026-07-11
|
|
62
|
+
|
|
63
|
+
Initial commit.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Martin Yosifov
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
# ctree
|
|
2
|
+
|
|
3
|
+
Replicate any Docker-compose based git repo as a sibling git worktree,
|
|
4
|
+
with its own branch, docker volumes, and a tailored `.env`, so that
|
|
5
|
+
multiple branches can run side by side without interfering with
|
|
6
|
+
each other's state.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
### From RubyGems (recommended)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
gem install ctree
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This places the `ctree` binary on your `PATH` automatically. Verify:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
ctree list # sanity-check that the binary runs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### From source
|
|
23
|
+
|
|
24
|
+
If you want to use the latest unreleased code, clone the repository
|
|
25
|
+
and add its `bin` directory to your `PATH` so the `ctree` binary
|
|
26
|
+
is available in every terminal:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd your_repositories_directory
|
|
30
|
+
git clone https://github.com/mytrak/ctree.git
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Execute the command below to add an entry for ctree to your
|
|
34
|
+
**`~/.zshrc`** (zsh, the macOS default) or **`~/.bashrc`** (bash).
|
|
35
|
+
Don't add an entry to `~/.bash_profile` or `~/.zprofile` as those run
|
|
36
|
+
only for login shells, but `ctree` needs to be on `PATH` for every
|
|
37
|
+
interactive shell.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cd ctree
|
|
41
|
+
echo "export PATH=\"$(pwd)/bin:\$PATH\"" >> ~/.zshrc
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then reload the file (or just open a new terminal tab):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
source ~/.zshrc
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Verify:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
type ctree # should print: ctree is /path/to/ctree/bin/ctree
|
|
54
|
+
ctree list # sanity-check that the binary runs
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Troubleshooting
|
|
58
|
+
|
|
59
|
+
**`command not found: ctree` in a fresh terminal** — `.zshrc` either
|
|
60
|
+
isn't being read or it bailed early, or the exported `PATH` entry
|
|
61
|
+
doesn't point at the directory containing the `ctree` executable.
|
|
62
|
+
Check `echo $0` (should be `-zsh`), then confirm the `export PATH`
|
|
63
|
+
line is correct.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
Most commands run from the source repository.
|
|
68
|
+
`update`, `rebase`, `sync`, `free`, `env`, and `compose-config` run from inside
|
|
69
|
+
a worktree.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
ctree create <worktree_name> <branch_name>
|
|
73
|
+
ctree delete <worktree_name>
|
|
74
|
+
ctree list [all | free | used]
|
|
75
|
+
ctree rebase
|
|
76
|
+
ctree update
|
|
77
|
+
ctree free
|
|
78
|
+
ctree env [list | check | fix]
|
|
79
|
+
ctree version
|
|
80
|
+
ctree domain [list | [add | delete] <tld>]
|
|
81
|
+
ctree config [list | add | delete]
|
|
82
|
+
ctree compose-config [list | check | fix]
|
|
83
|
+
ctree sync
|
|
84
|
+
ctree help <command>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Any command that normally prompt for confirmation — `create`, `delete`,
|
|
88
|
+
`rebase`, `update`, `env fix` and `config add/delete` — accepts
|
|
89
|
+
a global `--force` flag that skips the prompts and assumes the default
|
|
90
|
+
answer shown in brackets. For prompts with no bracket default (i.e. ones
|
|
91
|
+
that ask you to type the literal word "yes"), `--force` assumes yes.
|
|
92
|
+
Use `ctree help <command>` for per-command specifics, including the cases
|
|
93
|
+
where the assumed default means *not* proceeding (e.g. `rebase` and
|
|
94
|
+
`update` against a dirty or off-branch source).
|
|
95
|
+
|
|
96
|
+
### create
|
|
97
|
+
|
|
98
|
+
Creates a sibling worktree at `../<worktree_name>`. The entire source
|
|
99
|
+
directory — tracked files AND gitignored runtime content (node_modules,
|
|
100
|
+
build artifacts, plugin lock files, etc.) — is cloned into the new
|
|
101
|
+
worktree in one operation. On macOS APFS this is near-instant CoW via
|
|
102
|
+
`clonefile(2)`; on Linux, `cp --reflink=auto` provides the same for
|
|
103
|
+
btrfs/xfs and falls back to a plain copy on ext4.
|
|
104
|
+
|
|
105
|
+
After the cloning, docker volumes are replicated under the new compose
|
|
106
|
+
prefix and a tailored `.env` is written with `COMPOSE_PROJECT_NAME`.
|
|
107
|
+
For each constant defined in the source `.env` you will be prompted
|
|
108
|
+
to either accept or update the value for the worktree.
|
|
109
|
+
|
|
110
|
+
The optional `--config <path>` flag lets you create a worktree with a
|
|
111
|
+
custom configuration that differs from the repo's shared `.ctree/config.yml`.
|
|
112
|
+
The file is merged over the shipped defaults (the repo config layer is
|
|
113
|
+
skipped for this worktree) and persisted into the worktree's own
|
|
114
|
+
`.ctree/config.yml` so that later commands like `update`, `rebase`,
|
|
115
|
+
`free`, and `env` continue to use it automatically. The path is
|
|
116
|
+
relative to the current directory.
|
|
117
|
+
|
|
118
|
+
### delete
|
|
119
|
+
|
|
120
|
+
Reverses `create`: lists everything that would be deleted, prompts
|
|
121
|
+
for explicit `yes` confirmation, then tears it all down — the worktree
|
|
122
|
+
directory, its `git worktree` registration, the per-project docker
|
|
123
|
+
volumes, and any running compose stack.
|
|
124
|
+
|
|
125
|
+
**Branches are always preserved**, including the auto-derived branch
|
|
126
|
+
that `ctree create <name>` creates when no explicit branch is passed.
|
|
127
|
+
This is deliberately safe: an auto-derived branch can still carry
|
|
128
|
+
commits you want to keep, push, or re-check-out in a fresh worktree
|
|
129
|
+
later, and ctree can't tell from the branch itself whether that's the
|
|
130
|
+
case.
|
|
131
|
+
|
|
132
|
+
### list
|
|
133
|
+
|
|
134
|
+
Lists all worktrees for the current source repo. Each entry shows the
|
|
135
|
+
worktree path and its checked-out branch.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
ctree list # all worktrees
|
|
139
|
+
ctree list all # same as above
|
|
140
|
+
ctree list free # only worktrees on a free placeholder branch
|
|
141
|
+
ctree list used # only worktrees on a non-free branch
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Worktrees on a branch whose name starts with `free_branch_prefix`
|
|
145
|
+
(default `FREE-`, configurable in `.ctree/config.yml`) are annotated
|
|
146
|
+
with `(free)`. `ctree list free` limits output to those worktrees;
|
|
147
|
+
`ctree list used` shows the rest.
|
|
148
|
+
|
|
149
|
+
### rebase
|
|
150
|
+
|
|
151
|
+
Run **from inside a worktree** (no arguments). Does two things in order:
|
|
152
|
+
|
|
153
|
+
1. Rebases the worktree's current branch onto the source repo's `master`.
|
|
154
|
+
Skips automatically if `master` is already an ancestor (i.e. the
|
|
155
|
+
branch is already up to date). Aborts and reports conflicts if the
|
|
156
|
+
rebase cannot complete cleanly.
|
|
157
|
+
2. Rebases each embedded git repo listed under `rebase` in
|
|
158
|
+
`.ctree/config.yml` (e.g. `gems/plugins`) from its source
|
|
159
|
+
counterpart.
|
|
160
|
+
|
|
161
|
+
All operations are local — no network calls are made. Update the source
|
|
162
|
+
repo first, then run `ctree rebase` from the worktree to catch it up.
|
|
163
|
+
|
|
164
|
+
### update
|
|
165
|
+
|
|
166
|
+
Run **from inside a worktree** (no arguments). ctree resolves the source repo
|
|
167
|
+
from git's common dir, then:
|
|
168
|
+
|
|
169
|
+
1. Re-tags the source's images to the worktree's project name, so the worktree
|
|
170
|
+
picks up images the source rebuilt (e.g. after rebuilding source images).
|
|
171
|
+
2. Rsyncs allowlisted volumes (`update_volumes`) from source to worktree.
|
|
172
|
+
3. Copies or syncs any paths listed in `update` from source to worktree (see
|
|
173
|
+
schema below).
|
|
174
|
+
|
|
175
|
+
Shared volumes (`share_volumes`, e.g. gems/node_modules) are mounted
|
|
176
|
+
from the source via the override file, so they are already live — update
|
|
177
|
+
does not copy them.
|
|
178
|
+
|
|
179
|
+
Before doing anything, ctree warns and asks for confirmation (default **no**)
|
|
180
|
+
if the source is on a non-default branch.
|
|
181
|
+
|
|
182
|
+
### sync
|
|
183
|
+
|
|
184
|
+
Run **from inside a worktree** (no arguments). Convenience wrapper that runs
|
|
185
|
+
`rebase` and then `update` in sequence, so a single command brings the
|
|
186
|
+
worktree fully up to date with the source. All operations are local — no
|
|
187
|
+
network calls. Update the source repo first, then run `ctree sync` from the
|
|
188
|
+
worktree to catch it up.
|
|
189
|
+
|
|
190
|
+
### free
|
|
191
|
+
|
|
192
|
+
Run **from inside a worktree** (no arguments). Resets the worktree to a free
|
|
193
|
+
placeholder branch so it can be reused. ctree:
|
|
194
|
+
|
|
195
|
+
1. Lists all local branches whose names start with the configured
|
|
196
|
+
`free_branch_prefix` (default `FREE-`).
|
|
197
|
+
2. Checks out the first available branch — one not currently checked out in
|
|
198
|
+
any worktree — sorted alphabetically.
|
|
199
|
+
3. If all free branches are occupied, creates the next sequential one,
|
|
200
|
+
filling gaps in the numeric sequence. For example, if `FREE-001` and
|
|
201
|
+
`FREE-003` both exist and are checked out, it creates and checks out
|
|
202
|
+
`FREE-002`. If no free branches exist at all, it creates `FREE-001`.
|
|
203
|
+
Numbers are zero-padded to at least 3 digits (`FREE-001`, `FREE-002`, …).
|
|
204
|
+
4. Rebases the checked-out branch onto the source repo's `master` (skipped
|
|
205
|
+
automatically if already up to date). Aborts and reports on conflict —
|
|
206
|
+
resolve manually and re-run `ctree rebase` from the worktree.
|
|
207
|
+
|
|
208
|
+
### env
|
|
209
|
+
|
|
210
|
+
Run **from inside a worktree**. Manages the worktree's `.env` relative to
|
|
211
|
+
the source repo's `.env`.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
ctree env list # print current worktree .env
|
|
215
|
+
ctree env check # report discrepancies
|
|
216
|
+
ctree env fix # resolve discrepancies interactively
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Prints all `KEY=VALUE` pairs from the worktree `.env`. No comparison
|
|
220
|
+
with the source is performed.
|
|
221
|
+
|
|
222
|
+
#### check
|
|
223
|
+
|
|
224
|
+
Reports discrepancies between the source and worktree `.env` and exits 1
|
|
225
|
+
if any are found:
|
|
226
|
+
|
|
227
|
+
- `[missing] KEY` — key present in the source `.env` but absent from the
|
|
228
|
+
worktree. All missing keys are reported, including those in
|
|
229
|
+
`skip_env_keys`.
|
|
230
|
+
- `[extra] KEY` — key present in the worktree `.env` but absent from the
|
|
231
|
+
source. ctree-managed keys (`COMPOSE_PROJECT_NAME`, `HOST_NAME`,
|
|
232
|
+
`HOST_NAME_SUFFIX`, and `host_domain_env_key` when configured) and keys
|
|
233
|
+
in `skip_env_keys` are never reported as extra.
|
|
234
|
+
|
|
235
|
+
Exits 0 if the envs are in sync.
|
|
236
|
+
|
|
237
|
+
#### fix
|
|
238
|
+
|
|
239
|
+
Resolves discrepancies interactively, acting only on actual gaps:
|
|
240
|
+
|
|
241
|
+
- **Missing keys** — prompts with the source value as the default; press
|
|
242
|
+
enter to accept or type a new value.
|
|
243
|
+
- **Extra keys** — offers deletion (`[y/N]`); defaults to keeping the key.
|
|
244
|
+
- **Keys already present in both** — left untouched, no prompt shown.
|
|
245
|
+
|
|
246
|
+
ctree-managed keys and `skip_env_keys` are never offered for deletion.
|
|
247
|
+
Missing keys are always prompted regardless of `skip_env_keys`.
|
|
248
|
+
|
|
249
|
+
### compose-config
|
|
250
|
+
|
|
251
|
+
Run **from inside a worktree**. Manages shared-volume external references
|
|
252
|
+
in the compose override file (configured via `compose_override_file` in
|
|
253
|
+
`.ctree/config.yml`).
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
ctree compose-config list # show current state of the override file
|
|
257
|
+
ctree compose-config check # report missing or incorrect external references
|
|
258
|
+
ctree compose-config fix # write corrections automatically
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`fix` rewrites the override file to add correct `external: true` and
|
|
262
|
+
`name: <source_project>_<suffix>` entries for any `share_volumes` that
|
|
263
|
+
are missing or incorrect.
|
|
264
|
+
|
|
265
|
+
### domain
|
|
266
|
+
|
|
267
|
+
**macOS only.** Configures local DNS resolution for a TLD so that all
|
|
268
|
+
`*.tld` names resolve to `127.0.0.1`.
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
ctree domain list # show configured TLDs and resolver status
|
|
272
|
+
ctree domain add <tld> # add wildcard DNS rule for <tld>
|
|
273
|
+
ctree domain delete <tld> # remove wildcard DNS rule for <tld>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
`add <tld>` writes a wildcard dnsmasq rule (`address=/.tld/127.0.0.1`)
|
|
277
|
+
and creates a macOS resolver file at `/etc/resolver/<tld>` (requires
|
|
278
|
+
`sudo`). `delete <tld>` removes both. `list` shows which TLDs are
|
|
279
|
+
configured in dnsmasq and whether their `/etc/resolver/<tld>` files are
|
|
280
|
+
present.
|
|
281
|
+
|
|
282
|
+
## Configuration
|
|
283
|
+
|
|
284
|
+
Which docker volumes ctree copies, syncs, or treats as source-shared caches
|
|
285
|
+
is controlled by config — not by hardcoded values in the executable. There
|
|
286
|
+
are two layers, with an optional third that replaces the per-repo layer for
|
|
287
|
+
a single worktree:
|
|
288
|
+
|
|
289
|
+
1. **Shipped defaults** in `lib/ctree/config.yml` (loaded automatically).
|
|
290
|
+
2. **Per-repo override** at `<source_repo>/.ctree/config.yml` (optional).
|
|
291
|
+
Keys present here replace the shipped values; keys you omit fall through
|
|
292
|
+
to the defaults.
|
|
293
|
+
3. **`ctree create --config <path>`** (optional, per-worktree). Skips the
|
|
294
|
+
per-repo layer entirely for that worktree and merges the named file over
|
|
295
|
+
shipped defaults instead. The custom file is persisted into the
|
|
296
|
+
worktree's own `.ctree/config.yml` so that later commands (`update`,
|
|
297
|
+
`rebase`, `free`, `env`, `compose-config`) continue to use it.
|
|
298
|
+
|
|
299
|
+
### Schema
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
# <source_repo>/.ctree/config.yml — all keys are optional
|
|
303
|
+
|
|
304
|
+
# Volumes to share between the source and every worktree.
|
|
305
|
+
# List the SUFFIX only — the part after the leading `<project>_`.
|
|
306
|
+
#
|
|
307
|
+
# Full volume name Suffix to list
|
|
308
|
+
# ------------------------ ---------------
|
|
309
|
+
# myapp_yarn-cache → yarn-cache
|
|
310
|
+
# myapp_app-gems app-gems
|
|
311
|
+
#
|
|
312
|
+
# ctree rewrites the worktree's override file to mount the source volume
|
|
313
|
+
# directly (external: true) rather than creating a new empty one.
|
|
314
|
+
# Example:
|
|
315
|
+
# share_volumes:
|
|
316
|
+
# - yarn-cache
|
|
317
|
+
# - app-gems
|
|
318
|
+
|
|
319
|
+
# Volumes that `ctree update` is allowed to rsync from source into the worktree.
|
|
320
|
+
# List the SUFFIX only — the part after the leading `<project>_`.
|
|
321
|
+
#
|
|
322
|
+
# Full volume name Suffix to list
|
|
323
|
+
# ----------------- ---------------
|
|
324
|
+
# myapp_code → code
|
|
325
|
+
# myapp_bundle → bundle
|
|
326
|
+
#
|
|
327
|
+
# This is an allowlist — anything not listed is left untouched, so new
|
|
328
|
+
# stateful volumes fail closed rather than being silently overwritten.
|
|
329
|
+
# Example:
|
|
330
|
+
# update_volumes:
|
|
331
|
+
# - code
|
|
332
|
+
# - bundle
|
|
333
|
+
|
|
334
|
+
# Volume name suffixes created empty in the worktree during `ctree create`
|
|
335
|
+
# instead of being rsynced from source. Use for transient data that should
|
|
336
|
+
# always start fresh (logs, tmp files, reports). These volumes are also
|
|
337
|
+
# silently skipped by `ctree update`, regardless of update_volumes.
|
|
338
|
+
# Suffix = everything after the leading `<project>_`.
|
|
339
|
+
# Example:
|
|
340
|
+
# empty_volumes:
|
|
341
|
+
# - log
|
|
342
|
+
# - tmp
|
|
343
|
+
|
|
344
|
+
# Repo-relative files or directories copied/synced from source to worktree
|
|
345
|
+
# during `ctree create` and `ctree update`. Use for gitignored artifacts
|
|
346
|
+
# that must match the source after a volume sync (e.g. lock files for gem
|
|
347
|
+
# volumes). Files are copied directly; directories are synced
|
|
348
|
+
# recursively (additions, modifications, and deletions).
|
|
349
|
+
# Example:
|
|
350
|
+
# update:
|
|
351
|
+
# - Gemfile.plugins.lock # a gitignored lock file
|
|
352
|
+
|
|
353
|
+
# Top-level names (files or directories) to skip when cloning the source
|
|
354
|
+
# working tree during `ctree create`. Matched by basename.
|
|
355
|
+
# Example:
|
|
356
|
+
# exclude:
|
|
357
|
+
# - node_modules
|
|
358
|
+
|
|
359
|
+
# Directories (relative to repo root) scanned for embedded git repos
|
|
360
|
+
# during `ctree rebase`. Subdirectories with a .git entry that are not
|
|
361
|
+
# submodules are rebased from their source counterpart.
|
|
362
|
+
# Example:
|
|
363
|
+
# rebase:
|
|
364
|
+
# - gems/plugins
|
|
365
|
+
|
|
366
|
+
# The TLD appended to the worktree name to form HOST_NAME_SUFFIX
|
|
367
|
+
# in the worktree .env. Leave empty to disable.
|
|
368
|
+
# Example:
|
|
369
|
+
# host_name_suffix: docker
|
|
370
|
+
|
|
371
|
+
# The docker-compose override file ctree appends to the worktree's
|
|
372
|
+
# COMPOSE_FILE and rewrites shared-volume entries in.
|
|
373
|
+
# Example:
|
|
374
|
+
# compose_override_file: docker-compose.local.ctree.yml
|
|
375
|
+
|
|
376
|
+
# Branch name prefix used to identify free (placeholder) worktrees.
|
|
377
|
+
# `ctree list free/used` and `ctree free` use this to detect whether a
|
|
378
|
+
# worktree is available.
|
|
379
|
+
# Example:
|
|
380
|
+
# free_branch_prefix: "FREE-"
|
|
381
|
+
|
|
382
|
+
# Keys in the source .env that ctree never prompts to delete from the
|
|
383
|
+
# worktree — even if absent from the source. Use for per-worktree keys
|
|
384
|
+
# that are intentionally different from the source.
|
|
385
|
+
# Example:
|
|
386
|
+
# skip_env_keys:
|
|
387
|
+
# - SOME_KEY
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### How to configure
|
|
391
|
+
|
|
392
|
+
1. Scaffold an annotated starting file by running from inside
|
|
393
|
+
your source repo:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
ctree config add
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
This writes `<source_repo>/.ctree/config.yml` with the shipped defaults
|
|
400
|
+
verbatim (comments included). It refuses to overwrite an existing file
|
|
401
|
+
without confirmation, so it's safe to run if you're unsure. Run
|
|
402
|
+
`ctree config delete` to delete the file and its `.ctree` directory.
|
|
403
|
+
|
|
404
|
+
2. Edit the keys you want to change, and **remove the keys you want to
|
|
405
|
+
leave at the shipped defaults** — anything you delete falls through to
|
|
406
|
+
`lib/ctree/config.yml`. Example: a project that shares gems and
|
|
407
|
+
node_modules and also syncs a lock file:
|
|
408
|
+
|
|
409
|
+
```yaml
|
|
410
|
+
share_volumes:
|
|
411
|
+
- gems
|
|
412
|
+
- node_modules
|
|
413
|
+
update:
|
|
414
|
+
- Gemfile.plugins.lock
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
3. Commit `.ctree/config.yml` so collaborators on the same repo share the
|
|
418
|
+
configuration.
|
|
419
|
+
|
|
420
|
+
### Behavior on errors
|
|
421
|
+
|
|
422
|
+
- **No `.ctree.yml`** → silent; uses shipped defaults.
|
|
423
|
+
- **Malformed YAML** or **non-mapping top level** → ctree warns to stderr
|
|
424
|
+
and falls back to shipped defaults. The command continues.
|
|
425
|
+
- **Wrong type for a known key** (e.g. a string where a list is expected)
|
|
426
|
+
→ ctree exits with an error pointing at the offending key. Fix the file
|
|
427
|
+
and re-run.
|
|
428
|
+
- **`--config <path>` errors** — unlike the optional per-repo config,
|
|
429
|
+
errors in a custom config file are always fatal: a missing file, invalid
|
|
430
|
+
YAML, or wrong key type causes ctree to exit immediately with no partial
|
|
431
|
+
state left behind.
|
|
432
|
+
|
|
433
|
+
## Traefik / reverse-proxy domain routing
|
|
434
|
+
|
|
435
|
+
ctree sets two `.env` variables to give each worktree a unique routable domain:
|
|
436
|
+
|
|
437
|
+
| Variable | Set by | Value |
|
|
438
|
+
|---|---|---|
|
|
439
|
+
| `HOST_NAME` | ctree (always) | worktree name, e.g. `my-feature` |
|
|
440
|
+
| `HOST_NAME_SUFFIX` | ctree (when `host_name_suffix` is configured) | TLD, e.g. `docker` |
|
|
441
|
+
|
|
442
|
+
Together they form `${HOST_NAME}.${HOST_NAME_SUFFIX}` — e.g. `my-feature.docker` — which
|
|
443
|
+
your compose files can use in Traefik `Host()` rules and domain env vars.
|
|
444
|
+
|
|
445
|
+
### Per-repo setup
|
|
446
|
+
|
|
447
|
+
In your repo's `.ctree.yml`:
|
|
448
|
+
|
|
449
|
+
```yaml
|
|
450
|
+
host_name_suffix: docker # written to HOST_NAME_SUFFIX in every worktree .env
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Create a local compose override file (e.g. `docker-compose.local.ctree.yml`) that
|
|
454
|
+
references these variables:
|
|
455
|
+
|
|
456
|
+
```yaml
|
|
457
|
+
services:
|
|
458
|
+
web:
|
|
459
|
+
labels:
|
|
460
|
+
- "traefik.http.routers.web.rule=Host(`myapp.${HOST_NAME}.${HOST_NAME_SUFFIX}`)"
|
|
461
|
+
environment:
|
|
462
|
+
APP_DOMAIN: myapp.${HOST_NAME}.${HOST_NAME_SUFFIX}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Wiring up the override
|
|
466
|
+
|
|
467
|
+
ctree automatically appends the configured override file to `COMPOSE_FILE` in the
|
|
468
|
+
worktree's `.env` when the file exists in the source repo. No manual step required.
|
|
469
|
+
|
|
470
|
+
The source repo's `.env` and domain are left untouched — the override is only active
|
|
471
|
+
in worktrees, never in the source.
|
|
472
|
+
|
|
473
|
+
### How it works
|
|
474
|
+
|
|
475
|
+
- **Source repo:** `HOST_NAME` and `HOST_NAME_SUFFIX` are unset; existing routing is unchanged.
|
|
476
|
+
- **Worktrees:** ctree writes `HOST_NAME=<name>` and `HOST_NAME_SUFFIX=<tld>`; the override
|
|
477
|
+
file's `Host()` rules resolve to unique per-worktree domains.
|
|
478
|
+
- All worktrees and the source share the same Traefik network without conflicts because
|
|
479
|
+
each `Host()` rule resolves to a distinct value.
|
|
480
|
+
|
|
481
|
+
## Development
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
bundle install
|
|
485
|
+
bundle exec rspec # default suite (no docker required)
|
|
486
|
+
bundle exec rspec --tag docker # opt-in real-docker integration tests
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## License
|
|
490
|
+
|
|
491
|
+
MIT — see [LICENSE](LICENSE).
|