Skip to content
Open
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
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Ever find yourself with 50 directories named `test`, `test2`, `new-test`, `actua

**try** is here for your beautifully chaotic mind.

# What it does
# What it does

![Fuzzy Search Demo](assets/try-fuzzy-search-demo.gif)

Expand Down Expand Up @@ -131,6 +131,7 @@ try ./path/to/repo [name] # Use another repo as the worktre
try worktree dir [name] # Same as above, explicit CLI form
try clone https://github.com/user/repo.git # Clone repo into date-prefixed directory
try https://github.com/user/repo.git # Shorthand for clone (same as above)
try repo 2025-08-17-my-app # Publish a try directory to a new private GitHub repo
try --help # See all options
```

Expand Down Expand Up @@ -165,12 +166,34 @@ Supported git URI formats:

The `.git` suffix is automatically removed from URLs when generating directory names.

### GitHub Repository Publishing

Publish a plain try directory to a fresh GitHub repository with the GitHub CLI:

```bash
# Publish a try as a private repo named my-app
try repo 2025-08-17-my-app

# Choose a custom repo name
try repo 2025-08-17-my-app better-name

# Create a public repo instead of the private default
try repo 2025-08-17-my-app --public
```

The command temporarily runs `git init`, commits the current files, runs `gh repo create --source=. --remote=origin --push`, then removes the local `.git` directory after a successful push. If `gh` or `git` fails, `.git` remains so you can inspect and retry.

In the TUI, select a try and press `Ctrl-U` to edit the repo name and choose private or public visibility before publishing.

For safety, `try repo` only publishes plain directories. It refuses directories that already contain `.git`.

### Keyboard Shortcuts

- `↑/↓` or `Ctrl-P/N/J/K` - Navigate
- `Enter` - Select or create
- `Backspace` - Delete character
- `Ctrl-D` - Delete directory (with confirmation)
- `Ctrl-U` - Create GitHub repo from selected try
- `ESC` - Cancel
- Just type to filter

Expand Down Expand Up @@ -199,9 +222,9 @@ nix run github:tobi/try init ~/my-tries
```nix
{
inputs.try.url = "github:tobi/try";

imports = [ inputs.try.homeManagerModules.default ];

programs.try = {
enable = true;
path = "~/experiments"; # optional, defaults to ~/src/tries
Expand Down
38 changes: 38 additions & 0 deletions spec/command_line.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,44 @@ try . <name> # Shorthand (requires name)
- Returns shell script to cd into worktree
- `try .` without a name is NOT supported (too easy to invoke accidentally)

### repo

Publish a plain try directory to a fresh GitHub repository using the GitHub CLI.

```
try repo [path-or-name] [repo-name] [--private|--public]
try exec repo [path-or-name] [repo-name] [--private|--public]
```

**Arguments:**
- `path-or-name` (optional): Source directory to publish. Existing paths are used directly; otherwise the value is resolved as a child of the tries directory. Defaults to the current directory.
- `repo-name` (optional): GitHub repository name. Defaults to the source basename with a leading `YYYY-MM-DD-` prefix removed.

**Flags:**
- `--private`: Create a private repository (default)
- `--public`: Create a public repository

**Behavior:**
- Refuses sources that already contain `.git`
- Changes into the source directory
- Runs `git init`, `git add .`, and `git commit -m 'Initial commit'`
- Runs `gh repo create <repo-name> --private --source=. --remote=origin --push` by default
- Uses `--public` instead of `--private` when requested
- Removes local `.git` only after the GitHub repo creation and push succeed
- Returns shell script to cd back into the source directory

**Examples:**
```
try repo 2025-11-30-my-app
# Creates a private GitHub repo named my-app

try repo 2025-11-30-my-app better-name
# Creates a private GitHub repo named better-name

try repo 2025-11-30-my-app --public
# Creates a public GitHub repo named my-app
```

### init

Output shell function definition for shell integration.
Expand Down
101 changes: 101 additions & 0 deletions spec/tests/test_38_repo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# GitHub repo publishing tests
# Verify try repo emits a script that publishes a plain try folder via gh.

section "repo"

REPO_DIR=$(mktemp -d)
mkdir -p "$REPO_DIR/2026-05-16-my-app"
echo "hello" > "$REPO_DIR/2026-05-16-my-app/README.md"

# Test: CLI repo command initializes git and creates a private GitHub repo by default
output=$(try_run --path="$REPO_DIR" repo 2026-05-16-my-app 2>&1)
if echo "$output" | grep -q "git init" && echo "$output" | grep -q "gh repo create 'my-app' --private --source=. --remote=origin --push"; then
pass
else
fail "repo should init git and create private GitHub repo" "git init and gh repo create 'my-app' --private" "$output" "command_line.md#repo"
fi

# Test: repo command stages and commits current files
if echo "$output" | grep -q "git add ." && echo "$output" | grep -q "git commit -m 'Initial commit'"; then
pass
else
fail "repo should add and commit files" "git add . and initial commit" "$output" "command_line.md#repo"
fi

# Test: cleanup runs after gh repo create so failures leave .git for debugging
gh_line=$(echo "$output" | grep -n "gh repo create" | cut -d: -f1 | head -1)
cleanup_line=$(echo "$output" | grep -n "rm -rf '.git'" | cut -d: -f1 | head -1)
if [ -n "$gh_line" ] && [ -n "$cleanup_line" ] && [ "$cleanup_line" -gt "$gh_line" ]; then
pass
else
fail "repo should clean up .git after gh succeeds" "rm -rf '.git' after gh repo create" "$output" "command_line.md#repo"
fi

# Test: --public uses public visibility
output=$(try_run --path="$REPO_DIR" repo 2026-05-16-my-app --public 2>&1)
if echo "$output" | grep -q "gh repo create 'my-app' --public --source=. --remote=origin --push"; then
pass
else
fail "repo --public should create public GitHub repo" "--public" "$output" "command_line.md#repo"
fi

# Test: custom repo name overrides stripped directory name
output=$(try_run --path="$REPO_DIR" repo 2026-05-16-my-app better-name 2>&1)
if echo "$output" | grep -q "gh repo create 'better-name' --private --source=. --remote=origin --push"; then
pass
else
fail "repo should accept custom repo name" "better-name" "$output" "command_line.md#repo"
fi

# Test: existing relative paths win over same-named TRY_PATH children
LOCAL_ROOT=$(mktemp -d)
mkdir -p "$LOCAL_ROOT/shared-name"
mkdir -p "$REPO_DIR/shared-name"
LOCAL_SOURCE=$(cd "$LOCAL_ROOT/shared-name" && pwd -P)
output=$(cd "$LOCAL_ROOT" && try_run --path="$REPO_DIR" repo ./shared-name 2>&1)
if echo "$output" | grep -q "cd '$LOCAL_SOURCE'"; then
pass
else
fail "repo should prefer existing relative source paths" "cd '$LOCAL_SOURCE'" "$output" "command_line.md#repo"
fi

# Test: repo refuses existing git repositories to avoid deleting history
mkdir -p "$REPO_DIR/2026-05-16-existing-git/.git"
output=$(try_run --path="$REPO_DIR" repo 2026-05-16-existing-git 2>&1)
if echo "$output" | grep -q "already contains .git"; then
pass
else
fail "repo should refuse existing git repository" "already contains .git" "$output" "command_line.md#repo"
fi

# Test: exec repo command emits the same publish script
output=$(try_run --path="$REPO_DIR" exec repo 2026-05-16-my-app 2>&1)
if echo "$output" | grep -q "gh repo create 'my-app' --private --source=. --remote=origin --push"; then
pass
else
fail "exec repo should emit publish script" "gh repo create" "$output" "command_line.md#repo"
fi

# Test: TUI action can publish selected try with default private visibility
output=$(try_run --path="$REPO_DIR" --and-keys='DOWN,CTRL-U,ENTER' exec 2>/dev/null)
if echo "$output" | grep -q "gh repo create 'my-app' --private --source=. --remote=origin --push"; then
pass
else
fail "Ctrl-U should publish selected try as private repo" "gh repo create 'my-app' --private" "$output" "tui_spec.md#keyboard"
fi

# Test: TUI action can toggle public visibility
output=$(try_run --path="$REPO_DIR" --and-keys='DOWN,CTRL-U,DOWN,ENTER' exec 2>/dev/null)
if echo "$output" | grep -q "gh repo create 'my-app' --public --source=. --remote=origin --push"; then
pass
else
fail "Repo dialog should allow public visibility" "--public" "$output" "tui_spec.md#keyboard"
fi

# Test: TUI repo dialog can be cancelled
output=$(try_run --path="$REPO_DIR" --and-keys='CTRL-U,ESC' exec 2>/dev/null)
if echo "$output" | grep -q "gh repo create"; then
fail "Repo dialog Esc should cancel" "no gh repo create" "$output" "tui_spec.md#keyboard"
else
pass
fi
Loading