Skip to content

Simple git subtree management through declarative configuration with file extraction and validation capabilities.

License

Notifications You must be signed in to change notification settings

21-DOT-DEV/subtree

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌳 Subtree CLI

Simplify git subtree management through declarative configuration with safe file extraction and validation capabilities.

CI Status Swift 6.0+ License

Objectives

  • Declarative Configuration - Manage subtrees through a simple subtree.yaml file instead of remembering complex git commands
  • Atomic Operations - All subtree changes include configuration updates in single commits for perfect consistency
  • Safe File Management - Extract files from subtrees with smart overwrite protection and validation
  • Developer Experience - Intuitive CLI with clear error messages, dry-run modes, and helpful guidance

Note

Subtree CLI wraps git subtree with enhanced safety and convenience - your existing git history remains unchanged.

Table of Contents

Installation

Requirements

Important

You must be inside a Git repository to use Subtree CLI. The tool will not initialize repositories for you.

  • Swift 6.0+ toolchain
  • macOS 13+ or Linux (glibc 2.27+)
  • Git installed and available on PATH

Swift Package Manager

Add the following to your Package.swift dependencies:

dependencies: [
    .package(url: "https://github.com/21-DOT-DEV/subtree.git", from: "1.0.0")
]

GitHub Releases

Download pre-built binaries from GitHub Releases:

  1. Download the appropriate binary for your platform:

    • subtree_1.0.0_macOS_arm64 (Apple Silicon)
    • subtree_1.0.0_macOS_x86_64 (Intel Mac)
    • subtree_1.0.0_linux_x86_64 (Linux)
    • subtree_1.0.0_linux_arm64 (Linux ARM)
  2. Make executable and add to PATH:

    chmod +x subtree_1.0.0_macOS_arm64
    mv subtree_1.0.0_macOS_arm64 /usr/local/bin/subtree

Swift Artifact Bundle

Use the artifact bundle for Swift Package Manager integration:

dependencies: [
    .binaryTarget(
        name: "subtree",
        url: "https://github.com/21-DOT-DEV/subtree/releases/download/1.0.0/subtree.artifactbundle.zip",
        checksum: "..."
    )
]

Build from Source

git clone https://github.com/21-DOT-DEV/subtree.git
cd subtree
swift build -c release
./.build/release/subtree --help

Usage Examples

πŸš€ Quick Start

Create your first subtree.yaml configuration:

# Create minimal config in your git repository
subtree init

# 🎯 Interactive setup with step-by-step guidance (TTY only)
subtree init --interactive

Tip

Start with --interactive mode to get familiar with the configuration format!

πŸ“¦ Add Subtrees

Add configured subtrees to your repository:

# Add a single subtree by name
subtree add --name example-lib

# Add with explicit overrides
subtree add --name libfoo \
  --remote https://github.com/example/libfoo.git \
  --prefix Vendor/libfoo \
  --ref main \
  --no-squash

# Add all configured subtrees
subtree add --all

πŸ”„ Update Subtrees

Manage subtree updates with various strategies:

# Report pending updates (no changes, exit 5 if updates available)
subtree update

# Apply updates (one commit per subtree on topic branch)
subtree update --commit

# Single commit with all updates on current branch
subtree update --commit --single-commit --on-current

# Dry run to preview changes
subtree update --dry-run

πŸ—‘οΈ Remove Subtrees

# Remove a configured subtree
subtree remove --name example-lib

πŸ“‚ Extract Files

Copy files from subtrees to your repository:

Warning

Extract operations respect Git's tracking status - tracked files are protected unless you use --force.

# Ad-hoc file extraction with glob patterns
subtree extract --name example-lib --from "docs/**/*.md" --to Docs/

# Multi-pattern extraction (009) - extract from multiple directories at once
subtree extract --name mylib \
  --from "include/**/*.h" \
  --from "src/**/*.c" \
  --to vendor/

# Multi-destination extraction (012) - fan-out to multiple locations
subtree extract --name mylib \
  --from "**/*.h" \
  --to Lib/include/ \
  --to Vendor/headers/

# Combined: multi-pattern + multi-destination (cartesian product)
subtree extract --name mylib \
  --from "*.h" --from "*.c" \
  --to Lib/ --to Vendor/

# Brace expansion (011) - compact patterns with {alternatives}
subtree extract --name mylib --from "*.{h,c,cpp}" --to Sources/
subtree extract --name mylib --from "{src,test}/*.swift" --to Sources/

# Brace expansion with embedded path separators (different directory depths)
subtree extract --name crypto-lib \
  --from "Sources/{PrettyBytes,SecureBytes,BoringSSL/RNG}.swift" \
  --to Crypto/

# With exclusions (applies to all patterns)
subtree extract --name mylib --from "src/**/*.c" --to Sources/ --exclude "**/test/**"

# Save multi-destination mapping for future use
subtree extract --name mylib --from "**/*.h" --to Lib/ --to Vendor/ --persist

# Execute saved mappings from subtree.yaml
subtree extract --name example-lib
subtree extract --all

🧹 Clean Extracted Files

Remove previously extracted files with checksum validation:

# Clean specific files (validates checksums before deletion)
subtree extract --clean --name mylib --from "src/**/*.c" --to Sources/

# Clean from multiple destinations (012)
subtree extract --clean --name mylib --from "**/*.h" --to Lib/ --to Vendor/

# Clean all saved mappings for a subtree
subtree extract --clean --name mylib

# Clean all mappings for all subtrees
subtree extract --clean --all

# Force clean modified files (skips checksum validation)
subtree extract --clean --force --name mylib --from "*.c" --to Sources/

βœ… Validate Subtree State

Verify subtree integrity and synchronization:

# Offline validation against commit hash
subtree validate

# Validate specific subtree with pattern
subtree validate --name example-lib --from "**/*.md"

# Repair discrepancies
subtree validate --repair

# Include remote divergence check
subtree validate --with-remote

API Reference

Commands

  • init - Initialize subtree.yaml configuration

    • --import - Scan for existing git subtrees
    • --interactive - Guided setup (TTY only)
    • --force - Overwrite existing configuration
  • add - Add configured subtrees

    • --name <name> - Add specific subtree
    • --all - Add all configured subtrees
    • Override flags: --remote, --prefix, --ref, --no-squash
  • update - Update subtrees with various strategies

    • --name <name> - Update specific subtree
    • --all - Update all subtrees
    • --commit - Apply updates (default: report only)
    • --mode <branch|tag|release> - Update strategy
    • --branch <name> - Custom topic branch name
    • --single-commit - Squash all updates into one commit
    • --on-current - Apply updates to current branch
    • --dry-run - Preview changes without applying
    • --force - Override safety checks
  • remove - Remove configured subtrees

    • --name <name> - Remove specific subtree
  • extract - Copy or clean files from subtrees

    • --name <name> - Extract from specific subtree
    • --from <pattern> - Source glob pattern (repeatable for multi-pattern)
    • --to <path> - Destination path
    • --exclude <pattern> - Exclude pattern (repeatable)
    • --all - Execute all saved mappings
    • --persist - Save mapping to subtree.yaml
    • --force - Overwrite git-tracked files / force delete modified files
    • --clean - Remove extracted files (validates checksums first)
    • Multi-destination: Use --to multiple times for fan-out extraction
  • validate - Verify subtree integrity

    • --name <name> - Validate specific subtree
    • --from <pattern> - Validate specific files
    • --repair - Fix discrepancies
    • --with-remote - Include remote comparison

Exit Codes

  • 0 - Success
  • 1 - General error
  • 2 - Invalid usage or configuration
  • 3 - Git operation failure or not in Git repository
  • 4 - Configuration file not found
  • 5 - Updates available (report mode only)

Configuration Format

subtree.yaml schema:

subtrees:
  - name: example-lib                    # Unique identifier
    remote: https://github.com/example/lib.git
    prefix: Sources/ThirdParty/ExampleLib
    branch: main
    squash: true                         # Default: true
    commit: 0123456789abcdef...          # Latest known commit
    extractions:                         # File extraction mappings
      # Single pattern, single destination (legacy format)
      - from: "docs/**/*.md"
        to: Docs/
      # Multi-pattern (009) - union extraction
      - from:
          - "include/**/*.h"
          - "src/**/*.c"
        to: vendor/
        exclude:
          - "**/test/**"
      # Multi-destination (012) - fan-out to multiple locations
      - from: "**/*.h"
        to:
          - Lib/include/
          - Vendor/headers/
      # Combined: multi-pattern + multi-destination
      - from:
          - "*.h"
          - "*.c"
        to:
          - Lib/
          - Vendor/

Platform Compatibility

Platform Architecture Minimum Version Status
macOS arm64, x86_64 13.0+ βœ… Supported
Linux x86_64, arm64 glibc 2.27+ βœ… Supported
Windows x86_64, arm64 Windows 10+ Future

Dependencies:

  • Swift 6.0+ toolchain
  • Git (any recent version)
  • ArgumentParser 1.6.1
  • Yams 6.1.0
  • swift-subprocess 0.1.0+
  • SemanticVersion 0.5.1

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Quick Start for Contributors

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Run tests: swift test
  4. Make your changes following our coding standards
  5. Add tests for new functionality
  6. Submit a pull request

Development Setup

git clone https://github.com/21-DOT-DEV/subtree.git
cd subtree
swift build
swift test

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Simple git subtree management through declarative configuration with file extraction and validation capabilities.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published