Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 3ae78d9

Browse files
Fix rough edges in scaffolded projects (#4)
* fix: remove _workspace hack, keep bare repo properly bare The project root no longer pretends to be a working directory. The bare repo stays bare (core.bare=true), HEAD points to main, and git status correctly reports "this operation must be run in a work tree" at the root. Removes the orphan _workspace branch, core.bare=false override, and the root .gitignore wildcard that were only needed to fake a clean status. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: wt-add supports existing local and remote branches Previously always used -b, failing if the branch existed. Now checks for existing local branches and remote tracking branches before falling back to creating a new branch from base. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: wt-rm deletes local branch and guards against removing main Now deletes the local branch after removing the worktree. If the branch has unmerged changes, warns the user and shows the force-delete command instead of silently dropping work. Refuses to remove the main worktree. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: remote-add checks for existing remote and doesn't auto-push Now errors if the remote name already exists (showing current URL and how to replace it). No longer pushes main automatically; instead prints the push command so the user stays in control. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update AGENTS.md for bare repo root behavior Remove references to _workspace branch and root .gitignore. Document that the project root is a container (not a working directory) and that git commands should be run from inside worktrees. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e0a23f4 commit 3ae78d9

5 files changed

Lines changed: 48 additions & 32 deletions

File tree

template/.mise/tasks/remote-add

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
#!/bin/bash
2-
#MISE description="Add an existing GitHub repo as a remote and push main"
2+
#MISE description="Add an existing GitHub repo as a remote and fetch branches"
33

44
set -euo pipefail
55

6-
REPO="${1:?Usage: mise run remote-add <owner/repo>}"
6+
REPO="${1:?Usage: mise run remote-add <owner/repo> [remote-name]}"
77
NAME="${2:-origin}"
88
URL="git@github.com:${REPO}.git"
99

10+
if git remote get-url "$NAME" &>/dev/null; then
11+
echo "Error: remote '$NAME' already exists." >&2
12+
echo " Current URL: $(git remote get-url "$NAME")" >&2
13+
echo " To replace it: git remote set-url $NAME $URL" >&2
14+
exit 1
15+
fi
16+
1017
git remote add "$NAME" "$URL"
1118
git config "remote.$NAME.fetch" "+refs/heads/*:refs/remotes/$NAME/*"
1219
git fetch "$NAME"
13-
git push -u "$NAME" main
1420

1521
echo ""
16-
echo "Remote '$NAME' added and main branch pushed."
22+
echo "Remote '$NAME' added and branches fetched."
1723
echo " $URL"
24+
echo ""
25+
echo "To push main: git push -u $NAME main"

template/.mise/tasks/wt-add

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
#!/bin/bash
2-
#MISE description="Create a new git worktree with a fresh branch"
2+
#MISE description="Create a new git worktree for a branch"
33

44
set -euo pipefail
55

66
BRANCH="${1:?Usage: mise run wt-add <branch-name> [base-branch]}"
77
BASE="${2:-main}"
88

9-
git worktree add -b "$BRANCH" "$BRANCH" "$BASE"
10-
echo "Created worktree '$BRANCH' from '$BASE'"
9+
if git show-ref --verify --quiet "refs/heads/$BRANCH"; then
10+
# Local branch exists, check it out
11+
git worktree add "$BRANCH" "$BRANCH"
12+
echo "Checked out existing branch '$BRANCH'"
13+
elif git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then
14+
# Remote branch exists, track it
15+
git worktree add "$BRANCH" "$BRANCH"
16+
echo "Checked out '$BRANCH' (tracking origin/$BRANCH)"
17+
else
18+
# New branch, create from base
19+
git worktree add -b "$BRANCH" "$BRANCH" "$BASE"
20+
echo "Created new branch '$BRANCH' from '$BASE'"
21+
fi
1122
echo " cd $BRANCH/"

template/.mise/tasks/wt-rm

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
#!/bin/bash
2-
#MISE description="Remove a git worktree and its directory"
2+
#MISE description="Remove a git worktree and its local branch"
33

44
set -euo pipefail
55

66
BRANCH="${1:?Usage: mise run wt-rm <branch-name>}"
77

8+
if [ "$BRANCH" = "main" ]; then
9+
echo "Error: refusing to remove the main worktree." >&2
10+
exit 1
11+
fi
12+
813
git worktree remove "$BRANCH"
9-
echo "Removed worktree '$BRANCH'"
14+
15+
if ! git branch -d "$BRANCH" 2>/dev/null; then
16+
echo "Worktree removed but branch '$BRANCH' has unmerged changes."
17+
echo " To delete it anyway: git branch -D $BRANCH"
18+
else
19+
echo "Removed worktree and branch '$BRANCH'"
20+
fi

template/AGENTS.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ This project uses a **bare repo + worktree** structure. Read this before making
3030
basing new branches, not for edits.
3131
2. **Each worktree is a full checkout** of a branch. You `cd` into a worktree directory to work on
3232
that branch. There is no `git checkout` or `git switch` needed.
33-
3. **Git commands work from the project root**. The `.git` pointer file connects to `.bare/`.
34-
The root is on a `_workspace` branch (empty tree) so `git status` returns clean.
33+
3. **The project root is a container, not a working directory**. The `.git` pointer file connects
34+
to `.bare/`. Running `git status` at the root will say "must be run in a work tree", which
35+
is correct. Always `cd` into a worktree to do git operations on that branch.
3536
4. **Files at the project root** (outside worktrees) are not tracked by git. The `.mise/` tasks,
3637
`AGENTS.md`, and config directories live here intentionally.
3738

@@ -67,18 +68,17 @@ If the project was created without a remote URL, use one of these to connect it:
6768
mise run repo-public owner/repo-name
6869
mise run repo-private owner/repo-name
6970

70-
# Or add an existing remote
71+
# Or add an existing remote and fetch branches
7172
mise run remote-add owner/repo
7273
```
7374

7475
## When running commands
7576

76-
- Always `cd` into the appropriate worktree directory before running build, test, or lint commands.
77-
- To compare branches, use `git diff main...<branch>` from the project root.
78-
- To fetch updates: `git fetch --all` from anywhere in the project.
77+
- Always `cd` into the appropriate worktree directory before running build, test, lint, or git commands.
78+
- To compare branches from a worktree: `git diff main...<branch>`.
79+
- To fetch updates: `git fetch --all` from any worktree.
7980

8081
## Local excludes
8182

82-
The project root has a `.gitignore` containing `*` so all root-level files stay untracked.
83-
This only affects the `_workspace` checkout; linked worktrees have their own `.gitignore`.
84-
Use `.bare/info/exclude` only for patterns that should apply across all worktrees.
83+
Each worktree has its own `.gitignore`. Use `.bare/info/exclude` for patterns that should
84+
apply across all worktrees.

template/setup.sh.jinja

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,6 @@ else
2626
git worktree add main main
2727
fi
2828

29-
# Make git status work at the project root so shell prompts (starship, etc.)
30-
# don't show spurious indicators. An empty orphan branch means "nothing tracked
31-
# here" and a wildcard .gitignore hides all untracked project-root files.
32-
git config core.bare false
33-
EMPTY_TREE=$(git hash-object -t tree /dev/null)
34-
EMPTY_COMMIT=$(echo "workspace root" | git commit-tree "$EMPTY_TREE")
35-
git update-ref refs/heads/_workspace "$EMPTY_COMMIT"
36-
git symbolic-ref HEAD refs/heads/_workspace
37-
38-
# The project root is on the _workspace branch (empty tree). A wildcard .gitignore
39-
# here keeps git status clean without polluting .bare/info/exclude, which is
40-
# shared across all linked worktrees.
41-
echo "*" > .gitignore
42-
4329
# Create directories for scratchpad and agent config
4430
mkdir -p _ .claude
4531

0 commit comments

Comments
 (0)