gitgrip 0.18.0

Multi-repo workflow tool - manage multiple git repositories as one
Documentation
# Gripspace Layout Plan

## Status

- Implemented in codebase now:
  - Canonical workspace file path: `.gitgrip/spaces/main/gripspace.yml`
  - Legacy fallback reads:
    - `.gitgrip/manifests/manifest.yaml`
    - `.gitgrip/manifests/manifest.yml`
  - Command path resolution now prefers canonical layout and falls back to legacy.
- Not yet implemented:
  - Loading and merging `.gitgrip/spaces/local/gripspace.yml`
  - `include:` expansion across local gripspace files (see below)
- Implemented (PR #270):
  - `gripspaces:` directive for composable manifest inheritance via external git repos
  - Gripspace repos cloned into `.gitgrip/spaces/<name>/` alongside `main/` and `local/`
  - Reserved name handling (`main`, `local` auto-suffixed to `main-1`, etc.)
  - DAG-aware resolution with cycle detection
  - `composefile:` for concatenating parts from gripspaces and local manifest

## Goals

1. Make `gripspace.yml` the default, explicit workspace format.
2. Separate shareable workspace config (`main`) from user/local overrides (`local`).
3. Support reusable composition with `include:` while keeping deterministic behavior.
4. Preserve backward compatibility for existing workspaces during migration.

## Canonical Layout

```text
.gitgrip/
  spaces/
    main/
      gripspace.yml        # tracked/shared workspace definition
    local/
      gripspace.yml        # optional local overrides (not shared by default)
```

Legacy compatibility during migration:

```text
.gitgrip/manifests/manifest.yaml
.gitgrip/manifests/manifest.yml
```

## Merge Model (Main + Local)

Load order (lowest to highest precedence):

1. `spaces/main/gripspace.yml`
2. `spaces/local/gripspace.yml` (if present)

Proposed merge rules:

- Scalars (`version`, `settings.*`): local overrides main.
- Maps (`repos`, `workspace.env`, `workspace.scripts`, `workspace.ci.pipelines`): deep-merge by key, local key wins on conflict.
- Arrays:
  - `groups`: union with stable order (main first, then new local entries).
  - `copyfile` / `linkfile`: concatenate with de-dup by `(src,dest)`, local wins on duplicate.

## `gripspaces:` — Remote Includes (Implemented)

Gripspaces are external git repos that contribute repos, scripts, env, hooks, and file configs
to a workspace. They are declared at the top level:

```yaml
gripspaces:
  - url: "https://github.com/org/base-gripspace.git"
    rev: "v1.0"  # optional pin
```

Resolution happens at `gr sync` / `gr init` time. Gripspace repos are cloned into
`.gitgrip/spaces/<name>/` and their manifests are merged depth-first with local-wins semantics.

## `include:` — Local File Includes (Not Yet Implemented)

Proposed schema extension for splitting a large manifest into local files without a separate repo:

```yaml
include:
  - ../shared/base.gripspace.yml
  - ./team/mobile.gripspace.yml
```

Rules:

- Includes are resolved relative to the file that declares them.
- Includes are processed depth-first, then merged in declaration order.
- Current file overrides included content.
- Cycles are rejected with a clear error chain.
- Missing include file is a hard error by default.

Note: This is distinct from `gripspaces:` which clones external repos. `include:` is for
local file composition only and does not require network access.

## Validation and Guardrails

- Enforce workspace-bound paths after normalization.
- Reject path traversal (`..`) and absolute include paths by default.
- Error messages should include:
  - failing file path
  - include parent path
  - merge key conflict context where possible

## Migration Plan

1. **Read compatibility** (done): prefer canonical, fallback to legacy.
2. **Write default** (done): new workspaces write `spaces/main/gripspace.yml`.
3. **Optional migration command** (planned):
   - `gr manifest migrate-layout`
   - Moves/copies legacy manifest to canonical layout.
   - Optionally leaves a compatibility mirror.
4. **Deprecation window**:
   - keep legacy reads for N minor versions
   - emit warnings when legacy path is the active source

## Testing Plan

- Unit tests:
  - path resolution preference/fallback
  - include cycle detection
  - merge conflict behavior
- Integration tests:
  - commands run from canonical layout only
  - commands run with legacy-only layout
  - main+local overlay behavior
  - include chains and error paths
- Regression tests:
  - griptree add/remove/return with manifest worktree at `spaces/main`
  - sync/rebase/status behavior unchanged for non-manifest repos