Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install bats-core and zsh (Ubuntu)
- name: Install bats-core, zsh and mandoc (Ubuntu)
if: runner.os == 'Linux'
run: |
git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core
sudo /tmp/bats-core/install.sh /usr/local
sudo apt-get install -y zsh
sudo apt-get install -y zsh mandoc

- name: Install bats-core and bash (macOS)
if: runner.os == 'macOS'
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html):
- Tests: `wrktr_init` dry-run and stale-temp-dir cases (run in a pty via `tests/helpers/run_in_pty.py`), and zsh source/unload/reload cases

### Changed
- CI: the Linux job installs `mandoc` so the man-page lint test runs there (macOS already has it)
- CI: `actions/checkout` bumped to v7.0.1 (pinned by SHA), which runs on Node 24; the previous pin ran on the deprecated Node 20
- `install.sh` no longer edits your shell profile without consent: it asks first when run in a terminal, and leaves the profile untouched (printing the line to add) when it is not. New flags: `--yes` adds the line without asking, `--no-profile` never touches the profile. `update.sh` passes flags through.
- `uninstall.sh` asks before removing the source line from each profile, and lists the profiles without changing them when not run in a terminal. `--yes` removes the line without asking.
Expand All @@ -31,6 +32,7 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html):
- Release workflow: fails if the tag does not match `WRKTR_VERSION` and a CHANGELOG entry

### Fixed
- Docs: in-script `wrktr_help`, the man page and `docs/wrktr.md` now describe current behavior for `wrktr_use` (parses the config, never sources it; a failed load keeps the previous session), `wrktr_push`, `wrktr_adopt`, `wrktr_reload`, `wrktr_git` in dry-run, and the offline fallback of `wrktr_add`/`wrktr_checkout`; the reference no longer says old-format configs are sourced. Man page: replaced the placeholder clone URLs, fixed the `./install.sh` line that was dropped from the rendered page, and set a date that man tools can parse
- `wrktr_use`: when the session being loaded fails validation, the previously loaded session is restored instead of being lost
- `wrktr_init`: the bare repository's `HEAD` now points at the chosen main branch instead of an unborn `master`, so plain git commands in the bare repo work; an invalid branch name is now rejected before anything is created
- `uninstall.sh`: rewrites profiles in place, so a symlinked profile stays a symlink and keeps its permissions, and no longer aborts when the source line was the only line
Expand Down
23 changes: 16 additions & 7 deletions docs/wrktr.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.\" wrktr.1 — manual page for the wrktr shell worktree manager
.\" Install: cp wrktr.1 ~/.local/share/man/man1/ && man -W ~/.local/share/man/man1
.TH WRKTR 1 "June 2026" "wrktr 1.0.2" "User Commands"
.TH WRKTR 1 "June 23, 2026" "wrktr 1.0.2" "User Commands"
.
.SH NAME
wrktr \- branch-as-directory git worktree session manager
Expand Down Expand Up @@ -80,9 +80,9 @@ Required only by
.
.SH INSTALLATION
.nf
git clone https://github.com/your-username/wrktr.git
git clone https://github.com/gentbot/wrktr.git
cd wrktr
./install.sh
\&./install.sh
.fi
.PP
.B install.sh
Expand Down Expand Up @@ -132,8 +132,11 @@ Convert an existing normal git clone to the wrktr structure.
wrktr_adopt [path]
.fi
.PP
Creates a bare clone from an existing repo.
Creates a bare clone from an existing repo and restores every remote of the
original clone.
The original clone is not modified.
Only committed state is carried over; uncommitted changes and stash entries
are listed and confirmed before continuing.
.
.SS wrktr_init
Initialize a bare repository from a new local project with no remote.
Expand Down Expand Up @@ -185,7 +188,7 @@ wrktr_use <name>
Parses
.IR ~/.config/wrktr/<name>.env ,
exports session variables, and validates.
On failure, all variables are unset.
On failure, the previously loaded session, if any, stays active.
Sessions are shell-scoped.
.
.SS wrktr_list
Expand Down Expand Up @@ -281,9 +284,12 @@ Refuses if the working tree has uncommitted changes.
.SS wrktr_push
Push the current branch to the configured remote.
Refuses to push the main branch.
Pushes with
.BR \-u ,
so the branch tracks the remote.
Prompts before retrying with
.B \-\-force\-with\-lease
if the push is rejected.
if the push is rejected; other failures are reported without a force offer.
.
.SS wrktr_remove
Remove a worktree and optionally delete the branch ref.
Expand All @@ -309,6 +315,7 @@ Automatically supplies
Use from outside a worktree; from inside, plain
.BR git (1)
works without it.
In dry-run mode, read-only commands still run and only mutating ones are printed.
.
.SS wrktr
Raw passthrough to
Expand Down Expand Up @@ -360,6 +367,8 @@ variables from the current shell.
.B wrktr_reload
Unload and re-source from the original path. Useful after editing
.IR worktree-functions.sh .
The loaded session, dry-run state and settings are kept, and the reload is
refused if the file has a syntax error.
.TP
.B wrktr_prompt_info
Output a context string for embedding in
Expand Down Expand Up @@ -510,7 +519,7 @@ in the repository root.
wrktr contributors.
.PP
Source and issue tracker:
.I https://github.com/your-username/wrktr
.I https://github.com/gentbot/wrktr
.
.SH LICENSE
MIT License. See
Expand Down
8 changes: 4 additions & 4 deletions docs/wrktr.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ Loads a project config into the current shell.
wrktr_use omi
```

Sources `~/.config/wrktr/omi.env`. If validation fails, all variables are unset so the shell is not left in a partial state.
Parses `~/.config/wrktr/omi.env` (only the five session keys are read; the file is never executed) and validates the result. If validation fails, the previously loaded session, if any, stays active.

---

Expand Down Expand Up @@ -532,7 +532,7 @@ PS1='$(wrktr_prompt_info) \$ '
Creates a new branch and worktree directory, then `cd`s into it.

```bash
wrktr_add feature/login # branch from origin/main (fetches first)
wrktr_add feature/login # branch from origin/main (fetches first; offline it uses the refs fetched earlier)
wrktr_add fix/crash origin/v2 # branch from a specific ref
wrktr_add experiment/auth main # branch from local main
```
Expand All @@ -552,7 +552,7 @@ Creates a local worktree for a branch that already exists on the remote.
wrktr_checkout feature/login
```

Fetches first, verifies the remote branch exists (lists available ones if not), creates the local worktree, sets up upstream tracking, and `cd`s in. Requires a remote to be configured.
Fetches first (if the fetch fails, for example offline, it continues with the refs fetched earlier), verifies the remote branch exists (lists available ones if not), creates the local worktree, sets up upstream tracking, and `cd`s in. Requires a remote to be configured.

---

Expand Down Expand Up @@ -792,7 +792,7 @@ This does not affect the project files or bare repository.

### Migrating old configs

Configs created before this format change used shell script syntax (`export KEY=value`). These are detected automatically on load and still work — `wrktr_use` sources them as before and prints a migration notice. To migrate, run `wrktr_config_edit` and remove the `export ` prefix from each line.
Configs created before this format change used shell script syntax (`export KEY=value`). These are detected automatically on load and still work — `wrktr_use` reads the `KEY=value` pairs (it strips the `export ` prefix and never executes the file) and prints a migration notice. To migrate, run `wrktr_config_edit` and remove the `export ` prefix from each line.

---

Expand Down
61 changes: 59 additions & 2 deletions tests/commands.bats
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,14 @@ EOS
[ -z "$missing" ] || { echo "undocumented:$missing"; return 1; }
}

@test "docs: README has no placeholder clone URL" {
! grep -q 'your-username' "$BATS_TEST_DIRNAME/../README.md"
@test "docs: no placeholder clone URL in README, reference or man page" {
! grep -rq 'your-username' "$BATS_TEST_DIRNAME/../README.md" "$BATS_TEST_DIRNAME/../docs"
}

@test "docs: man page has no lint errors or warnings" {
command -v mandoc >/dev/null 2>&1 || skip "mandoc not available"
run bash -c "mandoc -Tlint \"$BATS_TEST_DIRNAME/../docs/wrktr.1\" 2>&1 | grep -v STYLE"
[ -z "$output" ]
}

# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -758,3 +764,54 @@ _make_worktree() {
[[ "$output" =~ "Worktree remove failed" ]]
[ -f "$TRUNK/feature%2Fr5/untracked" ]
}

# ---------------------------------------------------------------------------
# Help, man page and reference stay in step with behavior
# ---------------------------------------------------------------------------

@test "help: wrktr_use describes parsing and session restore, not sourcing" {
run wrktr_help use
[ "$status" -eq 0 ]
[[ ! "$output" =~ "Sources" ]]
[[ "$output" =~ "previously loaded session" ]]
}

@test "help: wrktr_push mentions upstream tracking and force only after a rejection" {
run wrktr_help push
[[ "$output" =~ "-u" ]]
[[ "$output" =~ "rejected" ]]
}

@test "help: wrktr_adopt mentions every remote and uncommitted changes" {
run wrktr_help adopt
[[ "$output" =~ "remote" ]]
[[ "$output" =~ "uncommitted" ]]
}

@test "help: wrktr_reload says it keeps the session" {
run wrktr_help reload
[[ "$output" =~ "session" ]]
[[ "$output" =~ "syntax" ]]
}

@test "help: wrktr_git says read-only commands run in dry-run mode" {
run wrktr_help git
[[ "$output" =~ "dry-run" ]]
}

@test "help: wrktr_add and wrktr_checkout mention the offline fallback" {
run wrktr_help add
[[ "$output" =~ "fetch fails" ]]
run wrktr_help checkout
[[ "$output" =~ "fetch fails" ]]
}

@test "docs: reference no longer says wrktr_use sources configs" {
! grep -q 'sources them as before' "$BATS_TEST_DIRNAME/../docs/wrktr.md"
! grep -q '^Sources `~/.config/wrktr' "$BATS_TEST_DIRNAME/../docs/wrktr.md"
! grep -q 'all variables are unset' "$BATS_TEST_DIRNAME/../docs/wrktr.md"
}

@test "docs: man page does not say a failed wrktr_use unsets all variables" {
! grep -q 'all variables are unset' "$BATS_TEST_DIRNAME/../docs/wrktr.1"
}
31 changes: 24 additions & 7 deletions worktree-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,9 @@ wrktr_adopt [path]

Convert an existing normal git clone into a wrktr bare repository structure.
The original clone is not modified — remove it manually when confirmed.
Every remote of the original clone is restored, not only origin. Only
committed state is carried over: if the clone has uncommitted changes or
stash entries, they are listed and you are asked before continuing.

Prompts:
Path to existing git clone Must have a .git subdirectory
Expand Down Expand Up @@ -635,9 +638,10 @@ EOF
cat <<'EOF'
wrktr_use <session>

Load a project session config into the current shell. Sources
~/.config/wrktr/<session>.env and validates the result. If validation
fails, all variables are unset so the shell is not left in a partial state.
Load a project session config into the current shell. Parses
~/.config/wrktr/<session>.env (only the five session keys are read; the
file is never executed) and validates the result. If validation fails, the
previously loaded session, if any, is left active.

Examples:
wrktr_use myapp
Expand Down Expand Up @@ -754,6 +758,8 @@ wrktr_add <branch> [base-ref]
when a remote is configured, or <main-branch> without one.

Fetches from the remote automatically before creating (when remote is set).
If the fetch fails (for example offline), it continues with the refs fetched
previously and fails only if the base ref is not among them.

Examples:
wrktr_add feature/login
Expand All @@ -768,7 +774,9 @@ wrktr_checkout <branch>

Create a local worktree for a branch that already exists on the remote.
Fetches first, verifies the remote branch exists, creates the worktree,
sets up upstream tracking, and cds in. Requires a remote to be configured.
sets up upstream tracking, and cds in. If the fetch fails (for example
offline), it continues with the refs fetched previously. Requires a remote
to be configured.

Examples:
wrktr_checkout feature/login
Expand Down Expand Up @@ -821,9 +829,10 @@ wrktr_push
Push the current branch to the configured remote.
Must be run from inside a worktree belonging to the loaded session.

Refuses to push the main branch. Attempts a regular push first; if rejected
(expected after wrktr_rebase), prompts before retrying with --force-with-lease.
Requires a remote to be configured.
Refuses to push the main branch. Pushes with -u so the branch tracks the
remote. If the push is rejected (expected after wrktr_rebase), prompts before
retrying with --force-with-lease; other failures (authentication, network)
are reported without a force-push offer. Requires a remote to be configured.

Examples:
wrktr_push
Expand Down Expand Up @@ -885,6 +894,10 @@ wrktr_git <git-args>
automatically. Use from outside a worktree. From inside a worktree,
ordinary 'git' commands work without it.

In dry-run mode, read-only commands (log, status, rev-parse, branch
listing, ...) still run; anything that could change the repository is only
printed.

Examples:
wrktr_git fetch origin
wrktr_git branch -d feature/login
Expand Down Expand Up @@ -962,6 +975,10 @@ wrktr_reload
path it was originally loaded from (WRKTR_SOURCE_PATH). Use after editing
the file to pick up changes without starting a new shell.

The loaded session, dry-run state, WRKTR_CONFIG_DIR and WRKTR_REPO_DIR_NAME
are kept. If the file has a syntax error the reload is refused and the
version already loaded stays in place.

Examples:
wrktr_reload
EOF
Expand Down
Loading