# Milestone v1.0: GitSL MVP

**Status:** ✅ SHIPPED 2026-01-18
**Phases:** 1-9
**Total Plans:** 12

## Overview

GitSL transforms git commands into Sapling equivalents, enabling git workflow tools to work transparently with Sapling repos. The roadmap builds from core execution infrastructure (parsing, subprocess handling) through command translation layers (direct mappings, then flag transformations) to output format emulation for tooling compatibility. E2E testing is foundational - we built the test harness early and used golden-master comparison (git vs gitsl output) to validate every phase.

## Testing Philosophy

**Golden-Master E2E Testing:** Since Sapling works with git repositories, every command was validated by:
1. Create temp git repository with specific state
2. Run `git <command>` and capture output/exit code
3. Run `gitsl <command>` and capture output/exit code
4. Compare results (exact for porcelain, semantic for human-readable)

## Phases

### Phase 1: Script Skeleton

**Goal**: Script can parse git commands from argv and show what would execute
**Depends on**: Nothing (first phase)
**Requirements**: EXEC-01, EXEC-06
**Success Criteria**:
  1. User can invoke script with git-style arguments and script correctly identifies command and arguments
  2. User can run with debug flag and see translated command without execution
  3. Script handles empty/missing arguments gracefully
**Plans**: 1 plan

Plans:
- [x] 01-01-PLAN.md - Create gitsl.py with argument parsing and debug mode

### Phase 2: E2E Test Infrastructure

**Goal**: Test harness can compare git and gitsl behavior on temp repositories
**Depends on**: Phase 1 (needs script to test)
**Requirements**: TEST-01, TEST-02, TEST-03, TEST-04, TEST-05, TEST-06, TEST-07
**Success Criteria**:
  1. Test can create temp git repo with `tempfile.mkdtemp()` and clean up after
  2. Test can run `git <cmd>` and capture stdout, stderr, exit code
  3. Test can run `gitsl <cmd>` and capture stdout, stderr, exit code
  4. Test can assert exit codes match between git and gitsl
  5. Test can assert exact output match (for porcelain formats)
  6. Test can assert semantic output match (ignoring whitespace, timestamps for human formats)
  7. Test fixtures can create repos with: initial commit, modified files, untracked files, branches
**Plans**: 2 plans

Plans:
- [x] 02-01-PLAN.md - Core test infrastructure (helpers, fixtures, conftest)
- [x] 02-02-PLAN.md - Harness self-validation tests

### Phase 3: Execution Pipeline

**Goal**: Script can execute Sapling commands and faithfully relay results to caller
**Depends on**: Phase 2 (test infra ready)
**Requirements**: ARCH-01, ARCH-02, ARCH-03, ARCH-04, EXEC-02, EXEC-03, EXEC-04, EXEC-05
**Success Criteria**:
  1. gitsl.py contains only entry point logic, dispatches to command handlers
  2. common.py contains shared utilities (parsing, subprocess, debug mode)
  3. Command handlers are in separate files (cmd_*.py pattern)
  4. Script executes sl commands via subprocess without deadlock
  5. Exit code from sl propagates exactly to caller (verified by echo $?)
  6. stdout from sl appears on caller's stdout in real-time
  7. stderr from sl appears on caller's stderr in real-time
  8. Ctrl+C cleanly terminates both script and sl subprocess
**Plans**: 2 plans

Plans:
- [x] 03-01-PLAN.md - Refactor gitsl.py into multi-file architecture
- [x] 03-02-PLAN.md - Implement subprocess execution with E2E tests

### Phase 4: Direct Command Mappings

**Goal**: Simple git commands translate directly to sl equivalents
**Depends on**: Phase 3
**Requirements**: CMD-01, CMD-04, CMD-05, CMD-06, CMD-07
**Success Criteria**:
  1. `git status` runs `sl status` and shows output
  2. `git log` runs `sl log` and shows output
  3. `git diff` runs `sl diff` and shows output
  4. `git init` runs `sl init` and creates repo
  5. `git rev-parse --short HEAD` returns current commit hash via `sl whereami`
**Plans**: 2 plans

Plans:
- [x] 04-01-PLAN.md - Passthrough commands (log, diff, init) with E2E tests
- [x] 04-02-PLAN.md - rev-parse --short HEAD handler with output truncation

### Phase 5: File Operation Commands

**Goal**: File staging and commit commands work correctly
**Depends on**: Phase 4
**Requirements**: CMD-02, CMD-03, CMD-08
**Success Criteria**:
  1. `git add <files>` stages specified files via `sl add`
  2. `git commit -m "message"` creates commit with message via `sl commit`
  3. `git add -A` stages all changes including new/deleted files via `sl addremove`
**Plans**: 1 plan

Plans:
- [x] 05-01-PLAN.md - Add and commit handlers with flag translation for -A/--all

### Phase 6: Status Output Emulation

**Goal**: Status output matches git's format exactly for tooling compatibility
**Depends on**: Phase 4
**Requirements**: FLAG-01, FLAG-02
**Success Criteria**:
  1. `git status --porcelain` outputs 2-character status codes matching git exactly
  2. `git status --short` outputs abbreviated status matching git format
  3. Tools parsing git status output work without modification
**Plans**: 1 plan

Plans:
- [x] 06-01-PLAN.md - Porcelain and short output transformation with E2E tests

### Phase 7: Log Output Emulation

**Goal**: Log output supports git's format options
**Depends on**: Phase 4
**Requirements**: FLAG-04, FLAG-05
**Success Criteria**:
  1. `git log --oneline` outputs `<hash> <subject>` format via sl template
  2. `git log -N` limits output to N commits via `sl log -l N`
  3. `git log --oneline -5` combines both flags correctly
**Plans**: 1 plan

Plans:
- [x] 07-01-PLAN.md - Flag translation for --oneline and -N with E2E tests

### Phase 8: Add -u Emulation

**Goal**: Stage only modified tracked files (exclude new files)
**Depends on**: Phase 5
**Requirements**: FLAG-03
**Success Criteria**:
  1. `git add -u` finds modified tracked files via `sl status -m` and stages them
  2. Untracked files are NOT staged when using -u
  3. Deleted files are marked for removal when using -u
**Plans**: 1 plan

Plans:
- [x] 08-01-PLAN.md - Implement -u/--update flag with deleted file handling

### Phase 9: Unsupported Command Handling

**Goal**: Gracefully handle commands we cannot translate
**Depends on**: Phase 3
**Requirements**: UNSUP-01, UNSUP-02
**Success Criteria**:
  1. Unsupported commands print original git command to stderr
  2. Unsupported commands exit with code 0 (prevent calling tool from failing)
  3. Message clearly indicates command is not supported by shim
**Plans**: 1 plan

Plans:
- [x] 09-01-PLAN.md - Implement unsupported command handler with E2E tests

---

## Milestone Summary

**Key Decisions:**

- Manual argv parsing instead of argparse for git-style command handling
- Debug mode via environment variable (GITSL_DEBUG) to avoid consuming args
- Multi-file architecture: gitsl.py entry point only, common.py shared logic, one file per command
- subprocess.run() defaults for real-time I/O passthrough (no PIPE)
- Status code mapping: sl M -> git ' M' (space+M), sl A -> git 'A ' (A+space)
- sl-template-output pattern for custom output formats (--oneline)
- Exit code 0 on unsupported commands to not break calling tools

**Issues Resolved:**

- Python executable portability (use sys.executable, not "python")
- Path.resolve() for symlink handling on macOS
- sl vs git status code differences handled via mapping dict

**Technical Debt Incurred:**

None - all requirements implemented as specified.

---

*For current project status, see .planning/ROADMAP.md*
