# ghq Migration

Migrate Git repositories to ghq directory structure.

## Script Location

`./scripts/repo-to-ghq.sh` - Script to move repositories to ghq path.

## When to Use

- User wants to migrate a regular Git repository to ghq
- User mentions "convert to ghq", "repo migrate", "ghq migrate"

## How It Works

1. **Detects bare+worktree structure** and converts to regular `.git` directory (with index verification)
2. Moves entire repository to ghq path (e.g., `~/ghq/host/group/repo/`)
3. Optionally creates symlink at original location (skip with `--no-symlink`)
4. Optionally remaps origin URL (replace with `--remap-origin`)
5. Cleans up empty directories left by old bare repo

## Instructions

### Step 1: Identify Target Repository

Check if the current directory or specified path is a regular Git repository (not a worktree):

```bash
# Check if it's a regular .git directory (not a file)
if [[ -d .git ]]; then
  echo "Regular Git repository - can migrate"
elif [[ -f .git ]]; then
  echo "Already a worktree - skip"
fi
```

### Step 2: Run Migration Script

```bash
# From the repository root (without symbolic links)
scripts/repo-to-ghq.sh --no-symlink

# When origin URL replacement is needed
scripts/repo-to-ghq.sh --no-symlink --remap-origin "git@github.com:org/repo.git"

# For repositories without origin (specify target path directly)
scripts/repo-to-ghq.sh --no-symlink ~/ghq/local/archive/<name>
```

### Step 3: Verify Migration

```bash
# Verify git commands work at new location
cd ~/ghq/host/group/repo
git status
git log --oneline -1
```

### Step 4: Update SourceGit

**CRITICAL**: SourceGit overwrites preference.json on exit. Always verify the app is closed before editing.

```bash
pgrep -x SourceGit
```

If running, ask user to quit first. Only proceed after confirming it is closed.

Update SourceGit preference.json:

1. **Remove old path entry** from `RepositoryNodes` (search for original path)
2. **Add new ghq path** to appropriate group's `SubNodes`
3. **Update Workspaces** if the old path was referenced there

**Important**: Do NOT leave duplicate entries. Replace old path with new path.

## Script Options

```bash
scripts/repo-to-ghq.sh [--no-symlink] [--remap-origin URL] [target_path]
```

| Option | Description |
|--------|-------------|
| `--no-symlink` | Do not create symbolic link at original location |
| `--remap-origin URL` | Replace origin URL with the specified URL after moving |
| `target_path` | Specify ghq path directly (for repositories without origin) |

## Batch Migration

Batch migration workflow:

### Discovery (Scout)

Verify target list based on reports generated by scout agent.
Use `/git-repo patrol --discover`.

### Duplicate Resolution

Handle repositories that already exist in ghq:

1. Compare HEAD commits: `git -C <external> rev-parse HEAD` vs `git -C <ghq> rev-parse HEAD`
2. If same: Check for branches/stash only in external, then delete
3. If different: Compare which is newer, confirm with user

### No-Origin Repositories

Specify target path directly for repositories without origin:

```bash
cd <repo>
scripts/repo-to-ghq.sh --no-symlink ~/ghq/local/archive/<name>
```

### No-Symlink Policy

Skip symbolic link creation with `--no-symlink` option. Delete original directory if empty after migration.

## Absolute Migration Principles

### Migration Philosophy: Use `mv` only

Migration should be completed with **2 mv commands**. No rm, cp, git reset, or mkdir needed.

```bash
# Step 1: Move existing worktree to ghq path
mv ~/works/repo ~/ghq/github.com/org/repo

# Step 2: Move bare repo to .git directory
mv ~/ghq/github.com/org/repo.git ~/ghq/github.com/org/repo/.git

# Step 3: Clean up config + verify
git -C ~/ghq/github.com/org/repo config --unset core.bare
git -C ~/ghq/github.com/org/repo config --unset core.worktree
git -C ~/ghq/github.com/org/repo status           # Verification only. AskUserQuestion on failure
```

Result: Nothing remains in works/, a complete repository exists in ghq/.

### Prohibited Actions

| Prohibited | Reason |
|------------|--------|
| `git reset --hard` | Creates new checkout = ignores existing work, orphans works/ |
| `cp` (instead of mv) | Original remains causing duplicates, requires rm later |
| `rm -rf` (for cleanup) | Creating garbage then deleting it is the wrong approach |
| `mkdir -p` (in ghq) | Creating empty directory = implies not moving the worktree |

### Manual Conversion Prohibited

**Do not manually convert bare repo + worktree structures.** Always use `scripts/repo-to-ghq.sh`.

When in doubt, **always confirm with AskUserQuestion** before proceeding.

## Index Preservation

The bare repo's index is located at `bare.git/index`. Running `mv bare.git .git/` automatically preserves it as `.git/index`.

**Do NOT run `git read-tree HEAD`** — it destroys all staged changes. If index issues occur, always use AskUserQuestion.

Verification method:
```bash
git -C <path> status                # Check overall status
git -C <path> diff --cached --stat  # Verify staged changes are preserved
```

## Migration Exclusions

- Bare repositories outside of ghq (e.g., `~/.logseq/git/`) → exclude from migration

## Script Details

The `repo-to-ghq.sh` script:

1. **ghq path calculation**: Parses origin URL to determine target path
   - HTTPS: `https://host/group/repo.git` → `~/ghq/host/group/repo`
   - SSH: `git@host:group/repo.git` → `~/ghq/host/group/repo`
   - Supports nested groups (e.g., `org/devops/repo`)

2. **bare+worktree conversion**: If `.git` is a file (worktree), converts to regular structure
   - Reads bare repo path from `.git` file
   - Moves bare repo to `.git` directory
   - Unsets `core.bare` and `core.worktree` configs
   - Cleans up empty parent directories

3. **Migration**: Moves entire repository to ghq path (symlink controlled by `--no-symlink`)
4. **Remap**: Replace origin URL after move with `--remap-origin`
5. **Index verification**: Automatic `git status` verification after move. AskUserQuestion on failure (`git read-tree HEAD` prohibited)

## Output

```
Repository moved to '/Users/es6kr/ghq/github.com/org/repo'.
```
