Skip to content

invopop/tsk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tsk

Multi-repo task workspaces backed by git worktrees.

If your work routinely touches a handful of repos at once — services and the libraries they share — tsk automates the bootstrap: one task directory, one worktree per repo, all on a fresh branch off each repo's default upstream.

Install

go install github.com/invopop/tsk

A 60-second tour

# 1. Create a task in the current directory.
tsk create app-489 multi-payment-methods
# → /path/to/cwd/app-489-multi-payment-methods

cd app-489-multi-payment-methods

# 2. Add as many repos as the task needs.
#    Each becomes a worktree on a new branch named after the slug.
tsk add ../../gobl.html ../../pdf.go ../../at-pt

# 3. Look across worktrees at any time.
tsk status
# gobl.html  [multi-payment-methods]  M 3   ↑2
# pdf.go     [multi-payment-methods]  clean
# at-pt      [multi-payment-methods]  clean

# 4. Drop a repo if it turns out you don't need it.
tsk rm pdf.go

# 5. When the work is shipped (and pushed!) close the task.
cd ..
tsk close app-489-multi-payment-methods

Convention over configuration

There is no global config and no central tasks directory. A task is just a directory containing a .tsk.yaml marker:

ref: app-489
slug: multi-payment-methods

Run tsk create wherever you want the task to live. The task directory's name is <ref>-<slug> (or just <slug> if you skip the ref). The branch created on each source repo by tsk add defaults to <slug> — the ref is not part of the branch name.

The base branch defaults to the first remote's default branch — e.g. on a typical clone, origin/main, but tsk follows whatever the repo is actually configured with (upstream/master works just the same). Override it with --base <remote>/<branch> on tsk add (or tsk create when using -a):

# Base the new worktrees off origin/develop instead of the default.
tsk add --base origin/develop ../../gobl.html

The full `<remote>/<branch>` form is required so it's never ambiguous whether
you mean a local branch or a remote-tracking one.

When `--base` helps:

- **Stacking on an unreleased feature branch.** Your task depends on a
  colleague's change that is approved but not yet merged to `main`. Branching
  off their feature branch keeps your diff focused on your own work instead
  of dragging in theirs, and avoids the "merge their branch into mine, then
  rebase later" dance.
- **Long-lived integration branches.** When several tasks land into a shared
  `develop` (or similar) before promotion, base new worktrees there so each
  task starts from the state the integration branch is actually in.

## Adding the same repo twice

By default each worktree's directory is named after the repo (`gov-fr`), so
adding the same repo again would collide. Use `--as <name>` to give the second
worktree its own directory name, and `-b` to put it on its own branch (git can't
check out one branch in two worktrees):

```sh
tsk add ../../gov-fr                               # → gov-fr   [<slug>]
tsk add --as gov-fr-hotfix -b hotfix ../../gov-fr  # → gov-fr-hotfix [hotfix]

--as names a single directory, so it can't be combined with multiple repo paths in one tsk add.

tsk close is paranoid by default

Closing a task removes each worktree and deletes the task directory. Before doing that, close refuses to touch a worktree if either:

  • the working tree is dirty, or
  • the branch was never pushed, or has unpushed commits ahead of its upstream.

This is the whole point: it is easy to forget that a worktree had local-only work. --force is the explicit escape hatch for the cases where you really do want to discard.

Commands

tsk create [--base <remote>/<branch>] [<ref>] <slug> [-a <repo>...]
                                   Create a task directory in cwd
tsk add [--base <remote>/<branch>] [-b <branch>] [--as <name>] <repo-path> [...]
                                   Add worktrees to the current task
tsk status                         git status summary across all worktrees
tsk rm [-f] <repo-path>            Remove one worktree from the current task
tsk close [-f] <task-path>         Decommission a task: clean worktrees + delete dir

add, status and rm walk up from cwd looking for .tsk.yaml, so they work from any subdirectory inside a task. close takes the path explicitly so you can run it from outside.

License

Apache-2.0 — see LICENSE.

About

Multi-repo task workspaces backed by git worktrees.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages