---
phase: 25-commit-and-branch-flags
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - cmd_commit.py
  - cmd_branch.py
autonomous: true

must_haves:
  truths:
    - "User running `git commit --amend` can modify the last commit"
    - "User running `git commit --amend --no-edit` amends without changing message"
    - "User running `git commit -F <file>` commits with message from file"
    - "User running `git commit --author='Name <email>'` sets commit author"
    - "User running `git commit -s` adds Signed-off-by trailer"
    - "User running `git branch -m old new` renames a branch"
    - "User running `git branch -a` sees all branches including remote"
    - "User running `git branch --show-current` sees just the current branch name"
    - "User running `git branch -c old new` copies a branch"
  artifacts:
    - path: "cmd_commit.py"
      provides: "Commit flag handling (--amend, --no-edit, -F, --author, --date, -v, -s, -n)"
      contains: "sl amend"
    - path: "cmd_branch.py"
      provides: "Branch flag handling (-m, -a, -r, -v, -l, --show-current, -t, -f, -c)"
      contains: "show_current"
  key_links:
    - from: "cmd_commit.py"
      to: "sl amend"
      via: "--amend flag triggers amend command"
      pattern: "run_sl.*amend"
    - from: "cmd_commit.py"
      to: "sl commit -l"
      via: "-F/--file flag translation"
      pattern: "-l.*message_file"
    - from: "cmd_branch.py"
      to: "sl log template"
      via: "--show-current implementation"
      pattern: "activebookmark"
---

<objective>
Extend cmd_commit.py and cmd_branch.py with comprehensive flag support for COMM-01 through COMM-08 and BRAN-01 through BRAN-09.

Purpose: Users can use advanced commit and branch management flags for amending, authoring, and branch organization.

Output: Updated cmd_commit.py and cmd_branch.py with flag translation following established patterns from cmd_log.py.
</objective>

<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/25-commit-and-branch-flags/25-RESEARCH.md

# Existing implementations to extend
@cmd_commit.py
@cmd_branch.py

# Pattern reference
@cmd_log.py
</context>

<tasks>

<task type="auto">
  <name>Task 1: Extend cmd_commit.py with new flag support</name>
  <files>cmd_commit.py</files>
  <action>
Extend the `handle()` function in cmd_commit.py to support COMM-01 through COMM-08:

**COMM-01: --amend**
- Detect `--amend` flag in args
- When present, use `sl amend` command instead of `sl commit`
- IMPORTANT: sl amend defaults to reusing the existing message (like git --no-edit)
- To match git's default behavior (open editor), add `-e` flag unless `--no-edit` is also present

**COMM-02: --no-edit**
- Detect `--no-edit` flag
- When combined with --amend, do NOT add `-e` flag (sl amend's default behavior)
- Has no effect without --amend (filter it out)

**COMM-03: -F/--file**
- Detect `-F` and `--file` and `--file=<path>`
- Translate to `sl commit -l <file>` or `sl amend -l <file>`
- Handle both `-F filename` and `-F=filename` and `--file filename` and `--file=filename` forms

**COMM-04: --author**
- Detect `--author` and `--author=<author>`
- Translate to `-u <author>` for both commit and amend
- Handle both `--author "Name <email>"` and `--author="Name <email>"` forms

**COMM-05: --date**
- Detect `--date` and `--date=<date>`
- Translate to `-d <date>` for both commit and amend
- Handle both `--date "2024-01-01"` and `--date="2024-01-01"` forms

**COMM-06: -v/--verbose**
- Detect `-v` and `--verbose` flags
- Print warning to stderr: "Note: -v/--verbose in git shows diff in editor. Sapling -v shows repository info. Proceeding without -v."
- Filter out the flag (do not pass to sl)

**COMM-07: -s/--signoff**
- Detect `-s` and `--signoff` flags
- This requires custom implementation to append "Signed-off-by: Name <email>" trailer
- Create helper function `get_user_identity()` that runs `sl config ui.username` to get configured identity
- Create helper function `add_signoff_to_message(message: str) -> str`
- For signoff with -m: modify message before passing to sl
- For signoff with -F: read file, add trailer, write to temp file, use that with -l
- For signoff without -m/-F: add `--config 'committemplate.signoff=Signed-off-by: {username}'` or use temp file approach

**COMM-08: -n/--no-verify**
- Detect `-n` and `--no-verify` flags
- Print warning to stderr: "Warning: --no-verify not directly supported. Sapling has no native hook bypass. Pre-commit hooks will still run."
- Filter out the flag (do not pass to sl)

**Implementation structure:**
```python
"""Handler for 'git commit' command.

Supported flags:
- COMM-01: --amend -> sl amend command
- COMM-02: --no-edit -> omit -e with amend (default sl amend behavior)
- COMM-03: -F/--file -> -l (logfile)
- COMM-04: --author -> -u (user)
- COMM-05: --date -> -d (date)
- COMM-06: -v/--verbose -> warning (different semantics)
- COMM-07: -s/--signoff -> custom trailer implementation
- COMM-08: -n/--no-verify -> warning (not supported)
"""

import subprocess
import sys
import tempfile
import os
from common import ParsedCommand, run_sl


def get_user_identity() -> str:
    """Get user identity from sl config for signoff trailer."""
    result = subprocess.run(
        ['sl', 'config', 'ui.username'],
        capture_output=True, text=True
    )
    return result.stdout.strip() or "Unknown User <unknown@example.com>"


def add_signoff_trailer(message: str, identity: str) -> str:
    """Append Signed-off-by trailer to message if not already present."""
    trailer = f"Signed-off-by: {identity}"
    if trailer not in message:
        return message.rstrip() + "\n\n" + trailer
    return message


def handle(parsed: ParsedCommand) -> int:
    # ... implementation following cmd_log.py pattern
```

Ensure the existing SAFE-01 logic (removing -a/--all) is preserved.
  </action>
  <verify>
Run manual tests in an sl repo:
```bash
# Create test repo
cd /tmp && rm -rf test_commit && sl init test_commit && cd test_commit
echo "test" > file.txt && sl add file.txt && sl commit -m "Initial"

# Test amend
echo "more" >> file.txt && sl add file.txt
python /path/to/gitsl.py commit --amend --no-edit

# Test -F (message from file)
echo "test2" > file2.txt && sl add file2.txt
echo "Message from file" > /tmp/msg.txt
python /path/to/gitsl.py commit -F /tmp/msg.txt

# Test --author
echo "test3" > file3.txt && sl add file3.txt
python /path/to/gitsl.py commit -m "Test" --author="Test User <test@example.com>"

# Test --signoff
echo "test4" > file4.txt && sl add file4.txt
python /path/to/gitsl.py commit -m "Test" -s
sl log -l 1  # Should show Signed-off-by trailer

# Test warnings
python /path/to/gitsl.py commit --no-verify -m "Test" 2>&1 | grep -i warning
```
  </verify>
  <done>
cmd_commit.py handles --amend, --no-edit, -F/--file, --author, --date, -v (warning), -s/--signoff (custom trailer), and -n/--no-verify (warning) with correct sl translations.
  </done>
</task>

<task type="auto">
  <name>Task 2: Extend cmd_branch.py with new flag support</name>
  <files>cmd_branch.py</files>
  <action>
Extend the `handle()` function in cmd_branch.py to support BRAN-01 through BRAN-09:

**BRAN-01: -m (rename)**
- Detect `-m` flag with two arguments (old and new name)
- Pass through to `sl bookmark -m <old> <new>` (already supported by sl)
- Handle both `-m old new` and `--move old new` forms

**BRAN-02: -a/--all**
- Detect `-a` and `--all` flags
- Translate to `sl bookmark --all` to show all bookmarks including remote

**BRAN-03: -r/--remotes**
- Detect `-r` and `--remotes` flags
- Translate to `sl bookmark --remote` to show only remote bookmarks

**BRAN-04: -v/--verbose**
- Detect `-v` and `--verbose` flags
- Use template to show commit info: `sl bookmark --template "{bookmark}: {node|short} {desc|firstline}\n"`
- For double -v (-vv), show more detail (can use same template for now)

**BRAN-05: -l/--list**
- Detect `-l` and `--list` flags with optional pattern
- When pattern provided, filter bookmarks matching the glob/regex pattern
- Can implement by: run `sl bookmark`, then filter output lines matching pattern
- Handle both `-l pattern` and `--list pattern` forms

**BRAN-06: --show-current**
- Detect `--show-current` flag
- Run `sl log -r . --template "{activebookmark}"` and print result
- If no active bookmark (detached), print nothing (matches git behavior)
- Return 0 regardless

**BRAN-07: -t/--track**
- Detect `-t` and `--track` flags
- Pass through to `sl bookmark -t` for tracking (already supported by sl)
- Note: Sapling tracking is different from git; pass through and let sl handle it

**BRAN-08: -f/--force**
- Detect `-f` and `--force` flags
- Pass through to `sl bookmark -f` for forced bookmark operations
- Already supported by sl bookmark

**BRAN-09: -c/--copy**
- Detect `-c` and `--copy` flags with source and destination
- Implement as two operations:
  1. Get the commit hash where source bookmark points: `sl log -r "bookmark(source)" --template "{node}"`
  2. Create new bookmark at that commit: `sl bookmark dest -r <hash>`
- Handle both `-c old new` and `--copy old new` forms

**Implementation structure:**
```python
"""Handler for 'git branch' command.

Supported flags:
- BRAN-01: -m -> -m (rename bookmark)
- BRAN-02: -a/--all -> --all (show all including remote)
- BRAN-03: -r/--remotes -> --remote (show remote only)
- BRAN-04: -v/--verbose -> template with commit info
- BRAN-05: -l/--list -> filter bookmarks by pattern
- BRAN-06: --show-current -> template query for active bookmark
- BRAN-07: -t/--track -> -t (pass through)
- BRAN-08: -f/--force -> -f (pass through)
- BRAN-09: -c/--copy -> custom two-step implementation
"""

import fnmatch
import subprocess
import sys
from common import ParsedCommand, run_sl


def show_current_branch() -> int:
    """BRAN-06: Show current branch name only."""
    result = subprocess.run(
        ['sl', 'log', '-r', '.', '--template', '{activebookmark}'],
        capture_output=True, text=True
    )
    if result.stdout.strip():
        print(result.stdout.strip())
    return 0


def copy_branch(source: str, dest: str) -> int:
    """BRAN-09: Copy a branch (create new bookmark at same commit)."""
    # Get commit where source bookmark points
    result = subprocess.run(
        ['sl', 'log', '-r', f'bookmark({source})', '--template', '{node}'],
        capture_output=True, text=True
    )
    if result.returncode != 0 or not result.stdout.strip():
        sys.stderr.write(f"error: branch '{source}' not found\n")
        return 1

    commit = result.stdout.strip()

    # Create new bookmark at that commit
    return run_sl(['bookmark', dest, '-r', commit])


def handle(parsed: ParsedCommand) -> int:
    # ... implementation following cmd_log.py pattern
```

Ensure the existing SAFE-04 logic (-D to -d translation) is preserved.
  </action>
  <verify>
Run manual tests in an sl repo:
```bash
# Create test repo with bookmarks
cd /tmp && rm -rf test_branch && sl init test_branch && cd test_branch
echo "test" > file.txt && sl add file.txt && sl commit -m "Initial"
sl bookmark main

# Test -m (rename)
sl bookmark feature
python /path/to/gitsl.py branch -m feature feature-renamed
sl bookmark  # Should show feature-renamed, not feature

# Test -a (all bookmarks)
python /path/to/gitsl.py branch -a

# Test -v (verbose)
python /path/to/gitsl.py branch -v  # Should show commit info

# Test --show-current
sl goto main
python /path/to/gitsl.py branch --show-current  # Should print "main"

# Test -c (copy)
python /path/to/gitsl.py branch -c main main-copy
sl bookmark  # Should show both main and main-copy at same commit

# Test -l (list with pattern)
python /path/to/gitsl.py branch -l "main*"  # Should show main and main-copy
```
  </verify>
  <done>
cmd_branch.py handles -m, -a/--all, -r/--remotes, -v/--verbose, -l/--list, --show-current, -t/--track, -f/--force, and -c/--copy with correct sl translations.
  </done>
</task>

</tasks>

<verification>
After completing both tasks:

1. Run existing tests to verify no regressions:
```bash
pytest tests/test_commit.py tests/test_branch.py -v
```

2. Verify all new commit flags work in an sl repo:
```bash
# Amend with no-edit
python gitsl.py commit --amend --no-edit
# Author override
python gitsl.py commit --author="Test <test@test.com>" -m "Test"
# Signoff
python gitsl.py commit -s -m "Signed commit"
```

3. Verify all new branch flags work:
```bash
# Rename
python gitsl.py branch -m old new
# Show current
python gitsl.py branch --show-current
# Copy
python gitsl.py branch -c existing new-copy
# Verbose
python gitsl.py branch -v
```
</verification>

<success_criteria>
1. `git commit --amend` uses sl amend command with -e flag by default
2. `git commit --amend --no-edit` uses sl amend without -e flag
3. `git commit -F <file>` reads message from file via -l flag
4. `git commit --author=<author>` sets author via -u flag
5. `git commit --date=<date>` sets date via -d flag
6. `git commit -v` prints note about different semantics
7. `git commit -s` adds Signed-off-by trailer to message
8. `git commit -n/--no-verify` prints warning about hook bypass
9. `git branch -m old new` renames bookmark via -m flag
10. `git branch -a` shows all bookmarks via --all flag
11. `git branch -r` shows remote bookmarks via --remote flag
12. `git branch -v` shows commit info via template
13. `git branch -l pattern` filters bookmarks by pattern
14. `git branch --show-current` outputs current bookmark name
15. `git branch -t` passes through tracking flag
16. `git branch -f` passes through force flag
17. `git branch -c old new` copies bookmark to new name
18. All existing commit/branch tests pass (SAFE-01, SAFE-04 preserved)
</success_criteria>

<output>
After completion, create `.planning/phases/25-commit-and-branch-flags/25-01-SUMMARY.md`
</output>
