Introduction
Welcome to MediaGit-Core, a next-generation media versioning system built with Rust that replaces Git-LFS with intelligent compression, multi-backend storage, full branching support, and media-aware merging capabilities.
What is MediaGit-Core?
MediaGit-Core is an open-source version control system designed specifically for managing large binary files (media assets) with the same efficiency and flexibility that Git provides for source code. It solves the fundamental limitations of Git-LFS while providing a familiar Git-like interface.
Key Features
High Performance
- Fast staging: 25–240 MB/s for large files (release build)
- Efficient storage: Up to 81% savings via compression + dedup + delta encoding
- Parallel operations: Optimized for modern multi-core systems
Multi-Backend Storage
Support for 7 storage backends with zero vendor lock-in:
- Local filesystem
- Amazon S3
- Azure Blob Storage
- Backblaze B2
- Google Cloud Storage
- MinIO
- DigitalOcean Spaces
Media-Aware Merging
Intelligent conflict detection and resolution for:
- Images (PSD, PNG, JPEG, WebP)
- Video files (MP4, MOV, AVI)
- Audio files (WAV, MP3, FLAC)
- 3D models and game assets
Full Branching Support
- Create, merge, and rebase branches just like Git
- Protected branches with review requirements
- Branch-specific storage optimization
Enterprise-Ready
- AGPL-3.0 community license + commercial licensing
- Audit trails and security features
- Self-hosted or cloud deployment options
Who Should Use MediaGit-Core?
MediaGit-Core is designed for teams and individuals working with large binary files:
- Game Developers: Manage textures, models, and game assets
- VFX Artists: Version video files, composites, and renders
- ML Engineers: Track datasets and model files
- Design Teams: Collaborate on PSD files and design assets
- Media Production: Manage video, audio, and multimedia projects
How Does It Compare?
| Feature | MediaGit-Core | Git-LFS | Perforce |
|---|---|---|---|
| Architecture | Standalone native VCS | Git extension + server | Centralized VCS |
| Branch Switch Speed | Instant (ref-based) | Instant (Git handles) | ⚠️ Copy-based |
| Storage Savings (avg) | Up to 81% (compression + dedup + delta) | ~0% (no dedup/delta) | ~10-20% (RCS deltas) |
| Deduplication | ✅ Content-addressable | ❌ None | ✅ Server-side |
| Multi-Backend Support | 7 backends | Server-dependent | Proprietary |
| Media-Aware Merging | ✅ Yes | ❌ No | ⚠️ Limited |
| Offline Commits | ✅ Full DVCS | ✅ (Git handles) | ❌ Server required |
| Open Source | ✅ AGPL-3.0 | ✅ MIT | ❌ No |
Quick Example
# Initialize a repository
mediagit init my-project
cd my-project
# Add and commit media files
mediagit add textures/*.png
mediagit commit -m "Add game textures"
# Create a feature branch
mediagit branch create feature/new-assets
# Work on the branch
mediagit add models/*.fbx
mediagit commit -m "Add 3D models"
# Merge back to main
mediagit branch switch main
mediagit merge feature/new-assets
Getting Started
Ready to get started? Head to the Installation guide to install MediaGit-Core on your platform, then follow the Quickstart Guide for a 5-minute tutorial.
License
MediaGit-Core is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
- ✅ Free to use, modify, and distribute
- ✅ Source code must be made available
- ✅ Network use requires source disclosure (AGPL provision)
- ✅ Commercial use allowed with license compliance
See the LICENSE file for details.
Community and Support
- GitHub: winnyboy5/mediagit-core
- Documentation: https://winnyboy5.github.io/mediagit-core
- Issues: GitHub Issues
What’s Next?
- Installation Guide - Install MediaGit-Core on your platform
- Quickstart Guide - Get up and running in 5 minutes
- CLI Reference - Comprehensive command reference
- Architecture - Learn how MediaGit-Core works
Installation
MediaGit-Core provides pre-built binaries for all major platforms and architectures. Choose your platform below for detailed installation instructions.
Quick Install
Linux / macOS (one-liner)
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
The install script automatically detects your OS and architecture and downloads the correct binary.
Linux (x86_64) — manual
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz \
| tar xz -C /usr/local/bin
macOS (Apple Silicon) — manual
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-macos.tar.gz \
| tar xz -C /usr/local/bin
Windows (x86_64 — PowerShell)
Invoke-WebRequest -Uri "https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-windows.zip" -OutFile mediagit.zip
Expand-Archive mediagit.zip -DestinationPath "$env:LOCALAPPDATA\MediaGit\bin"
Docker
docker pull ghcr.io/winnyboy5/mediagit-core:0.2.6-beta.1
docker run --rm ghcr.io/winnyboy5/mediagit-core:0.2.6-beta.1 mediagit --version
All Release Archives
Each release on GitHub Releases includes:
| Platform | Archive |
|---|---|
| Linux x86_64 | mediagit-{VERSION}-x86_64-linux.tar.gz |
| Linux ARM64 | mediagit-{VERSION}-aarch64-linux.tar.gz |
| macOS Intel | mediagit-{VERSION}-x86_64-macos.tar.gz |
| macOS Apple Silicon | mediagit-{VERSION}-aarch64-macos.tar.gz |
| Windows x86_64 | mediagit-{VERSION}-x86_64-windows.zip |
Each archive contains both mediagit (CLI) and mediagit-server binaries, with a corresponding .sha256 checksum file.
Platform-Specific Guides
- Linux x64 - Ubuntu, Debian, Fedora, Arch, etc.
- Linux ARM64 - Raspberry Pi, ARM servers
- macOS Intel - Intel-based Macs
- macOS ARM64 (M1/M2/M3) - Apple Silicon Macs
- Windows x64 - Windows 10/11 64-bit
- Windows ARM64 - Windows on ARM (Surface Pro X, etc.)
- Building from Source - Build with Rust/Cargo
System Requirements
Minimum Requirements
- CPU: x64 or ARM64 processor (2+ cores recommended)
- RAM: 512MB minimum, 2GB recommended
- Disk: 100MB for binaries, additional space for repositories
- OS: Linux (kernel 4.4+), macOS 10.15+, Windows 10+
Recommended Requirements
- CPU: 4+ cores for parallel operations
- RAM: 4GB+ for large repositories
- Disk: SSD for best performance
- Network: Stable internet for cloud backends
Verifying Installation
After installation, verify MediaGit-Core is working:
# Check version
mediagit --version
# Should output: mediagit-core 0.2.6-beta.1
# Run self-test
mediagit fsck --self-test
# Should output: All checks passed ✓
Cloud Backend Setup (Optional)
If you plan to use cloud storage backends (S3, Azure, GCS, etc.), you’ll need:
AWS S3
# Install AWS CLI
# Configure credentials
aws configure
# MediaGit will use AWS credentials automatically
Azure Blob Storage
# Install Azure CLI
az login
# MediaGit will use Azure credentials automatically
Google Cloud Storage
# Install gcloud CLI
gcloud auth login
# MediaGit will use gcloud credentials automatically
Next Steps
After installation:
- Follow the Quickstart Guide for a 5-minute tutorial
- Read Configuration to customize MediaGit
- Explore CLI Reference for all available commands
Troubleshooting
If you encounter issues:
- Check Troubleshooting Guide
- Verify system requirements above
- Ensure PATH is configured correctly
- Try building from source as fallback
Uninstalling
Linux/macOS
sudo rm /usr/local/bin/mediagit /usr/local/bin/mediagit-server
Windows
# Remove binary directory and clean PATH
Remove-Item "$env:LOCALAPPDATA\MediaGit" -Recurse -Force
Docker
docker rmi ghcr.io/winnyboy5/mediagit-core:0.2.6-beta.1
Linux x64 Installation
MediaGit-Core provides pre-built binaries and package manager support for Linux x64 systems.
Quick Install (Recommended)
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
This script automatically detects your architecture and downloads the correct binary from GitHub Releases.
Direct Download (x86_64)
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz \
| sudo tar xz -C /usr/local/bin
mediagit --version
The archive contains both mediagit and mediagit-server binaries.
Distribution-Specific Installation
Ubuntu / Debian
Using APT Repository
# Add MediaGit repository
curl -fsSL https://apt.mediagit.dev/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/mediagit-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/mediagit-archive-keyring.gpg] https://apt.mediagit.dev stable main" | sudo tee /etc/apt/sources.list.d/mediagit.list
# Update and install
sudo apt update
sudo apt install mediagit-core
Using .deb Package
# Download latest release
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit_0.2.6-beta.1_amd64.deb
# Install
sudo dpkg -i mediagit_0.2.6-beta.1_amd64.deb
# Fix dependencies if needed
sudo apt-get install -f
Fedora / RHEL / CentOS
Using DNF/YUM
# Add MediaGit repository
sudo dnf config-manager --add-repo https://rpm.mediagit.dev/mediagit.repo
# Install
sudo dnf install mediagit-core
# For older systems using yum
sudo yum install mediagit-core
Using .rpm Package
# Download latest release
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-1.x86_64.rpm
# Install
sudo rpm -i mediagit-0.2.6-beta.1-1.x86_64.rpm
Arch Linux
# Install from AUR
yay -S mediagit-core
# Or using paru
paru -S mediagit-core
# Manual AUR installation
git clone https://aur.archlinux.org/mediagit-core.git
cd mediagit-core
makepkg -si
openSUSE
# Add repository
sudo zypper addrepo https://download.opensuse.org/repositories/home:mediagit/openSUSE_Tumbleweed/home:mediagit.repo
# Install
sudo zypper refresh
sudo zypper install mediagit-core
Manual Binary Installation
If package managers aren’t available, install manually:
# Download archive
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
# Verify checksum
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz.sha256
sha256sum -c mediagit-0.2.6-beta.1-x86_64-linux.tar.gz.sha256
# Extract (contains mediagit + mediagit-server)
tar -xzf mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
# Move to bin directory
sudo mv mediagit mediagit-server /usr/local/bin/
# Verify installation
mediagit --version
Post-Installation Setup
Shell Completions
Bash
mediagit completions bash > ~/.local/share/bash-completion/completions/mediagit
Zsh
mediagit completions zsh > ~/.zfunc/_mediagit
echo 'fpath=(~/.zfunc $fpath)' >> ~/.zshrc
Fish
mediagit completions fish > ~/.config/fish/completions/mediagit.fish
Environment Variables
Add to ~/.bashrc or ~/.zshrc:
# Optional: Set default backend
export MEDIAGIT_DEFAULT_BACKEND=local
# Optional: Set storage path
export MEDIAGIT_STORAGE_PATH=~/.mediagit/storage
# Optional: Enable debug logging
export MEDIAGIT_LOG=debug
Verify Installation
# Check version
mediagit --version
# Run self-test
mediagit fsck --self-test
# Create test repository
mkdir test-repo
cd test-repo
mediagit init
Expected output:
mediagit-core 0.2.6-beta.1
✓ Initialized empty MediaGit repository in .mediagit/
System Requirements
- CPU: x86_64 processor (Intel, AMD)
- RAM: 512MB minimum, 2GB recommended
- Disk: 100MB for binaries
- OS: Linux kernel 4.4+ (glibc 2.17+)
- Dependencies: None (statically linked)
Verified Distributions
| Distribution | Version | Status |
|---|---|---|
| Ubuntu | 20.04, 22.04, 24.04 | ✅ Tested |
| Debian | 10, 11, 12 | ✅ Tested |
| Fedora | 38, 39, 40 | ✅ Tested |
| RHEL | 8, 9 | ✅ Tested |
| CentOS | 7, 8, Stream 9 | ✅ Tested |
| Arch Linux | Rolling | ✅ Tested |
| openSUSE | Leap 15.5, Tumbleweed | ✅ Tested |
Troubleshooting
Permission Denied
# If standard install fails, try user-local install
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh -s -- --no-sudo
# Add to PATH
export PATH="$HOME/.local/bin:$PATH"
GLIBC Version Too Old
If you see: version 'GLIBC_2.17' not found:
# Check your glibc version
ldd --version
# Solution 1: Upgrade your system
sudo apt update && sudo apt upgrade
# Solution 2: Build from source
# See: Building from Source guide
Command Not Found
# Check if binary exists
which mediagit
# If not found, add to PATH
export PATH="/usr/local/bin:$PATH"
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc
SSL Certificate Errors
# Update CA certificates
sudo apt update
sudo apt install ca-certificates
# Or for Fedora/RHEL
sudo dnf install ca-certificates
Updating
APT/DNF Repository
# Ubuntu/Debian
sudo apt update && sudo apt upgrade mediagit-core
# Fedora/RHEL
sudo dnf update mediagit-core
Manual Update
# Re-run install script (downloads latest)
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
# Or download specific version manually
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
tar -xzf mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
sudo mv mediagit mediagit-server /usr/local/bin/
Uninstalling
APT
sudo apt remove mediagit-core
DNF/YUM
sudo dnf remove mediagit-core
Manual
sudo rm /usr/local/bin/mediagit
rm -rf ~/.mediagit
Next Steps
- Quickstart Guide - Get started in 5 minutes
- Configuration - Customize MediaGit
- CLI Reference - Learn all commands
Linux ARM64 Installation
MediaGit-Core supports ARM64 Linux systems including Raspberry Pi, ARM servers, and cloud ARM instances.
Quick Install
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
The script auto-detects ARM64 architecture and downloads the correct binary from GitHub Releases.
Raspberry Pi Setup
Raspberry Pi OS (64-bit)
# Update system
sudo apt update && sudo apt upgrade
# Install MediaGit
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
tar -xzf mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
sudo mv mediagit /usr/local/bin/
sudo chmod +x /usr/local/bin/mediagit
# Verify
mediagit --version
Raspberry Pi 4/5 Optimization
# ~/.mediagit/config.toml
[performance]
worker_threads = 4 # Raspberry Pi 4/5 has 4 cores
chunk_size = "4MB" # Optimize for limited RAM
[compression]
algorithm = "zstd"
level = "fast" # Less CPU intensive
ARM Server Installation
Ubuntu Server ARM64
# Add MediaGit repository
curl -fsSL https://apt.mediagit.dev/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/mediagit-archive-keyring.gpg
echo "deb [arch=arm64 signed-by=/usr/share/keyrings/mediagit-archive-keyring.gpg] https://apt.mediagit.dev stable main" | sudo tee /etc/apt/sources.list.d/mediagit.list
# Install
sudo apt update
sudo apt install mediagit-core
Amazon Linux 2 (Graviton)
# Download ARM64 build
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
# Install
tar -xzf mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
sudo mv mediagit /usr/local/bin/
sudo chmod +x /usr/local/bin/mediagit
Cloud ARM Instances
AWS Graviton (EC2 t4g, c7g)
Optimized for AWS Graviton processors:
# Install
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
# Configure for Graviton
mediagit config set performance.worker_threads $(nproc)
mediagit config set compression.algorithm zstd
Oracle Cloud Ampere
# Install on Oracle Cloud ARM instances
sudo dnf config-manager --add-repo https://rpm.mediagit.dev/mediagit.repo
sudo dnf install mediagit-core
Azure ARM VMs
# Ubuntu 22.04 ARM64
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
Manual Binary Installation
# Download ARM64 binary
wget https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
# Extract and install
tar -xzf mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
sudo mv mediagit /usr/local/bin/
sudo chmod +x /usr/local/bin/mediagit
# Verify
mediagit --version
Performance Tuning for ARM
Memory-Constrained Devices (1-2GB RAM)
# ~/.mediagit/config.toml
[performance]
worker_threads = 2
chunk_size = "2MB"
cache_size = "256MB"
[compression]
level = "fast"
parallel = false
High-Performance ARM Servers (Graviton 3, Ampere Altra)
# ~/.mediagit/config.toml
[performance]
worker_threads = 64 # Full core utilization
chunk_size = "16MB"
cache_size = "4GB"
[compression]
level = 3
parallel = true
threads = 8
System Requirements
- CPU: ARMv8-A or later (AArch64)
- RAM: 512MB minimum, 2GB recommended
- Disk: 100MB for binaries
- OS: Linux kernel 4.4+
Verified ARM Platforms
| Platform | Version | Status |
|---|---|---|
| Raspberry Pi 4 | 8GB | ✅ Tested |
| Raspberry Pi 5 | 4GB, 8GB | ✅ Tested |
| AWS Graviton 2/3 | All instance types | ✅ Tested |
| Oracle Ampere A1 | All shapes | ✅ Tested |
| Azure ARM64 VMs | Dpsv5, Epsv5 series | ✅ Tested |
| Ampere Altra | All SKUs | ✅ Tested |
Troubleshooting
Illegal Instruction Error
If you see “Illegal instruction”:
# Check CPU features
cat /proc/cpuinfo | grep Features
# Ensure ARMv8-A or later
uname -m # Should output: aarch64
Out of Memory on Raspberry Pi
# Reduce memory usage
[performance]
worker_threads = 1
chunk_size = "1MB"
cache_size = "128MB"
[compression]
level = "fast"
parallel = false
Slow Performance
# Check CPU frequency (may be throttled)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
# Enable performance governor
sudo apt install cpufrequtils
sudo cpufreq-set -g performance
Building from Source (ARM64)
If pre-built binaries don’t work:
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone and build
git clone https://github.com/winnyboy5/mediagit-core.git
cd mediagit-core
cargo build --release --target aarch64-unknown-linux-gnu
# Install
sudo mv target/aarch64-unknown-linux-gnu/release/mediagit /usr/local/bin/
Cross-Compilation (Advanced)
Compile ARM64 binaries on x64 machines:
# Install cross-compilation tools
rustup target add aarch64-unknown-linux-gnu
sudo apt install gcc-aarch64-linux-gnu
# Build
cargo build --release --target aarch64-unknown-linux-gnu
Next Steps
- Quickstart Guide - Get started in 5 minutes
- Performance Optimization - Tune for your hardware
- Configuration - Customize settings
macOS Intel Installation
MediaGit-Core provides native binaries optimized for Intel-based Macs.
Quick Install (Homebrew - Recommended)
brew tap mediagit/tap
brew install mediagit-core
Alternative Installation Methods
Direct Binary Download
# Download latest Intel binary
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-macos.tar.gz \
| sudo tar xz -C /usr/local/bin
# Verify
mediagit --version
Using Installation Script
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
macOS Gatekeeper Approval
First run may require security approval:
# If you see "cannot be opened because the developer cannot be verified"
xattr -d com.apple.quarantine /usr/local/bin/mediagit
# Or approve via System Preferences
# System Preferences → Security & Privacy → General → "Allow Anyway"
Post-Installation Setup
Shell Completions
Zsh (default on macOS 10.15+)
mediagit completions zsh > /usr/local/share/zsh/site-functions/_mediagit
Bash
brew install bash-completion
mediagit completions bash > /usr/local/etc/bash_completion.d/mediagit
Environment Variables
Add to ~/.zshrc:
# Optional: Set default backend
export MEDIAGIT_DEFAULT_BACKEND=local
# Optional: Enable debug logging
export MEDIAGIT_LOG=info
System Requirements
- macOS Version: 10.15 Catalina or later
- CPU: Intel Core 2 Duo or later
- RAM: 512MB minimum, 2GB recommended
- Disk: 100MB for binaries
- Xcode: Command Line Tools (optional, for some features)
Install Xcode Command Line Tools
xcode-select --install
Verification
# Check version
mediagit --version
# Run self-test
mediagit fsck --self-test
# Create test repo
mkdir ~/test-mediagit
cd ~/test-mediagit
mediagit init
Expected output:
mediagit-core 0.2.6-beta.1
✓ All checks passed
✓ Initialized empty MediaGit repository in .mediagit/
Troubleshooting
“mediagit” cannot be opened
# Remove quarantine attribute
xattr -d com.apple.quarantine /usr/local/bin/mediagit
# If that doesn't work, explicitly allow in System Preferences
open "x-apple.systempreferences:com.apple.preference.security"
Command Not Found
# Check if binary exists
which mediagit
# If not found, check PATH
echo $PATH
# Add /usr/local/bin to PATH
export PATH="/usr/local/bin:$PATH"
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
Homebrew Not Found
# Install Homebrew first
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Permission Issues
# If brew install fails with permissions
sudo chown -R $(whoami) /usr/local/bin /usr/local/lib /usr/local/share
# Retry installation
brew install mediagit-core
Updating
Via Homebrew
brew update
brew upgrade mediagit-core
Manual Update
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-macos.tar.gz \
| sudo tar xz -C /usr/local/bin
Uninstalling
Via Homebrew
brew uninstall mediagit-core
brew untap mediagit/tap
Manual Uninstall
sudo rm /usr/local/bin/mediagit
rm -rf ~/.mediagit
Next Steps
- Quickstart Guide - Get started in 5 minutes
- Configuration - Customize MediaGit
- CLI Reference - Learn all commands
macOS ARM64 (Apple Silicon) Installation
MediaGit-Core is optimized for Apple Silicon (M1, M2, M3, M4) processors with native ARM64 binaries.
Quick Install (Homebrew - Recommended)
brew tap mediagit/tap
brew install mediagit-core
Homebrew automatically installs the ARM64 version on Apple Silicon Macs.
Alternative Installation Methods
Direct Binary Download
# Download latest ARM64 binary
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-macos.tar.gz \
| sudo tar xz -C /usr/local/bin
# Verify native ARM64
file /usr/local/bin/mediagit
# Output should show: Mach-O 64-bit executable arm64
Using Installation Script
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
macOS Gatekeeper Approval
First run requires security approval:
# Remove quarantine attribute
xattr -d com.apple.quarantine /usr/local/bin/mediagit
# Or approve via System Settings
# System Settings → Privacy & Security → Security → "Allow Anyway"
Post-Installation Setup
Shell Completions
Zsh (default on macOS)
mediagit completions zsh > /opt/homebrew/share/zsh/site-functions/_mediagit
# For manual installation
mkdir -p ~/.zfunc
mediagit completions zsh > ~/.zfunc/_mediagit
echo 'fpath=(~/.zfunc $fpath)' >> ~/.zshrc
Bash (if using Homebrew bash)
brew install bash-completion@2
mediagit completions bash > $(brew --prefix)/etc/bash_completion.d/mediagit
Environment Variables
Add to ~/.zshrc:
# Optional: Set default backend
export MEDIAGIT_DEFAULT_BACKEND=local
# Optional: Optimize for Apple Silicon
export MEDIAGIT_USE_SIMD=1
# Optional: Enable debug logging
export MEDIAGIT_LOG=info
Apple Silicon Optimizations
MediaGit-Core leverages Apple Silicon features:
- Native ARM64: Full performance, no Rosetta 2 emulation
- Metal Acceleration: GPU-accelerated image processing (future)
- AMX Instructions: Matrix operations for ML workloads
- Efficiency Cores: Balanced power/performance
Performance Configuration
# ~/.mediagit/config.toml
[performance]
worker_threads = 8 # M1: 8, M2/M3: 8-12, M4: 10-16
chunk_size = "16MB"
cache_size = "2GB" # Leverage unified memory
[compression]
algorithm = "zstd"
level = 3
parallel = true
threads = 4 # Use performance cores
System Requirements
- macOS Version: 11.0 Big Sur or later (12.0+ recommended)
- CPU: Apple M1 or later (M1, M1 Pro, M1 Max, M1 Ultra, M2, M3, M4)
- RAM: 8GB minimum, 16GB+ recommended
- Disk: 100MB for binaries, SSD recommended
- Xcode: Command Line Tools (optional)
Verified Chips
| Chip | Cores | Status |
|---|---|---|
| M1 | 4P+4E | ✅ Tested |
| M1 Pro | 6P+2E, 8P+2E | ✅ Tested |
| M1 Max | 8P+2E | ✅ Tested |
| M1 Ultra | 16P+4E | ✅ Tested |
| M2 | 4P+4E | ✅ Tested |
| M2 Pro | 6P+4E, 8P+4E | ✅ Tested |
| M2 Max | 8P+4E | ✅ Tested |
| M2 Ultra | 16P+8E | ✅ Tested |
| M3 | 4P+4E | ✅ Tested |
| M3 Pro | 6P+6E | ✅ Tested |
| M3 Max | 12P+4E | ✅ Tested |
| M4 | 4P+6E | ✅ Tested |
Verification
# Check version and architecture
mediagit --version
file $(which mediagit)
# Run self-test
mediagit fsck --self-test
# Create test repo
mkdir ~/test-mediagit
cd ~/test-mediagit
mediagit init
Expected output:
mediagit-core 0.2.6-beta.1
/opt/homebrew/bin/mediagit: Mach-O 64-bit executable arm64
✓ All checks passed
✓ Initialized empty MediaGit repository in .mediagit/
Troubleshooting
Running Under Rosetta 2 (Not Recommended)
If you accidentally installed the Intel version:
# Check if running under Rosetta
sysctl sysctl.proc_translated
# If output is 1, you're using Intel binary
# Uninstall and reinstall ARM64 version
brew uninstall mediagit-core
brew cleanup
arch -arm64 brew install mediagit-core
“mediagit” cannot be opened
# Remove quarantine attribute
xattr -d com.apple.quarantine /usr/local/bin/mediagit
# If that doesn't work, allow in System Settings
open "x-apple.systempreferences:com.apple.preference.security"
Command Not Found
# Check Homebrew PATH for Apple Silicon
echo $PATH | grep /opt/homebrew
# If missing, add to ~/.zshrc
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
Permission Issues
# Fix Homebrew permissions
sudo chown -R $(whoami) /opt/homebrew
# Retry installation
brew install mediagit-core
Performance Benchmarks
Apple Silicon performance vs Intel:
| Operation | M1 | M1 Max | M2 | M3 | Intel i9 |
|---|---|---|---|---|---|
| Compression (1GB) | 2.3s | 1.8s | 2.1s | 1.6s | 4.2s |
| Branch Switch | 45ms | 38ms | 42ms | 35ms | 120ms |
| Object Scan (10k) | 0.8s | 0.6s | 0.7s | 0.5s | 1.9s |
Updating
Via Homebrew
brew update
brew upgrade mediagit-core
Manual Update
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-aarch64-macos.tar.gz \
| sudo tar xz -C /usr/local/bin
Uninstalling
Via Homebrew
brew uninstall mediagit-core
brew untap mediagit/tap
rm -rf ~/.mediagit
Manual Uninstall
sudo rm /usr/local/bin/mediagit
sudo rm /opt/homebrew/bin/mediagit
rm -rf ~/.mediagit
Next Steps
- Quickstart Guide - Get started in 5 minutes
- Performance Optimization - Tune for Apple Silicon
- Configuration - Customize MediaGit
- CLI Reference - Learn all commands
Windows x64 Installation
MediaGit-Core provides native Windows binaries for x64 systems (Windows 10/11).
Quick Install (Chocolatey - Recommended)
# Open PowerShell as Administrator
choco install mediagit-core
Alternative Installation Methods
Windows Package Manager (winget)
winget install MediaGit.MediaGitCore
Direct Download
- Download the latest ZIP from GitHub Releases:
mediagit-0.2.6-beta.1-x86_64-windows.zip - Extract the archive
- Move
mediagit.exeandmediagit-server.exeto a directory on your PATH
Manual Binary Installation
# Download ZIP archive
Invoke-WebRequest -Uri "https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-windows.zip" -OutFile "mediagit.zip"
# Extract (contains mediagit.exe + mediagit-server.exe)
$dest = "$env:LOCALAPPDATA\MediaGit\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Expand-Archive -Path mediagit.zip -DestinationPath $dest -Force
# Add to PATH
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($userPath -notlike "*$dest*") {
[Environment]::SetEnvironmentVariable("Path", "$userPath;$dest", "User")
}
# Restart terminal, then verify
mediagit --version
Post-Installation Setup
PowerShell Completions
# Generate completions
mediagit completions powershell > $PROFILE\..\Completions\mediagit.ps1
# Enable completions in profile
Add-Content $PROFILE "`nImport-Module `"$PROFILE\..\Completions\mediagit.ps1`""
Git Bash Completions (if using Git Bash on Windows)
mediagit completions bash > ~/.bash_completion.d/mediagit
Environment Variables
Set via System Properties or PowerShell:
# Optional: Set default backend
[Environment]::SetEnvironmentVariable("MEDIAGIT_DEFAULT_BACKEND", "local", "User")
# Optional: Set storage path
[Environment]::SetEnvironmentVariable("MEDIAGIT_STORAGE_PATH", "$env:USERPROFILE\.mediagit\storage", "User")
# Optional: Enable debug logging
[Environment]::SetEnvironmentVariable("MEDIAGIT_LOG", "info", "User")
System Requirements
- Windows Version: Windows 10 (1809+) or Windows 11
- CPU: x64 processor (Intel, AMD)
- RAM: 1GB minimum, 4GB recommended
- Disk: 100MB for binaries
- Dependencies: Visual C++ Redistributable 2015-2022 (included in installer)
Visual C++ Redistributable
The MSI installer includes required dependencies. For manual installation:
# Download and install VC++ Redistributable
Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vc_redist.x64.exe" -OutFile "vc_redist.x64.exe"
.\vc_redist.x64.exe /install /quiet /norestart
Verification
# Check version
mediagit --version
# Run self-test
mediagit fsck --self-test
# Create test repository
mkdir C:\test-mediagit
cd C:\test-mediagit
mediagit init
Expected output:
mediagit-core 0.2.6-beta.1
✓ All checks passed
✓ Initialized empty MediaGit repository in .mediagit/
Windows-Specific Configuration
Long Path Support (Required for Deep Repositories)
Enable long path support in Windows:
# Run as Administrator
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
Windows Defender Exclusions
For better performance, exclude MediaGit directories:
# Run as Administrator
Add-MpPreference -ExclusionPath "C:\Program Files\MediaGit"
Add-MpPreference -ExclusionPath "$env:USERPROFILE\.mediagit"
File System Configuration
# %USERPROFILE%\.mediagit\config.toml
[filesystem]
case_sensitive = false # Windows is case-insensitive
symlinks_enabled = false # Limited symlink support
line_endings = "crlf" # Windows-style line endings
Troubleshooting
“mediagit is not recognized”
# Check if in PATH
$env:Path -split ';' | Select-String mediagit
# If not found, add to PATH
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
$newPath = "$oldPath;C:\Program Files\MediaGit"
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
# Restart PowerShell
Permission Denied
# Run PowerShell as Administrator
Start-Process powershell -Verb RunAs
# Or adjust execution policy
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Visual C++ Runtime Error
# Install missing runtime
choco install vcredist140
# Or download directly
Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vc_redist.x64.exe" -OutFile "vc_redist.x64.exe"
.\vc_redist.x64.exe /install /quiet /norestart
Slow Performance on Network Drives
# Disable real-time scanning for MediaGit operations
[performance]
disable_indexing = true
bypass_cache_manager = true
Chocolatey Not Found
# Install Chocolatey first
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
Integration with Windows Tools
Windows Terminal
Add MediaGit-specific profile:
// settings.json
{
"profiles": {
"list": [
{
"name": "MediaGit",
"commandline": "powershell.exe -NoExit -Command \"cd $env:USERPROFILE\\repos\"",
"icon": "C:\\Program Files\\MediaGit\\icon.ico"
}
]
}
}
VS Code Integration
Install the MediaGit extension:
code --install-extension mediagit.mediagit-vscode
File Explorer Context Menu
Right-click integration (requires registry edit):
# Run as Administrator
$regPath = "HKCU:\Software\Classes\Directory\shell\MediaGit"
New-Item -Path $regPath -Force
New-ItemProperty -Path $regPath -Name "(Default)" -Value "Open MediaGit Here" -Force
New-ItemProperty -Path $regPath -Name "Icon" -Value "C:\Program Files\MediaGit\mediagit.exe" -Force
$commandPath = "$regPath\command"
New-Item -Path $commandPath -Force
New-ItemProperty -Path $commandPath -Name "(Default)" -Value "wt.exe -d `"%V`" powershell.exe -NoExit -Command mediagit status" -Force
Updating
Via Chocolatey
choco upgrade mediagit-core
Via winget
winget upgrade MediaGit.MediaGitCore
Manual Update
- Download latest ZIP from GitHub Releases
- Extract and replace the binaries in your install directory
Uninstalling
Via Chocolatey
choco uninstall mediagit-core
Via Windows Settings
- Open Settings → Apps → Installed apps
- Find “MediaGit-Core”
- Click “Uninstall”
Manual Uninstall
# Remove program files
Remove-Item "C:\Program Files\MediaGit" -Recurse -Force
# Remove user data
Remove-Item "$env:USERPROFILE\.mediagit" -Recurse -Force
# Remove from PATH
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
$newPath = ($oldPath -split ';' | Where-Object { $_ -notlike '*MediaGit*' }) -join ';'
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
WSL2 Integration
Use Windows MediaGit from WSL2:
# Add Windows PATH to WSL
echo 'export PATH="$PATH:/mnt/c/Program Files/MediaGit"' >> ~/.bashrc
source ~/.bashrc
# Create alias
echo 'alias mediagit="/mnt/c/Program\ Files/MediaGit/mediagit.exe"' >> ~/.bashrc
Next Steps
- Quickstart Guide - Get started in 5 minutes
- Configuration - Customize MediaGit
- CLI Reference - Learn all commands
- Windows-Specific Tips - Platform-specific guidance
Windows ARM64 Installation
Status: Windows ARM64 pre-built binaries are not currently included in official releases. The
cross-rstool used for cross-compilation does not support Windows targets. Windows ARM64 users must build from source.
Build from Source
Building from source on a Windows ARM64 machine (Surface Pro X, Snapdragon-based Copilot+ PCs):
Prerequisites
-
Install Rust — download from rustup.rs
winget install Rustlang.Rustup -
Install Visual Studio Build Tools (required for MSVC linker):
winget install Microsoft.VisualStudio.2022.BuildTools # Select "Desktop development with C++" -
Add the ARM64 Rust target:
rustup target add aarch64-pc-windows-msvc
Build
git clone https://github.com/winnyboy5/mediagit-core.git
cd mediagit-core
# Build for native ARM64
cargo build --release --target aarch64-pc-windows-msvc --bin mediagit --bin mediagit-server
Install
# Copy to a directory on your PATH
$dest = "$env:USERPROFILE\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Copy-Item "target\aarch64-pc-windows-msvc\release\mediagit.exe" -Destination $dest
Copy-Item "target\aarch64-pc-windows-msvc\release\mediagit-server.exe" -Destination $dest
# Add to PATH (if not already done)
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($userPath -notlike "*$dest*") {
[Environment]::SetEnvironmentVariable("Path", "$userPath;$dest", "User")
Write-Host "Added $dest to PATH. Restart your terminal."
}
Verify
mediagit --version
Alternative: x64 Binary on ARM64 Windows
Windows ARM64 supports running x64 binaries via emulation. You can download the standard
mediagit-0.2.6-beta.1-x86_64-windows.zip from the Releases page
and run it directly. Performance will be lower than native, but it is fully functional.
Tracking Issue
Follow GitHub Issues for native Windows ARM64 release support. Once a native ARM64 Windows GitHub Actions runner becomes available (or an alternative cross-compilation strategy is adopted), pre-built binaries will be added to official releases.
Building from Source
Build MediaGit from source when:
- A pre-built binary is not available for your platform (e.g., Windows ARM64)
- You want to build with custom feature flags
- You are contributing to MediaGit development
- You need to cross-compile for a different target
Prerequisites
All platforms
- Rust 1.92.0 or later — install via rustup.rs
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup update - Git — to clone the repository
Linux
A C linker is needed (usually already installed):
# Debian/Ubuntu
sudo apt install build-essential
# Fedora/RHEL
sudo dnf install gcc
macOS
Install Xcode Command Line Tools:
xcode-select --install
Windows
Install Visual Studio Build Tools with the “Desktop development with C++” workload:
winget install Microsoft.VisualStudio.2022.BuildTools
Or install the full Visual Studio 2022.
Build
# Clone the repository
git clone https://github.com/winnyboy5/mediagit-core.git
cd mediagit-core
# Build release binaries
cargo build --release --bin mediagit --bin mediagit-server
Binaries are written to target/release/:
target/release/mediagit(Linux/macOS)target/release/mediagit.exe(Windows)target/release/mediagit-server/mediagit-server.exe
Build time: 3–8 minutes on first build; incremental rebuilds are much faster.
Install
Linux / macOS
# Install to ~/.cargo/bin (already on PATH if you used rustup)
cargo install --path crates/mediagit-cli --locked
cargo install --path crates/mediagit-server --locked
# Or copy manually
sudo cp target/release/mediagit /usr/local/bin/
sudo cp target/release/mediagit-server /usr/local/bin/
Windows
# Copy to a directory on your PATH
$dest = "$env:USERPROFILE\bin"
New-Item -ItemType Directory -Force -Path $dest | Out-Null
Copy-Item "target\release\mediagit.exe" -Destination $dest
Copy-Item "target\release\mediagit-server.exe" -Destination $dest
# Add to PATH if not already present
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($userPath -notlike "*$dest*") {
[Environment]::SetEnvironmentVariable("Path", "$userPath;$dest", "User")
Write-Host "Added $dest to PATH. Restart your terminal."
}
Verify
mediagit --version
mediagit-server --version
Cross-Compilation
Linux ARM64 (from Linux x64)
Install cross:
cargo install cross --git https://github.com/cross-rs/cross
Build:
cross build --release --target aarch64-unknown-linux-gnu \
--bin mediagit --bin mediagit-server
macOS Apple Silicon (from macOS Intel)
rustup target add aarch64-apple-darwin
cargo build --release --target aarch64-apple-darwin \
--bin mediagit --bin mediagit-server
macOS Intel (from macOS Apple Silicon)
rustup target add x86_64-apple-darwin
cargo build --release --target x86_64-apple-darwin \
--bin mediagit --bin mediagit-server
Windows x64 (from Linux)
Note:
cross-rsdoes not support Windows targets. To build for Windows, use a Windows machine or a Windows GitHub Actions runner.
On Windows:
rustup target add x86_64-pc-windows-msvc
cargo build --release --target x86_64-pc-windows-msvc \
--bin mediagit --bin mediagit-server
Windows ARM64
See Windows ARM64 Installation.
Checking MSRV
MediaGit’s Minimum Supported Rust Version (MSRV) is 1.92.0. Verify compatibility:
cargo +1.92.0 check --workspace --all-features
Running Tests
# Unit and integration tests (no external services)
cargo test --workspace
# Skip slow tests
cargo test --workspace -- --skip integration
# With all features
cargo test --workspace --all-features
Integration tests that require Docker (MinIO, Azurite, fake-gcs-server):
docker compose -f docker-compose.test.yml up -d
AWS_ACCESS_KEY_ID=minioadmin \
AWS_SECRET_ACCESS_KEY=minioadmin \
AWS_ENDPOINT_URL=http://localhost:9000 \
AWS_REGION=us-east-1 \
AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;" \
GCS_EMULATOR_HOST=http://localhost:4443 \
cargo test --ignored -p mediagit-storage -p mediagit-server
docker compose -f docker-compose.test.yml down -v
WSL2 Notes
Building on a Windows NTFS filesystem (e.g., /mnt/d/...) from WSL2 can cause Cargo’s incremental build fingerprinting to miss source changes. For reliable builds during development, use a WSL2-native path:
# Clone to WSL2 filesystem
git clone ... ~/projects/mediagit-core
cd ~/projects/mediagit-core
cargo build --release
The resulting Linux ELF binary can then be tested in WSL2. To build the Windows PE binary, run cargo build --release from a Windows terminal (cmd, PowerShell, or Windows Terminal).
See Also
Quickstart Guide
Get up and running with MediaGit in 5 minutes!
Prerequisites
- Rust 1.92.0 or later (if building from source)
- Git (for installing from source or contributing)
Installation
Quick Install (Recommended)
# Linux/macOS — one-liner install
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh
# Windows (PowerShell)
Invoke-WebRequest -Uri "https://github.com/winnyboy5/mediagit-core/releases/download/v0.2.6-beta.1/mediagit-0.2.6-beta.1-x86_64-windows.zip" -OutFile mediagit.zip
Expand-Archive mediagit.zip -DestinationPath "$env:LOCALAPPDATA\MediaGit\bin"
Docker
docker pull ghcr.io/winnyboy5/mediagit-core:0.2.6-beta.1
docker run --rm ghcr.io/winnyboy5/mediagit-core:0.2.6-beta.1 mediagit --version
From Pre-built Binaries
Download the latest release for your platform from GitHub Releases:
| Platform | Archive |
|---|---|
| Linux x86_64 | mediagit-0.2.6-beta.1-x86_64-linux.tar.gz |
| Linux ARM64 | mediagit-0.2.6-beta.1-aarch64-linux.tar.gz |
| macOS Intel | mediagit-0.2.6-beta.1-x86_64-macos.tar.gz |
| macOS Apple Silicon | mediagit-0.2.6-beta.1-aarch64-macos.tar.gz |
| Windows x86_64 | mediagit-0.2.6-beta.1-x86_64-windows.zip |
From Source
git clone https://github.com/winnyboy5/mediagit-core.git
cd mediagit-core
cargo build --release
Your First Repository
1. Initialize a Repository
mkdir my-media-project
cd my-media-project
mediagit init
Output:
✓ Initialized empty MediaGit repository in .mediagit/
2. Add Files
# Add a single file
mediagit add my-video.mp4
# Add multiple files
mediagit add images/*.jpg videos/*.mp4
# Add entire directory
mediagit add assets/
3. Check Status
mediagit status
Output:
On branch main
Changes to be committed:
new file: my-video.mp4
new file: images/photo1.jpg
new file: images/photo2.jpg
4. Commit Changes
mediagit commit -m "Initial commit: Add project media files"
Output:
[main abc1234] Initial commit: Add project media files
3 files changed
Compression ratio: 15.2% (saved 42.3 MB)
Deduplication: 2 identical chunks found
5. View History
mediagit log
Output:
commit abc1234def5678
Author: Your Name <you@example.com>
Date: Mon Nov 24 2025 12:00:00
Initial commit: Add project media files
Files: 3
Size: 42.3 MB → 6.4 MB (84.8% savings)
Working with Branches
Create a Feature Branch
mediagit branch create feature/new-assets
mediagit branch switch feature/new-assets
Make Changes
# Add new files
mediagit add new-video.mp4
mediagit commit -m "Add new promotional video"
Merge Back to Main
mediagit branch switch main
mediagit merge feature/new-assets
Storage Backend Configuration
MediaGit supports multiple storage backends. By default, it uses local filesystem storage.
Configure AWS S3 Backend
# Edit .mediagit/config.toml
mediagit config set storage.backend s3
mediagit config set storage.s3.bucket my-media-bucket
mediagit config set storage.s3.region us-west-2
Configure Azure Blob Storage
mediagit config set storage.backend azure
mediagit config set storage.azure.account my-storage-account
mediagit config set storage.azure.container media-container
See Storage Backend Configuration for detailed setup instructions.
Media-Aware Features
Automatic Conflict Resolution for Images
When merging branches with image edits:
mediagit merge feature/photo-edits
MediaGit automatically detects:
- ✅ Non-overlapping edits (auto-merge)
- ✅ Metadata-only changes (auto-merge)
- ⚠️ Overlapping pixel edits (manual resolution required)
PSD Layer Merging
MediaGit understands PSD layer structure:
mediagit merge feature/design-updates
- ✅ Different layer edits → Auto-merge
- ✅ New layers added → Auto-merge
- ⚠️ Same layer modified → Conflict marker
Video Timeline Merging
MediaGit can merge non-overlapping video edits:
mediagit merge feature/video-cuts
- ✅ Different timeline ranges → Auto-merge
- ✅ Different audio tracks → Auto-merge
- ⚠️ Overlapping timeline edits → Manual resolution
Performance Tips
Enable Compression
Compression is enabled by default. Adjust levels in .mediagit/config.toml:
[compression]
algorithm = "zstd" # or "brotli"
level = 3 # zstd: 1 (fastest) – 22 (best); brotli: 0–11
Delta Encoding
For incremental changes to large files:
[delta]
enabled = true
similarity_threshold = 0.80 # 80% similar = use delta
max_chain_depth = 10
Deduplication
MediaGit automatically deduplicates identical content:
# Check deduplication statistics
mediagit stats
# Output:
# Total objects: 1,234
# Unique objects: 856 (69.4%)
# Deduplicated: 378 (30.6%)
# Space saved: 1.2 GB
Next Steps
- 📚 Basic Workflow Guide - Learn common workflows
- 🌿 Branching Strategies - Effective branch management
- 🎨 Merging Media Files - Advanced media-aware merging
- 🚀 Performance Optimization - Optimize for large files
- 📖 CLI Reference - Complete command documentation
Getting Help
- 📖 Documentation
- 💬 Discord Community
- 🐛 Issue Tracker
- 📧 Email: support@mediagit.dev
Common Issues
Permission Denied on Install
# Linux/macOS: Use sudo
sudo sh -c 'curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh'
# Or install to user directory
curl -fsSL https://raw.githubusercontent.com/winnyboy5/mediagit-core/main/install.sh | sh -s -- --no-sudo
Command Not Found After Install
Add MediaGit to your PATH:
# Linux/macOS (bash)
echo 'export PATH="$HOME/.mediagit/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# macOS (zsh)
echo 'export PATH="$HOME/.mediagit/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Windows
# Add %USERPROFILE%\.mediagit\bin to System PATH
Large File Upload Timeout
Increase timeout in configuration:
[storage]
timeout_seconds = 300 # 5 minutes
For more troubleshooting, see the Troubleshooting Guide.
Configuration
MediaGit configuration reference.
Repository Configuration
Located in .mediagit/config:
[storage]
backend = "filesystem"
base_path = "./data"
[compression]
algorithm = "zstd"
level = 3
[author]
name = "Your Name"
email = "your.email@example.com"
See Configuration Reference for all options.
CLI Reference
MediaGit command-line interface reference documentation.
Command Categories
Core Commands
Essential commands for daily workflows:
- init - Initialize repository
- add - Stage files
- commit - Create commits
- status - Show working tree status
- log - Show commit history
- diff - Show differences
- show - Show object details
Branch Management
Working with branches:
- branch - Create, list, delete branches
- merge - Merge branches
- rebase - Rebase branches
- cherry-pick - Apply commits from another branch
- bisect - Binary search through commit history
- stash - Stash uncommitted changes
- reset - Reset current branch to a commit
- revert - Revert a commit by creating an inverse commit
- tag - Create and manage tags
Remote Operations
Collaborating with remotes:
- clone - Clone a remote repository
- remote - Manage remote repositories
- fetch - Fetch from remote without merging
- push - Push changes to remote
- pull - Fetch and merge from remote
History and Diagnostics
Inspecting repository state:
- reflog - Show reference log (history of HEAD and branch movements)
Maintenance
Repository maintenance:
- gc - Garbage collection
- fsck - File system check
- verify - Verify object integrity
- stats - Repository statistics
Global Options
Available for all commands:
-C <path>- Run as if started in this directory--help- Show command help--version- Show MediaGit version--verbose,-v- Verbose output--quiet,-q- Suppress output--color <when>- Colorize output (auto/always/never)
Environment Variables
MEDIAGIT_REPO- Repository root path (set automatically by-C)MEDIAGIT_AUTHOR_NAME- Author name overrideMEDIAGIT_AUTHOR_EMAIL- Author email override
See Environment Variables for complete list.
Core Commands
Essential commands for daily MediaGit workflows.
Commands
- init - Initialize a new repository
- add - Stage files for commit
- commit - Create a commit from staged changes
- status - Show working tree status
- log - Show commit history
- diff - Show differences between versions
- show - Show object details (commits, blobs, trees)
Typical Workflow
# Initialize repository
mediagit init
# Stage files
mediagit add large-file.psd
# Create commit
mediagit commit -m "Add initial PSD file"
# Check status
mediagit status
# View history
mediagit log
mediagit init
Initialize a new MediaGit repository in the current directory.
Synopsis
mediagit init [OPTIONS] [PATH]
Description
Creates a new MediaGit repository by setting up the .mediagit directory structure with configuration files, object database, and references. This command prepares a directory for version control of media files.
If PATH is not specified, initializes the repository in the current directory.
Options
--storage-backend <BACKEND>
Storage backend to use for the object database.
- Values:
local,s3,azure,gcs,minio,b2,spaces - Default:
local
--compression <ALGORITHM>
Compression algorithm for storing objects.
- Values:
zstd,brotli,none - Default:
zstd
--compression-level <LEVEL>
Compression level to use.
- Values:
fast,default,best - Default:
default
-b, --initial-branch <BRANCH>
Name of the initial branch.
- Default:
main
--bare
Create a bare repository without a working directory.
Examples
Initialize in current directory
$ mediagit init
✓ Initialized empty MediaGit repository in .mediagit/
Initialize with specific path
$ mediagit init my-media-project
✓ Initialized empty MediaGit repository in my-media-project/.mediagit/
Initialize with S3 backend
$ mediagit init --storage-backend s3
✓ Initialized empty MediaGit repository in .mediagit/
✓ Configured AWS S3 storage backend
Initialize with custom initial branch
$ mediagit init --initial-branch develop
✓ Initialized empty MediaGit repository in .mediagit/
✓ Created initial branch: develop
Initialize bare repository
$ mediagit init --bare repo.git
✓ Initialized bare MediaGit repository in repo.git/
Repository Structure
After initialization, the .mediagit directory contains:
.mediagit/
├── config.toml # Repository configuration
├── HEAD # Current branch reference
├── objects/ # Object database
├── refs/
│ ├── heads/ # Branch references
│ └── tags/ # Tag references
└── index # Staging area
Configuration File
The generated config.toml contains the full default configuration. Key sections:
[app]
name = "mediagit"
version = "0.2.1" # matches current binary version
environment = "development"
port = 8080
[storage]
backend = "filesystem"
base_path = "/absolute/path/to/repo/.mediagit/objects"
create_dirs = true
sync = false
file_permissions = "0644"
# [compression] values below are informational — SmartCompressor selects
# algorithm and level automatically per file type and ignores these settings.
[compression]
enabled = true
algorithm = "zstd"
level = 3
min_size = 1024
[author]
# Set with: mediagit config author.name "Your Name"
# mediagit config author.email "you@example.com"
# Or via env: MEDIAGIT_AUTHOR_NAME, MEDIAGIT_AUTHOR_EMAIL
[remotes]
# Added by: mediagit remote add origin http://server/repo
All backend fields are at the same level as backend in [storage] (no nested [storage.filesystem] subsection).
The [compression] section is written for reference but is not read at runtime. MediaGit’s SmartCompressor automatically chooses the optimal algorithm and level based on file type (e.g., Zstd Best for PSD/3D models, Store for already-compressed formats like JPEG/MP4).
Exit Status
- 0: Successful initialization
- 1: Directory already contains a repository
- 2: Invalid options or configuration
See Also
- mediagit add - Add files to the staging area
- mediagit commit - Record changes to the repository
- mediagit config - Get and set repository options
mediagit add
Add file contents to the staging area for the next commit.
Synopsis
mediagit add [OPTIONS] <PATH>...
Description
Adds the current content of specified files to the staging area (index), preparing them for inclusion in the next commit. MediaGit automatically handles:
- Content deduplication: Identical content stored only once
- Delta compression: Efficient storage of file modifications
- Chunking: Large files split for optimal storage
- Hash computation: SHA-256 content addressing
Arguments
<PATH>...
Files or directories to add. Can be:
- Individual files:
video.mp4,image.png - Directories:
assets/,media/videos/ - Glob patterns:
*.jpg,videos/*.mp4
Options
-A, --all
Add all modified and new files in the working directory.
-u, --update
Add only modified files that are already tracked (ignore new files).
-n, --dry-run
Show what would be added without actually adding files.
-v, --verbose
Show detailed information about added files.
-f, --force
Add files even if they match .mediagitignore patterns.
--no-chunking
Disable automatic chunking for large files.
--no-delta
Disable delta compression (delta encoding is enabled by default).
--no-parallel
Process files sequentially (default is parallel using all CPU cores).
-j, --jobs <N>
Number of parallel worker threads (default: CPU count, max 8).
Examples
Add single file
$ mediagit add video.mp4
✓ Added video.mp4 (150.2 MB → 22.5 MB after compression)
Add multiple files
$ mediagit add image1.jpg image2.jpg video.mp4
✓ Added 3 files
image1.jpg: 2.5 MB → 1.8 MB
image2.jpg: 3.1 MB → 2.2 MB
video.mp4: 150.2 MB → 22.5 MB
Total: 155.8 MB → 26.5 MB (83% savings)
Add entire directory
$ mediagit add assets/
✓ Added 24 files from assets/
Compression: 840.5 MB → 156.2 MB (81.4% savings)
Deduplication: 3 files already exist
Add with glob pattern
$ mediagit add "*.psd"
✓ Added 5 PSD files
total_design.psd: 450.2 MB → 89.1 MB
header_mockup.psd: 120.5 MB → 28.3 MB
...
Add all files
$ mediagit add --all
✓ Added 42 files, removed 3 deleted files
New files: 35
Modified files: 7
Deleted files: 3
Total size: 2.1 GB → 384.2 MB (81.7% savings)
Dry run
$ mediagit add --dry-run *.mp4
Would add:
video1.mp4 (150.2 MB)
video2.mp4 (200.5 MB)
video3.mp4 (180.3 MB)
Total: 531.0 MB (estimated: 95.6 MB after compression)
Verbose output
$ mediagit add -v large_video.mp4
Processing large_video.mp4...
Size: 1.2 GB
Chunks: 307 (4 MB each)
Compression: zstd level 3
Deduplication: 12 chunks already exist
Delta encoding: Not applicable (new file)
✓ Added large_video.mp4: 1.2 GB → 180.5 MB (84.9% savings)
New unique chunks: 295
Deduplicated chunks: 12
Time: 8.3s
Deduplication
MediaGit automatically deduplicates content:
$ mediagit add copy1.jpg
✓ Added copy1.jpg (5.2 MB → 3.8 MB)
$ mediagit add copy2.jpg
✓ Added copy2.jpg (5.2 MB → 0 bytes)
ℹ File content identical to copy1.jpg (deduplicated)
Large File Handling
For files >100 MB, MediaGit provides progress indicators:
$ mediagit add huge_video.mov
Adding huge_video.mov...
[████████████████████] 100% | 4.2 GB / 4.2 GB | 45s
Chunks processed: 1075/1075
Compression: 4.2 GB → 620.3 MB (85.2% savings)
✓ Added huge_video.mov
Staging Area Status
View staged changes with mediagit status:
$ mediagit add video.mp4 image.jpg
$ mediagit status
On branch main
Changes to be committed:
(use "mediagit restore --staged <file>..." to unstage)
new file: video.mp4
new file: image.jpg
Exit Status
- 0: All files added successfully
- 1: One or more files could not be added
- 2: Invalid options or arguments
Notes
Performance Tips
- Batch operations: Add multiple files in one command for better performance
- Parallel processing: MediaGit automatically uses multiple cores
- Network optimization: For remote backends, files are chunked and uploaded in parallel
Storage Optimization
MediaGit optimizes storage through:
- Content-addressable storage: Identical content stored once
- Compression: Zstd or Brotli compression
- Delta encoding: Store differences for similar files
- Chunking: Efficient handling of large files
.mediagitignore
Create a .mediagitignore file in the repository root to prevent certain files from ever being staged. Uses the same glob syntax as .gitignore:
# .mediagitignore
# Ignore temporary files
*.tmp
*.bak
*.swp
# Ignore build output directories
build/
dist/
__pycache__/
# Ignore OS artifacts
.DS_Store
Thumbs.db
# Negation: un-ignore a specific file matching a broader pattern
!important.tmp
Ignoring files example
$ cat .mediagitignore
*.tmp
build/
$ mediagit add --all
✓ Staged 5 file(s)
# file.tmp and build/ contents silently skipped
$ mediagit add --all --verbose
✓ Staged 5 file(s)
ignored (.mediagitignore): file.tmp
ignored (.mediagitignore): build/output.bin
Force-adding an ignored file
$ mediagit add important.tmp
Warning: 'important.tmp' is ignored by .mediagitignore — use --force to override
$ mediagit add --force important.tmp
✓ Staged 1 file(s)
See Also
- mediagit status - Show the working tree status
- mediagit commit - Record changes to the repository
- mediagit restore - Restore working tree files
- mediagit diff - Show changes between commits
mediagit commit
Record changes to the repository.
Synopsis
mediagit commit [OPTIONS]
Description
Creates a new commit containing the current contents of the staging area along with a log message describing the changes. The commit becomes the new tip of the current branch.
MediaGit commits include:
- SHA-256 hash of the commit tree
- Parent commit references
- Author and committer information
- Timestamp
- Commit message
- Compression and deduplication statistics
Options
-m, --message <MESSAGE>
Required (unless --amend or --file is used). Commit message describing the changes.
-F, --file <FILE>
Read commit message from file instead of command line.
--amend
Replace the tip of the current branch by creating a new commit with the previous commit’s contents plus staged changes.
-a, --all
Automatically stage all modified tracked files before committing.
--allow-empty
Allow creating a commit with no changes.
-v, --verbose
Show diff of changes being committed.
--author <AUTHOR>
Override the commit author.
- Format:
"Name <email@example.com>"
--date <DATE>
Override the author date.
- Format: ISO 8601 or Unix timestamp
Examples
Basic commit
$ mediagit commit -m "Add promotional video assets"
[main a3c8f9d] Add promotional video assets
5 files changed
Compression ratio: 18.5% (saved 410.2 MB)
Deduplication: 0 identical chunks
Time: 2.3s
Commit with detailed message
$ mediagit commit -m "Update brand identity assets
- Updated logo files with new color scheme
- Added high-res versions for print media
- Removed deprecated logo variants"
[main b4d7e1a] Update brand identity assets
12 files changed (8 added, 3 modified, 1 deleted)
Compression: 156.8 MB → 28.4 MB (81.9% savings)
Commit all changes
$ mediagit commit -am "Quick fix: correct video resolution"
✓ Auto-staged 3 modified files
[main c5e9f2b] Quick fix: correct video resolution
3 files changed
Compression: 450.3 MB → 68.2 MB (84.8% savings)
Amend last commit
$ mediagit commit --amend -m "Add promotional video assets (final version)"
[main d6f0a3c] Add promotional video assets (final version)
5 files changed
ℹ Amended previous commit
Commit with verbose output
$ mediagit commit -v -m "Add product photography"
Changes to be committed:
new file: product_shot_001.jpg
new file: product_shot_002.jpg
new file: product_shot_003.jpg
modified: catalog.json
[main e7g1b4d] Add product photography
4 files changed (3 added, 1 modified)
Compression: 45.6 MB → 12.3 MB (73.0% savings)
Deduplication: 0 chunks
Delta encoding: catalog.json (95% size reduction)
Commit from file
$ cat commit-message.txt
Major redesign of homepage assets
This commit includes:
- New hero images optimized for retina displays
- Updated video backgrounds with improved compression
- Refreshed icon set with SVG versions
$ mediagit commit -F commit-message.txt
[main f8h2c5e] Major redesign of homepage assets
28 files changed
Compression: 820.4 MB → 142.7 MB (82.6% savings)
Override author
$ mediagit commit -m "Apply design changes" --author "Designer <designer@company.com>"
[main g9i3d6f] Apply design changes
Author: Designer <designer@company.com>
7 files changed
Commit Statistics
Each commit displays optimization metrics:
$ mediagit commit -m "Add training video series"
[main h0j4e7g] Add training video series
12 files changed
Original size: 3.2 GB
Stored size: 485.3 MB (84.8% savings)
Breakdown:
Compression: 3.2 GB → 890.2 MB (72.2% savings)
Deduplication: 15 chunks (105.8 MB saved)
Delta encoding: 2 files (299.1 MB saved)
Storage:
New unique objects: 3,847
Reused objects: 142
Total objects in ODB: 8,293
Empty Commits
Empty commits require explicit flag:
$ mediagit commit -m "Trigger CI rebuild"
error: no changes added to commit
$ mediagit commit -m "Trigger CI rebuild" --allow-empty
[main i1k5f8h] Trigger CI rebuild
0 files changed
Commit Tree
View commit history with mediagit log:
$ mediagit log --oneline -5
i1k5f8h (HEAD -> main) Trigger CI rebuild
h0j4e7g Add training video series
g9i3d6f Apply design changes
f8h2c5e Major redesign of homepage assets
e7g1b4d Add product photography
Commit Message Guidelines
Format
Short summary (50 chars or less)
More detailed explanation if needed. Wrap at 72 characters.
Explain the problem this commit solves and why you made
the changes.
- Bullet points are fine
- Use present tense: "Add feature" not "Added feature"
- Reference issues: Fixes #123
Example
$ mediagit commit -m "Optimize video encoding for mobile devices
Reduced bitrate for mobile-targeted videos to improve
load times on slower connections. Videos maintain quality
on small screens while reducing file size by 40%.
Affected files:
- All videos in mobile/campaigns/ directory
- Thumbnail generation updated
Closes #456"
Exit Status
- 0: Commit created successfully
- 1: Nothing to commit (no staged changes)
- 2: Invalid options or commit message
Notes
Best Practices
- Atomic commits: Each commit should represent one logical change
- Descriptive messages: Explain why changes were made, not just what changed
- Test before committing: Ensure files work as expected
- Review staged changes: Use
mediagit statusandmediagit diff --staged
Performance
MediaGit optimizes commit operations:
- Parallel processing: Multiple files processed concurrently
- Incremental hashing: Only new content is hashed
- Smart caching: Reuse computations where possible
- Background cleanup: Object database optimization happens asynchronously
See Also
- mediagit add - Add files to the staging area
- mediagit status - Show the working tree status
- mediagit log - Show commit history
- mediagit diff - Show changes between commits
- mediagit show - Show commit details
mediagit status
Display the working tree status.
Synopsis
mediagit status [OPTIONS]
Description
Shows the status of the working tree, displaying:
- Files staged for commit (in the index)
- Files with modifications not staged
- Untracked files not yet added
- Ignored files (when
--ignoredis set) - Current branch information
MediaGit status provides enhanced insights compared to traditional version control:
- Real-time compression savings preview
- Deduplication opportunities for staged files
- Storage backend health indicators
- Media-specific file analysis
Options
-s, --short
Show output in short format, one file per line with status codes.
-b, --branch
Show branch information even in short format.
-v, --verbose
Show detailed information including:
- File sizes and compression ratios
- Deduplication statistics
- Storage backend status
- Object database metrics
--porcelain[=<version>]
Machine-readable output format. Version can be 1 or 2.
--long
Show output in long format (default).
--show-stash
Show number of entries currently stashed.
-u, --untracked-files[=<mode>]
Show untracked files:
- no: Show no untracked files
- normal: Show untracked files and directories (default)
- all: Show individual files in untracked directories
--ignored
Show files excluded by .mediagitignore in an “Ignored files:” section.
Ignored files are always hidden from the “Untracked files:” list; this flag makes them visible.
Status Indicators
Short Format Codes
M modified in working tree
M staged for commit
MM staged with additional modifications
A new file staged
AM staged new file with modifications
D deleted in working tree
?? untracked file
!! ignored file
Long Format Sections
Changes to be committed:
(staged files ready for commit)
Changes not staged for commit:
(modified files not yet staged)
Untracked files:
(files not tracked by MediaGit)
Examples
Basic status
$ mediagit status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "mediagit restore --staged <file>..." to unstage)
new file: project_video.mp4
modified: README.md
Changes not staged for commit:
(use "mediagit add <file>..." to update what will be committed)
(use "mediagit restore <file>..." to discard changes)
modified: config.json
Untracked files:
(use "mediagit add <file>..." to include in commit)
draft_design.psd
temp_render.mov
Storage preview for staged files:
Original size: 250.3 MB
After compression: 42.1 MB (83.2% savings)
Deduplication opportunities: 5 chunks (8.2 MB additional savings)
Short format
$ mediagit status --short
M README.md
A project_video.mp4
M config.json
?? draft_design.psd
?? temp_render.mov
Short format with branch
$ mediagit status --short --branch
## main...origin/main [ahead 2]
M README.md
A project_video.mp4
M config.json
?? draft_design.psd
Verbose status
$ mediagit status --verbose
On branch main
Your branch is ahead of 'origin/main' by 2 commits.
(use "mediagit push" to publish your local commits)
Changes to be committed:
(use "mediagit restore --staged <file>..." to unstage)
new file: project_video.mp4
Size: 245.8 MB → 38.5 MB (compressed, 84.3% savings)
Chunks: 63 (4 MB each)
Deduplication: 3 chunks already exist (11.8 MB saved)
modified: README.md
Size: 4.5 KB → 1.2 KB (delta encoded, 73.3% savings)
Previous version: e4f3a2b
Changes: +28 lines, -15 lines
Changes not staged for commit:
modified: config.json
Size: 2.1 KB (not yet staged)
Changes: +5 lines, -2 lines
Untracked files:
draft_design.psd (89.2 MB)
temp_render.mov (156.7 MB)
Object Database Status:
Total objects: 2,847
Total size: 1.2 GB → 185.3 MB (stored)
Compression ratio: 84.5%
Deduplication savings: 127.8 MB
Cache hit rate: 92.3%
Storage Backend: AWS S3 (us-west-2)
Status: Healthy ✓
Bucket: mediagit-prod-assets
Last sync: 2 minutes ago
Show ignored files
$ cat .mediagitignore
*.tmp
build/
$ mediagit status --ignored
Repository Status
Untracked files:
(use "mediagit add <file>..." to include in what will be committed)
new_asset.mp4
Ignored files:
(add .mediagitignore negation '!<pattern>' to un-ignore)
cache.tmp
render.tmp
Porcelain output with ignored
$ mediagit status --porcelain --ignored
?? new_asset.mp4
!! cache.tmp
!! render.tmp
Machine-readable output
$ mediagit status --porcelain
M README.md
A project_video.mp4
M config.json
?? draft_design.psd
?? temp_render.mov
After staging all changes
$ mediagit add --all
$ mediagit status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
Changes to be committed:
(use "mediagit restore --staged <file>..." to unstage)
new file: draft_design.psd
new file: project_video.mp4
new file: temp_render.mov
modified: README.md
modified: config.json
Commit preview:
5 files changed (3 added, 2 modified)
Original size: 495.3 MB
Compressed size: 78.6 MB (84.1% savings)
Ready to commit ✓
Working Tree Status
Clean working tree
$ mediagit status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
Detached HEAD
$ mediagit status
HEAD detached at a3c8f9d
nothing to commit, working tree clean
Merge conflict
$ mediagit status
On branch feature-video
You have unmerged paths.
(fix conflicts and run "mediagit commit")
(use "mediagit merge --abort" to abort the merge)
Unmerged paths:
(use "mediagit add <file>..." to mark resolution)
both modified: project_settings.json
Automatic merge strategy: Latest Modified Time
Conflicting files: 1
- project_settings.json: local modified 2024-01-15, remote modified 2024-01-14
- Resolution: Keep local version (newer)
Branch Tracking
Ahead of remote
$ mediagit status
On branch main
Your branch is ahead of 'origin/main' by 3 commits.
(use "mediagit push" to publish your local commits)
Behind remote
$ mediagit status
On branch main
Your branch is behind 'origin/main' by 5 commits.
(use "mediagit pull" to update your local branch)
Diverged branches
$ mediagit status
On branch main
Your branch and 'origin/main' have diverged,
and have 2 and 3 different commits each, respectively.
(use "mediagit pull" to merge the remote branch)
Storage Insights
MediaGit status provides storage optimization insights:
$ mediagit status --verbose
...
Storage Optimization Opportunities:
✓ 3 files can benefit from delta encoding: 45.2 MB → 12.1 MB
✓ 2 files have duplicate chunks: 23.8 MB deduplication potential
✓ 1 file can use better compression: 18.3 MB → 5.2 MB
Run "mediagit add --optimize" to apply optimizations
Performance
MediaGit status is optimized for large repositories:
- Incremental checks: Only scan files with changed mtimes
- Parallel scanning: Multi-threaded file status checking
- Cache utilization: Reuse hash computations from previous operations
- Smart sampling: For very large files, sample-based change detection
Typical performance:
- Small repos (<1000 files): <100ms
- Medium repos (<10000 files): <500ms
- Large repos (>10000 files): <2s
Exit Status
- 0: Working tree is clean, or changes displayed successfully
- 1: Error accessing working tree or repository
- 2: Invalid options or configuration error
Configuration
Status display can be customized:
[status]
# Show short format by default
short = false
# Always show branch information
show_branch = true
# Show untracked files
show_untracked = "normal" # normal | no | all
# Color output
color = "auto" # auto | always | never
[status.preview]
# Show compression preview for staged files
compression = true
# Show deduplication opportunities
deduplication = true
# Show storage backend status
backend = true
Notes
Working Tree States
- Clean: No changes, nothing to commit
- Modified: Changes exist but not staged
- Staged: Changes ready for commit
- Conflicted: Merge conflicts need resolution
- Detached: HEAD not on a branch tip
Performance Tips
- Use
--shortfor faster output in scripts - Use
--porcelainfor machine parsing - Use
.mediagitignoreto permanently exclude build artifacts and temp files from appearing as untracked - Use
--ignoredto audit which files are currently excluded by.mediagitignore - Enable status caching for very large repositories
Media File Tracking
MediaGit provides enhanced status for media files:
- Automatic format detection (video, image, audio)
- Codec and quality information
- Resolution and duration metadata
- Compatibility warnings for unsupported formats
See Also
- mediagit add - Add files to the staging area
- mediagit commit - Record changes to the repository
- mediagit diff - Show changes between commits
- mediagit restore - Restore working tree files
- mediagit branch - List, create, or delete branches
mediagit log
Show commit history.
Synopsis
mediagit log [OPTIONS] [<revision-range>] [[--] <path>...]
Description
Shows the commit logs, displaying commit history with metadata, messages, and statistics. MediaGit log provides enhanced insights including compression metrics, deduplication statistics, and storage efficiency trends over time.
The log output shows commits in reverse chronological order by default, with the most recent commits appearing first.
Options
Output Format
--oneline
Condensed output showing one commit per line with short OID and message.
--pretty=<format>
Use custom format. Options:
- oneline: Compact single-line format
- short: Brief format with commit and author
- medium: Standard format with full details (default)
- full: Full format with author and committer
- fuller: Like full but with dates
- raw: Raw commit object format
- format:
: Custom format string
--format=<format>
Alias for --pretty=format:<format>.
--abbrev-commit
Show abbreviated commit OIDs (short form).
--no-abbrev-commit
Show full 64-character SHA-256 commit OIDs.
Filtering
-n <number>, --max-count=<number>
Limit number of commits to show.
--skip=<number>
Skip the first N commits before showing output.
--since=<date>, --after=<date>
Show commits more recent than specified date.
--until=<date>, --before=<date>
Show commits older than specified date.
--author=<pattern>
Filter commits by author name or email.
--committer=<pattern>
Filter commits by committer name or email.
--grep=<pattern>
Filter commits by message content.
-i, --regexp-ignore-case
Case-insensitive pattern matching for –grep, –author, –committer.
Content Filtering
--all
Show commits from all branches.
--branches[=<pattern>]
Show commits from matching branches.
--tags[=<pattern>]
Show commits from matching tags.
-- <path>...
Show only commits affecting specified paths.
Display Options
--graph
Draw ASCII graph showing branch and merge history.
--decorate[=<mode>]
Show branch and tag names. Mode: short, full, auto, no.
--stat[=<width>[,<name-width>[,<count>]]]
Show diffstat for each commit.
--shortstat
Show only summary line from –stat.
--name-only
Show names of changed files.
--name-status
Show names and status of changed files.
--patch, -p
Show patch (diff) for each commit.
--no-patch
Suppress patch output.
MediaGit-Specific Options
--compression-stats
Show compression and deduplication statistics for each commit.
--storage-trend
Display storage efficiency trends over time.
--media-only
Show only commits affecting media files.
--backend-info
Include storage backend information in output.
Format Placeholders
Custom format strings support placeholders:
Commit Information
%H: Full commit hash (SHA-256)%h: Abbreviated commit hash%T: Tree hash%t: Abbreviated tree hash%P: Parent hashes%p: Abbreviated parent hashes
Author/Committer
%an: Author name%ae: Author email%ad: Author date%ar: Author date, relative%cn: Committer name%ce: Committer email%cd: Committer date%cr: Committer date, relative
Message
%s: Subject (first line)%b: Body%B: Raw body (subject and body)
MediaGit Extensions
%Cs: Compression savings%Dd: Deduplication savings%Sz: Total storage size%Fc: File count
Examples
Basic log
$ mediagit log
commit a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Uploaded 5 new video files for Q1 marketing campaign.
Includes various resolution versions and format variants.
Compression: 410.2 MB → 75.9 MB (81.5% savings)
Deduplication: 8 chunks (12.3 MB saved)
Files: 5 added
commit b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Author: Bob Designer <bob@example.com>
Date: Sun Jan 14 09:15:47 2024 -0800
Update brand identity assets
- Updated logo files with new color scheme
- Added high-res versions for print media
- Removed deprecated logo variants
Compression: 156.8 MB → 28.4 MB (81.9% savings)
Files: 12 changed (8 added, 3 modified, 1 deleted)
One-line format
$ mediagit log --oneline
a3c8f9d Add promotional video assets
b4d7e1a Update brand identity assets
c5e9f2b Quick fix: correct video resolution
d6f0a3c Initial commit with base assets
Limited count
$ mediagit log -n 3
commit a3c8f9d...
...
commit b4d7e1a...
...
commit c5e9f2b...
...
Graph view
$ mediagit log --graph --oneline --all
* a3c8f9d (HEAD -> main) Add promotional video assets
* b4d7e1a Update brand identity assets
| * c5e9f2b (feature/video-opt) Optimize video encoding
|/
* d6f0a3c Initial commit with base assets
Date range filtering
$ mediagit log --since="2 weeks ago" --until="3 days ago"
commit b4d7e1a...
Author: Bob Designer <bob@example.com>
Date: Sun Jan 14 09:15:47 2024 -0800
Update brand identity assets
...
Author filtering
$ mediagit log --author="Alice" --oneline
a3c8f9d Add promotional video assets
e7g1b4d Add product photography
f8h2c5e Major redesign of homepage assets
Path-specific history
$ mediagit log -- videos/
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Files in videos/ directory:
- videos/promo_1080p.mp4 (added)
- videos/promo_4k.mp4 (added)
- videos/promo_mobile.mp4 (added)
Stat output
$ mediagit log --stat -n 1
commit a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
videos/promo_1080p.mp4 | 245.8 MB → 42.1 MB (82.9% savings)
videos/promo_4k.mp4 | 856.3 MB → 145.2 MB (83.0% savings)
videos/promo_mobile.mp4 | 89.5 MB → 18.7 MB (79.1% savings)
assets/thumbnail.jpg | 2.4 MB → 0.8 MB (66.7% savings)
metadata.json | 1.2 KB → 0.4 KB (delta)
5 files changed, 3 insertions(+), 0 deletions(-)
Custom format
$ mediagit log --format="%h - %an, %ar : %s" -n 3
a3c8f9d - Alice Developer, 2 hours ago : Add promotional video assets
b4d7e1a - Bob Designer, 1 day ago : Update brand identity assets
c5e9f2b - Alice Developer, 3 days ago : Quick fix: correct video resolution
Compression statistics
$ mediagit log --compression-stats -n 2
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Compression Statistics:
Algorithm: Zstd (level 3)
Original size: 410.2 MB
Compressed size: 75.9 MB
Compression ratio: 81.5%
Deduplication:
Duplicate chunks found: 8
Space saved: 12.3 MB
Efficiency gain: 3.0%
Delta Encoding:
Delta-encoded files: 1 (metadata.json)
Delta savings: 0.8 KB
Total Storage Impact:
New objects: 3,847
Reused objects: 142
Net storage increase: 63.6 MB
commit b4d7e1a...
...
Storage trend
$ mediagit log --storage-trend --oneline -n 5
a3c8f9d Add promotional video assets [Storage: +63.6 MB, Total: 1.2 GB]
b4d7e1a Update brand identity assets [Storage: +12.4 MB, Total: 1.1 GB]
c5e9f2b Quick fix: correct video [Storage: -2.1 MB, Total: 1.1 GB]
d6f0a3c Optimize existing media [Storage: -45.8 MB, Total: 1.1 GB]
e7g1b4d Add product photography [Storage: +8.9 MB, Total: 1.2 GB]
Storage Efficiency Trend:
Average compression ratio: 82.3%
Total deduplication savings: 267.4 MB
Trend: Improving (+2.1% over last 10 commits)
Media-only commits
$ mediagit log --media-only --oneline -n 5
a3c8f9d Add promotional video assets (5 video files)
e7g1b4d Add product photography (12 image files)
f8h2c5e Major redesign of homepage assets (28 media files)
g9i3d6f Apply design changes (7 image files)
h0j4e7g Add training video series (12 video files)
Search commit messages
$ mediagit log --grep="video" --oneline
a3c8f9d Add promotional video assets
c5e9f2b Quick fix: correct video resolution
h0j4e7g Add training video series
Branch comparison
$ mediagit log main..feature/video-opt --oneline
c5e9f2b Optimize video encoding parameters
i1k5f8h Add batch processing script
j2l6g9i Update compression profiles
Output Formatting
Decorations
$ mediagit log --oneline --decorate --graph -n 5
* a3c8f9d (HEAD -> main, origin/main) Add promotional video assets
* b4d7e1a Update brand identity assets
| * c5e9f2b (feature/video-opt) Optimize video encoding
|/
* d6f0a3c (tag: v1.0.0) Initial commit
Name and status
$ mediagit log --name-status -n 1
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
A videos/promo_1080p.mp4
A videos/promo_4k.mp4
A videos/promo_mobile.mp4
A assets/thumbnail.jpg
M metadata.json
Revision Ranges
Show commits in a range:
# Commits in branch2 not in branch1
$ mediagit log branch1..branch2
# Commits in either branch, but not both
$ mediagit log branch1...branch2
# Commits reachable from tag
$ mediagit log v1.0.0
# Commits since tag
$ mediagit log v1.0.0..HEAD
# All commits not in origin/main
$ mediagit log origin/main..HEAD
Performance
MediaGit log is optimized for large repositories:
- Commit streaming: Display results as they’re found
- Index utilization: Fast commit traversal using commit graph
- Parallel object loading: Multi-threaded object database access
- Smart caching: Cache recent commits for faster repeated queries
Typical performance:
- Unbounded log: Streams immediately, ~5000 commits/second
- Filtered log: Depends on filter complexity
- With –stat: ~1000 commits/second
- With –patch: ~100 commits/second
Exit Status
- 0: Success, commits displayed
- 1: Error accessing repository or objects
- 2: Invalid options or revision range
Configuration
[log]
# Default output format
format = "medium" # oneline | short | medium | full
# Show decorations by default
decorate = "auto" # auto | short | full | no
# Date format
date = "default" # default | iso | rfc | relative | short
# Abbreviate commit OIDs
abbrev_commit = true
# Follow renames
follow = true
[log.compression]
# Show compression stats by default
show_stats = false
# Include deduplication info
show_dedup = false
# Show storage trends
show_trends = false
Notes
Media-Aware Features
MediaGit log provides additional insights for media repositories:
- Format detection: Identify video, image, audio files
- Codec changes: Track encoding parameter changes
- Quality trends: Monitor compression quality over time
- Size analysis: Identify commits with large storage impact
Performance Optimization
For very large histories:
# Limit depth
$ mediagit log --max-count=100
# Skip expensive operations
$ mediagit log --no-patch --no-stat
# Filter early
$ mediagit log --since="1 month ago"
Commit Graph
MediaGit builds a commit graph for fast traversal:
# Rebuild if corrupted
$ mediagit gc --build-commit-graph
# Verify integrity
$ mediagit fsck --commit-graph
See Also
- mediagit show - Show commit details
- mediagit diff - Show changes between commits
- mediagit branch - List, create, or delete branches
- mediagit reflog - Show reference log
- mediagit blame - Show last modification for each line
mediagit diff
Show changes between commits, working tree, and staging area.
Synopsis
mediagit diff [OPTIONS] [<commit>] [<commit>] [--] [<path>...]
Description
Shows differences between various states in MediaGit:
- Working tree vs staging area (default)
- Staging area vs last commit (
--staged) - Between two commits
- Working tree vs specific commit
MediaGit diff provides media-aware comparison including:
- Visual diff for images (pixel-level comparison)
- Audio waveform comparison
- Video metadata and codec differences
- Binary file size changes with compression impact
Options
Diff Selection
--staged, --cached
Show changes staged for commit (between staging area and HEAD).
<commit>
Show changes between working tree and specified commit.
<commit> <commit>
Show changes between two commits.
-- <path>...
Limit diff to specified paths.
Output Format
-p, --patch
Generate patch format (default).
-s, --no-patch
Suppress diff output, show only summary.
--raw
Generate raw diff format.
--stat[=<width>[,<name-width>[,<count>]]]
Generate diffstat showing file changes summary.
--shortstat
Output only last line of –stat format.
--summary
Output condensed summary of extended header information.
--patch-with-stat
Output patch along with stat.
Unified Context
-U<n>, --unified=<n>
Generate diffs with N lines of context (default 3).
--no-prefix
Do not show “a/” and “b/” prefixes in diff output.
--src-prefix=<prefix>
Show given source prefix instead of “a/”.
--dst-prefix=<prefix>
Show given destination prefix instead of “b/”.
Comparison Options
-b, --ignore-space-change
Ignore changes in amount of whitespace.
-w, --ignore-all-space
Ignore whitespace when comparing lines.
--ignore-blank-lines
Ignore changes whose lines are all blank.
--binary
Output binary diffs for binary files.
MediaGit-Specific Options
--media-diff
Enable enhanced media file comparison:
- Image: Visual diff with pixel changes
- Audio: Waveform comparison
- Video: Metadata and codec changes
--compression-impact
Show compression impact of changes.
--size-analysis
Display detailed size analysis for binary files.
--visual
Generate visual representations for media files (requires external tools).
Display Options
--color[=<when>]
Show colored diff. When: always, never, auto (default).
--no-color
Turn off colored diff.
--word-diff[=<mode>]
Show word-level diff. Mode: color, plain, porcelain, none.
--name-only
Show only names of changed files.
--name-status
Show names and status of changed files.
Examples
Working tree vs staging area
$ mediagit diff
diff --git a/video.mp4 b/video.mp4
index a3c8f9d..b4d7e1a 100644
Binary files a/video.mp4 and b/video.mp4 differ
Size: 245.8 MB → 256.3 MB (+10.5 MB)
Compression impact: +1.8 MB (compressed)
diff --git a/config.json b/config.json
index e4f3a2b..f5g4b3c 100644
--- a/config.json
+++ b/config.json
@@ -12,7 +12,7 @@
"output": {
- "format": "mp4",
+ "format": "webm",
"quality": "high"
}
Staged changes
$ mediagit diff --staged
diff --git a/assets/logo.png b/assets/logo.png
new file mode 100644
index 0000000..a3c8f9d
Binary file assets/logo.png added
Size: 156.3 KB (compressed to 45.2 KB)
diff --git a/README.md b/README.md
index b4d7e1a..c5e9f2b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
# Media Project
+This project contains marketing assets.
+
## Usage
Compare commits
$ mediagit diff HEAD~2 HEAD
diff --git a/video_old.mp4 b/video_old.mp4
deleted file mode 100644
index a3c8f9d..0000000
Binary file video_old.mp4 removed
Size: 245.8 MB (freed: 42.1 MB compressed)
diff --git a/video_new.mp4 b/video_new.mp4
new file mode 100644
index 0000000..f5g4b3c
Binary file video_new.mp4 added
Size: 312.5 MB (compressed to 56.3 MB)
Net storage impact: +14.2 MB
Stat summary
$ mediagit diff --stat
video.mp4 | Binary file: 245.8 MB → 256.3 MB (+10.5 MB)
config.json | 2 +-
README.md | 3 +++
assets/logo.png | Binary file: 156.3 KB added
4 files changed, 4 insertions(+), 1 deletion(-)
Name and status only
$ mediagit diff --name-status
M video.mp4
M config.json
M README.md
A assets/logo.png
Specific path
$ mediagit diff -- video.mp4
diff --git a/video.mp4 b/video.mp4
index a3c8f9d..b4d7e1a 100644
Binary files a/video.mp4 and b/video.mp4 differ
Size: 245.8 MB → 256.3 MB (+10.5 MB)
Compression impact: +1.8 MB (compressed)
Metadata changes:
Duration: 00:03:45 → 00:03:52 (+7 seconds)
Resolution: 1920x1080 (unchanged)
Codec: H.264 → H.265 (HEVC)
Bitrate: 8.5 Mbps → 7.8 Mbps (-0.7 Mbps)
Media-aware diff
$ mediagit diff --media-diff image.jpg
diff --git a/image.jpg b/image.jpg
index e4f3a2b..f5g4b3c 100644
--- a/image.jpg
+++ b/image.jpg
@@ Image comparison:
Size: 2.4 MB → 2.6 MB (+0.2 MB)
Dimensions: 3840x2160 → 4096x2304 (+6.5% pixels)
Format: JPEG (quality 90) → JPEG (quality 95)
Pixel differences:
Changed pixels: 127,483 (1.4% of image)
Average color difference: 12.3 (ΔE)
Significant changes in regions:
- Top-left quadrant: +15.2% brightness
- Bottom-right corner: Color shift (+8 hue)
Compression impact: +0.3 MB (compressed)
Audio comparison
$ mediagit diff --media-diff audio.wav
diff --git a/audio.wav b/audio.wav
index a3c8f9d..b4d7e1a 100644
--- a/audio.wav
+++ b/audio.wav
@@ Audio comparison:
Size: 45.2 MB → 47.8 MB (+2.6 MB)
Duration: 00:04:32 → 00:04:32 (unchanged)
Sample rate: 44.1 kHz → 48 kHz
Bit depth: 16-bit → 24-bit
Channels: Stereo (unchanged)
Waveform analysis:
RMS level change: -2.3 dB (quieter)
Peak amplitude: -0.1 dB → -0.3 dB
Dynamic range: 18.2 dB → 22.5 dB (improved)
Compression impact: +0.8 MB (compressed with Zstd)
Compression impact analysis
$ mediagit diff --compression-impact --stat
video_1.mp4 | Binary: 245.8 MB → 256.3 MB | Compressed: +1.8 MB
video_2.mp4 | Binary: 312.5 MB → 298.7 MB | Compressed: -2.3 MB
image.jpg | Binary: 2.4 MB → 2.6 MB | Compressed: +0.3 MB
audio.wav | Binary: 45.2 MB → 47.8 MB | Compressed: +0.8 MB
config.json | 2 lines changed | Compressed: +12 bytes (delta)
Total impact:
Original size change: +18.9 MB
Compressed size change: +0.6 MB (96.8% compression efficiency)
Deduplication opportunities: 3 chunks (4.2 MB potential savings)
Size analysis
$ mediagit diff --size-analysis video.mp4
diff --git a/video.mp4 b/video.mp4
index a3c8f9d..b4d7e1a 100644
Size Analysis:
Original files:
Before: 245.8 MB
After: 256.3 MB
Change: +10.5 MB (+4.3%)
Compressed (Zstd level 3):
Before: 42.1 MB (82.9% compression)
After: 43.9 MB (82.9% compression)
Change: +1.8 MB (+4.3%)
Storage breakdown:
Video stream: +10.2 MB
Audio stream: +0.2 MB
Metadata: +0.1 MB
Chunk analysis:
Total chunks: 63 → 65 (+2 chunks)
Dedup chunks: 15 → 18 (+3 reused)
New unique: 48 → 47 (-1 unique)
Net new storage: +1.8 MB
Word-level diff
$ mediagit diff --word-diff config.json
diff --git a/config.json b/config.json
index e4f3a2b..f5g4b3c 100644
--- a/config.json
+++ b/config.json
@@ -12,7 +12,7 @@
"output": {
"format": [-"mp4"-]{+"webm"+},
"quality": "high"
}
Branch comparison
$ mediagit diff main..feature/optimize
diff --git a/video.mp4 b/video.mp4
index a3c8f9d..b4d7e1a 100644
Binary files differ
Size: 245.8 MB → 198.3 MB (-47.5 MB, 19.3% reduction)
Optimization applied:
Codec: H.264 → H.265 (better compression)
Bitrate: 8.5 Mbps → 7.2 Mbps
Quality loss: Minimal (PSNR > 45 dB)
Compression impact: -8.1 MB compressed (-19.2%)
Comparing Specific States
Working tree vs HEAD
$ mediagit diff HEAD
# Shows unstaged and staged changes
Staging area vs HEAD
$ mediagit diff --staged
# Shows only staged changes
Working tree vs staging area
$ mediagit diff
# Shows only unstaged changes (default)
Two branches
$ mediagit diff branch1..branch2
$ mediagit diff branch1...branch2 # symmetric difference
Status Codes
When using --name-status:
A Added
M Modified
D Deleted
R Renamed
C Copied
T Type changed
U Unmerged
Performance
MediaGit diff is optimized for media files:
- Smart binary detection: Skip detailed diff for large binaries
- Chunk-level comparison: Fast comparison using content-addressable chunks
- Parallel processing: Multi-threaded diff generation
- Incremental loading: Stream large diffs progressively
Typical performance:
- Text files: ~100MB/s
- Binary files (basic): ~500MB/s
- Media analysis: ~50MB/s
- Visual diff: ~10MB/s (CPU-intensive)
Exit Status
- 0: No differences found
- 1: Differences found
- 2: Error during diff operation
Configuration
[diff]
# Enable/disable color
color = "auto" # auto | always | never
# Context lines
context = 3
# Rename detection
renames = true
# Binary file handling
binary = true
[diff.media]
# Enable media-aware diff
enabled = true
# Include metadata analysis
metadata = true
# Visual comparison for images
visual = false # CPU-intensive
# Audio waveform comparison
waveform = false # requires ffmpeg
[diff.compression]
# Show compression impact
show_impact = true
# Size analysis detail level
size_detail = "summary" # summary | detailed | full
Media File Handling
Images
MediaGit can compare images at various levels:
# Basic size comparison (fast)
$ mediagit diff image.jpg
# Pixel-level comparison
$ mediagit diff --media-diff image.jpg
# Visual diff (generates side-by-side comparison)
$ mediagit diff --visual image.jpg
Videos
Video comparison includes:
- Metadata changes (codec, resolution, bitrate)
- Duration differences
- Quality metrics (when available)
- File size and compression impact
Audio
Audio comparison features:
- Format and encoding changes
- Sample rate and bit depth
- Waveform analysis (requires ffmpeg)
- RMS and peak levels
Notes
Binary File Diffs
Binary files show size changes by default:
Binary files a/video.mp4 and b/video.mp4 differ
Size: 245.8 MB → 256.3 MB (+10.5 MB)
Use --binary to see binary patch format (useful for small binaries).
Large File Performance
For very large files, diff uses:
- Chunk-based comparison (fast)
- Sampling for preview (configurable)
- Metadata-only mode for quick checks
Rename Detection
MediaGit automatically detects file renames:
$ mediagit diff --name-status
R100 old_video.mp4 -> new_video.mp4
The number indicates similarity percentage (100 = identical content).
See Also
- mediagit status - Show working tree status
- mediagit log - Show commit history
- mediagit show - Show commit details
- mediagit add - Add files to staging area
- mediagit restore - Restore working tree files
mediagit show
Show commit details and contents.
Synopsis
mediagit show [OPTIONS] [<object>...]
Description
Shows one or more objects (commits, trees, blobs, tags). For commits, shows:
- Commit metadata (author, date, message)
- Full diff of changes introduced
- Compression and deduplication statistics
- Storage impact analysis
MediaGit show provides enhanced insights for media-heavy repositories including detailed compression metrics, deduplication analysis, and media-specific metadata.
Options
Output Format
--pretty=<format>
Pretty-print commit. Options:
- oneline: Compact single-line format
- short: Brief format with commit and author
- medium: Standard format (default)
- full: Full format with author and committer
- fuller: Like full but with dates
- raw: Raw commit object format
--format=<format>
Custom format string (see mediagit log for placeholders).
--abbrev-commit
Show abbreviated commit OID.
--no-abbrev-commit
Show full 64-character SHA-256 OID.
Diff Options
-p, --patch
Show patch (default for commits).
-s, --no-patch
Suppress diff output.
--stat[=<width>[,<name-width>[,<count>]]]
Show diffstat.
--shortstat
Show only summary line of –stat.
--name-only
Show only names of changed files.
--name-status
Show names and status of changed files.
-U<n>, --unified=<n>
Generate diffs with N lines of context.
MediaGit-Specific Options
--compression-details
Show detailed compression statistics for the commit.
--dedup-analysis
Show deduplication analysis and chunk reuse information.
--storage-impact
Show storage impact and object database statistics.
--media-metadata
Show enhanced metadata for media files.
Examples
Show latest commit
$ mediagit show
commit a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Uploaded 5 new video files for Q1 marketing campaign.
Includes various resolution versions and format variants.
Compression: 410.2 MB → 75.9 MB (81.5% savings)
Deduplication: 8 chunks (12.3 MB saved)
Files: 5 added
diff --git a/videos/promo_1080p.mp4 b/videos/promo_1080p.mp4
new file mode 100644
index 0000000..a3c8f9d
Binary file videos/promo_1080p.mp4 added
Size: 245.8 MB (compressed to 42.1 MB, 82.9% savings)
diff --git a/videos/promo_4k.mp4 b/videos/promo_4k.mp4
new file mode 100644
index 0000000..b4d7e1a
Binary file videos/promo_4k.mp4 added
Size: 856.3 MB (compressed to 145.2 MB, 83.0% savings)
diff --git a/metadata.json b/metadata.json
index e4f3a2b..f5g4b3c 100644
--- a/metadata.json
+++ b/metadata.json
@@ -1,4 +1,9 @@
{
+ "videos": [
+ "promo_1080p.mp4",
+ "promo_4k.mp4"
+ ],
"version": "1.0"
}
Show specific commit
$ mediagit show b4d7e1a
commit b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Author: Bob Designer <bob@example.com>
Date: Sun Jan 14 09:15:47 2024 -0800
Update brand identity assets
- Updated logo files with new color scheme
- Added high-res versions for print media
- Removed deprecated logo variants
Compression: 156.8 MB → 28.4 MB (81.9% savings)
Files: 12 changed (8 added, 3 modified, 1 deleted)
diff --git a/assets/logo_old.png b/assets/logo_old.png
deleted file mode 100644
...
Show without patch
$ mediagit show --no-patch
commit a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Compression: 410.2 MB → 75.9 MB (81.5% savings)
Deduplication: 8 chunks (12.3 MB saved)
Files: 5 added
Show with stat
$ mediagit show --stat
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
videos/promo_1080p.mp4 | Binary: 245.8 MB (compressed to 42.1 MB)
videos/promo_4k.mp4 | Binary: 856.3 MB (compressed to 145.2 MB)
videos/promo_mobile.mp4 | Binary: 89.5 MB (compressed to 18.7 MB)
assets/thumbnail.jpg | Binary: 2.4 MB (compressed to 0.8 MB)
metadata.json | 5 insertions(+)
5 files changed (4 added, 1 modified)
Storage impact:
Original size: 410.2 MB
Compressed size: 75.9 MB (81.5% savings)
Net new objects: 3,847
Reused objects: 142
Show with compression details
$ mediagit show --compression-details a3c8f9d
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Compression Details:
Algorithm: Zstd (level 3)
Per-file breakdown:
videos/promo_1080p.mp4:
Original: 245.8 MB
Compressed: 42.1 MB
Ratio: 82.9%
Chunks: 63 (4 MB each)
Compression time: 2.3s
videos/promo_4k.mp4:
Original: 856.3 MB
Compressed: 145.2 MB
Ratio: 83.0%
Chunks: 215 (4 MB each)
Compression time: 8.1s
videos/promo_mobile.mp4:
Original: 89.5 MB
Compressed: 18.7 MB
Ratio: 79.1%
Chunks: 23 (4 MB each)
Compression time: 0.9s
Aggregate statistics:
Total original: 410.2 MB
Total compressed: 75.9 MB
Average ratio: 81.5%
Total compression time: 11.3s
Compression throughput: 36.3 MB/s
Show with deduplication analysis
$ mediagit show --dedup-analysis a3c8f9d
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Deduplication Analysis:
Total chunks processed: 301
Unique chunks: 293
Duplicate chunks found: 8
Deduplication ratio: 2.7%
Duplicate chunk details:
Chunk a8b9c0d1... (4 MB):
Found in: promo_1080p.mp4, promo_4k.mp4
Reused 1 time
Savings: 4.0 MB
Chunk b9c0d1e2... (4 MB):
Found in: promo_1080p.mp4, promo_mobile.mp4
Reused 1 time
Savings: 4.0 MB
[6 more chunks...]
Total space saved: 12.3 MB
Effective compression: 84.2% (including deduplication)
Object database impact:
Chunks already in ODB: 142
New unique chunks: 293
Total ODB chunks: 8,582 → 8,875 (+293)
Show with storage impact
$ mediagit show --storage-impact a3c8f9d
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Storage Impact Analysis:
Size changes:
New files: 5
Total original size: 410.2 MB
Total compressed: 75.9 MB
Compression savings: 334.3 MB (81.5%)
Deduplication savings: 12.3 MB (3.0%)
Net storage increase: 63.6 MB
Object database:
Objects before: 5,028
Objects after: 8,875
New objects: 3,847
Reused objects: 142
Object growth: +76.5%
Storage backend (AWS S3):
Region: us-west-2
Bucket: mediagit-prod-assets
New objects written: 3,847
Data transferred: 63.6 MB
Estimated cost: $0.0015/month
Repository totals:
Total objects: 8,875
Total size: 3.2 GB → 485.3 MB (84.8% compression)
Repository growth: +63.6 MB (+15.1%)
Show media metadata
$ mediagit show --media-metadata a3c8f9d
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
Media File Analysis:
videos/promo_1080p.mp4:
Type: Video (H.264/AVC)
Duration: 00:03:45
Resolution: 1920x1080 (Full HD)
Frame rate: 29.97 fps
Bitrate: 8.5 Mbps
Audio: AAC, 128 kbps, Stereo
File size: 245.8 MB → 42.1 MB (compressed)
videos/promo_4k.mp4:
Type: Video (H.265/HEVC)
Duration: 00:03:45
Resolution: 3840x2160 (4K UHD)
Frame rate: 29.97 fps
Bitrate: 28.3 Mbps
Audio: AAC, 256 kbps, Stereo
File size: 856.3 MB → 145.2 MB (compressed)
videos/promo_mobile.mp4:
Type: Video (H.264/AVC)
Duration: 00:03:45
Resolution: 1280x720 (HD)
Frame rate: 29.97 fps
Bitrate: 3.2 Mbps
Audio: AAC, 96 kbps, Stereo
File size: 89.5 MB → 18.7 MB (compressed)
assets/thumbnail.jpg:
Type: Image (JPEG)
Resolution: 1920x1080
Color space: sRGB
Quality: 90
File size: 2.4 MB → 0.8 MB (compressed)
Show specific file from commit
$ mediagit show a3c8f9d:metadata.json
{
"videos": [
"promo_1080p.mp4",
"promo_4k.mp4",
"promo_mobile.mp4"
],
"campaign": "Q1 2024",
"version": "1.0"
}
Show multiple commits
$ mediagit show b4d7e1a a3c8f9d
commit b4d7e1a...
Author: Bob Designer <bob@example.com>
Date: Sun Jan 14 09:15:47 2024 -0800
Update brand identity assets
...
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
...
Show tree object
$ mediagit show HEAD^{tree}
tree fb3a8bdd0ceddd019615af4d57a53f43d8cee2bf
videos/
assets/
metadata.json
README.md
Show blob object
$ mediagit show a3c8f9d:README.md
# Media Project
This project contains marketing assets for Q1 2024 campaign.
## Contents
- Promotional videos in various resolutions
- Brand identity assets
- Product photography
One-line format
$ mediagit show --oneline --no-patch
a3c8f9d Add promotional video assets
Name and status
$ mediagit show --name-status
commit a3c8f9d...
Author: Alice Developer <alice@example.com>
Date: Mon Jan 15 14:30:22 2024 -0800
Add promotional video assets
A videos/promo_1080p.mp4
A videos/promo_4k.mp4
A videos/promo_mobile.mp4
A assets/thumbnail.jpg
M metadata.json
Object Types
Commits
Default behavior shows commit details with diff:
$ mediagit show <commit>
Trees
Shows directory listing:
$ mediagit show <commit>^{tree}
$ mediagit show <commit>:path/to/directory/
Blobs
Shows file contents:
$ mediagit show <commit>:path/to/file
Tags
Shows tag information and tagged object:
$ mediagit show v1.0.0
Revision Syntax
# Show HEAD
$ mediagit show HEAD
# Show parent commit
$ mediagit show HEAD~1
$ mediagit show HEAD^
# Show specific commit
$ mediagit show a3c8f9d
# Show branch tip
$ mediagit show main
# Show tag
$ mediagit show v1.0.0
# Show file at commit
$ mediagit show HEAD:path/to/file
Performance
MediaGit show is optimized for large repositories:
- Lazy loading: Load only requested objects
- Chunk caching: Reuse decompressed chunks
- Parallel processing: Multi-threaded diff generation
- Smart formatting: Stream output progressively
Typical performance:
- Commit metadata: < 10ms
- Small diffs: < 100ms
- Large diffs (100+ files): < 2s
- Media analysis: 50-100 MB/s
Exit Status
- 0: Object shown successfully
- 1: Object not found or invalid
- 2: Error accessing repository
Configuration
[show]
# Default format
format = "medium"
# Show patch by default
patch = true
# Abbreviate OIDs
abbrev_commit = false
[show.compression]
# Show compression details by default
details = false
# Show deduplication analysis
dedup = false
# Show storage impact
storage_impact = false
[show.media]
# Show media metadata
metadata = false
# Media analysis depth
analysis = "basic" # basic | detailed | full
Notes
Large File Handling
For very large files in commits:
- Use
--no-patchto skip diff generation - Use
--statfor summary only - Metadata shown even for large binaries
Object Addressing
MediaGit uses SHA-256 for all objects:
- Full OID: 64 hexadecimal characters
- Short OID: First 7-12 characters (configurable)
- Automatic disambiguation for short OIDs
Media File Support
MediaGit provides enhanced display for:
- Videos: Codec, resolution, bitrate, duration
- Images: Resolution, format, color space
- Audio: Sample rate, bit depth, channels
- Documents: Page count, format version (when available)
See Also
- mediagit log - Show commit history
- mediagit diff - Show changes between commits
- mediagit cat-file - Show raw object contents
- mediagit ls-tree - List tree contents
- mediagit blame - Show last modification for each line
Branch Management
Commands for working with branches.
Commands
- branch - Create, list, delete, rename branches
- merge - Merge branches together
- rebase - Rebase branch onto another
- cherry-pick - Apply specific commits from another branch
- bisect - Binary search to find a regression-introducing commit
- stash - Save and restore uncommitted changes
- reset - Reset branch pointer to a commit
- revert - Undo a commit by creating an inverse commit
- tag - Create and manage tags
Typical Workflow
# Create feature branch
mediagit branch feature-new-asset
# Switch to branch
mediagit branch feature-new-asset
# Work on feature...
mediagit add new-asset.psd
mediagit commit -m "Add new asset"
# Merge back to main
mediagit branch main
mediagit merge feature-new-asset
mediagit branch
List, create, or delete branches.
Synopsis
mediagit branch [OPTIONS] [<branch>]
mediagit branch [OPTIONS] (-d | -D) <branch>...
mediagit branch [OPTIONS] (-m | -M) [<old-branch>] <new-branch>
mediagit branch [OPTIONS] (-c | -C) [<old-branch>] <new-branch>
Description
Manage branches in MediaGit repository. With no arguments, lists existing branches. The current branch is highlighted with an asterisk.
Branch operations in MediaGit are lightweight and instant, as they simply create references to commit objects. Branches are ideal for organizing parallel work on media projects, feature development, or maintaining multiple versions.
Options
Branch Listing
-l, --list [<pattern>]
List branches matching optional pattern.
-a, --all
List both local and remote-tracking branches.
-r, --remotes
List remote-tracking branches only.
-v, --verbose
Show commit OID and message for each branch.
-vv
Show upstream branch and tracking status (ahead/behind).
--merged [<commit>]
List branches merged into specified commit (default: HEAD).
--no-merged [<commit>]
List branches not merged into specified commit.
--contains <commit>
List branches containing specified commit.
--no-contains <commit>
List branches not containing specified commit.
Branch Creation
<branch>
Create new branch at current HEAD without switching to it.
<branch> <start-point>
Create new branch at specified commit/branch.
-c, --copy [<old-branch>] <new-branch>
Copy a branch and its reflog.
-C
Force copy even if target exists.
Branch Deletion
-d, --delete <branch>...
Delete fully merged branch. Refuses if branch not merged.
-D
Force delete branch regardless of merge status.
Branch Renaming
-m, --move [<old-branch>] <new-branch>
Rename branch. If old-branch omitted, rename current branch.
-M
Force rename even if new-branch exists.
Branch Configuration
-u <upstream>, --set-upstream-to=<upstream>
Set upstream tracking for current or specified branch.
--unset-upstream
Remove upstream tracking information.
-t, --track [direct|inherit]
Set branch tracking mode when creating.
--no-track
Do not set up tracking even if configured.
Display Options
--color[=<when>]
Color branches. When: always, never, auto (default).
--no-color
Turn off branch coloring.
--column[=<options>]
Display branches in columns.
--sort=<key>
Sort by key: refname, objectsize, authordate, committerdate.
Examples
List branches
$ mediagit branch
feature/video-optimization
feature/new-assets
* main
release/v1.0
List with details
$ mediagit branch -v
feature/video-optimization a3c8f9d Optimize video encoding
feature/new-assets b4d7e1a Add new promotional assets
* main c5e9f2b Update README
release/v1.0 d6f0a3c Release version 1.0
List with tracking info
$ mediagit branch -vv
feature/video-optimization a3c8f9d [origin/feature: ahead 2] Optimize encoding
feature/new-assets b4d7e1a Add new promotional assets
* main c5e9f2b [origin/main] Update README
release/v1.0 d6f0a3c [origin/release/v1.0: behind 1] Release
List all branches (including remotes)
$ mediagit branch -a
feature/video-optimization
feature/new-assets
* main
release/v1.0
remotes/origin/HEAD -> origin/main
remotes/origin/main
remotes/origin/feature/video-optimization
remotes/origin/release/v1.0
List remote branches only
$ mediagit branch -r
origin/HEAD -> origin/main
origin/main
origin/feature/video-optimization
origin/release/v1.0
Create new branch
$ mediagit branch feature/audio-processing
$ mediagit branch -v
feature/audio-processing c5e9f2b Update README
feature/video-optimization a3c8f9d Optimize video encoding
* main c5e9f2b Update README
Create branch at specific commit
$ mediagit branch hotfix/urgent-fix a3c8f9d
$ mediagit branch -v
hotfix/urgent-fix a3c8f9d Optimize video encoding
* main c5e9f2b Update README
Create and track remote branch
$ mediagit branch feature/new-feature origin/main
$ mediagit branch -u origin/feature/new-feature feature/new-feature
Branch 'feature/new-feature' set up to track 'origin/feature/new-feature'.
Delete merged branch
$ mediagit branch -d feature/completed
Deleted branch feature/completed (was a3c8f9d).
Force delete unmerged branch
$ mediagit branch -d feature/experimental
error: branch 'feature/experimental' not fully merged
$ mediagit branch -D feature/experimental
Deleted branch feature/experimental (was b4d7e1a).
warning: Deleted branch was not fully merged.
Rename branch
# Rename a specific branch: OLD first, then NEW (matches git -m semantics)
$ mediagit branch rename feature/old-name feature/new-name
Renamed branch 'feature/old-name' to 'feature/new-name'.
Rename current branch
# With a single argument, the current branch is renamed
$ mediagit branch rename new-branch-name
Renamed branch 'old-branch-name' to 'new-branch-name'.
Copy branch
$ mediagit branch -c main backup-main
Created branch 'backup-main' from 'main'.
List merged branches
$ mediagit branch --merged
feature/completed-task-1
feature/completed-task-2
* main
List unmerged branches
$ mediagit branch --no-merged
feature/in-progress
feature/experimental
hotfix/pending-review
List branches containing commit
$ mediagit branch --contains a3c8f9d
feature/video-optimization
* main
Set upstream tracking
$ mediagit branch -u origin/main
Branch 'main' set up to track 'origin/main'.
$ mediagit branch -vv
* main c5e9f2b [origin/main] Update README
Unset upstream tracking
$ mediagit branch --unset-upstream
Branch 'main' upstream tracking removed.
Sort branches by date
$ mediagit branch --sort=-committerdate
* main (2024-01-15)
feature/video-optimization (2024-01-14)
feature/new-assets (2024-01-12)
release/v1.0 (2024-01-10)
Filter branches with pattern
$ mediagit branch --list 'feature/*'
feature/video-optimization
feature/new-assets
feature/audio-processing
Branch Management Strategies
Feature Branches
# Create feature branch
$ mediagit branch feature/add-transitions main
$ mediagit checkout feature/add-transitions
# Work on feature...
# When complete, merge back
$ mediagit checkout main
$ mediagit merge feature/add-transitions
$ mediagit branch -d feature/add-transitions
Release Branches
# Create release branch
$ mediagit branch release/v2.0 main
# Finalize release
$ mediagit checkout release/v2.0
# Make release-specific changes...
$ mediagit commit -m "Prepare release v2.0"
# Tag release
$ mediagit tag v2.0
# Merge back to main
$ mediagit checkout main
$ mediagit merge release/v2.0
Hotfix Workflow
# Create hotfix from production tag
$ mediagit branch hotfix/critical-fix v1.0
$ mediagit checkout hotfix/critical-fix
# Fix issue
$ mediagit commit -m "Fix critical audio glitch"
# Merge to main and release
$ mediagit checkout main
$ mediagit merge hotfix/critical-fix
$ mediagit checkout release/v1.0
$ mediagit merge hotfix/critical-fix
$ mediagit tag v1.0.1
Branch Naming Conventions
Recommended patterns:
feature/<description> - New features
feature/video-editor
feature/audio-mixer
bugfix/<description> - Bug fixes
bugfix/audio-sync
bugfix/rendering-issue
hotfix/<description> - Urgent production fixes
hotfix/critical-crash
hotfix/security-patch
release/<version> - Release preparation
release/v1.0
release/v2.0-beta
experiment/<description> - Experimental work
experiment/new-codec
experiment/ml-upscaling
Branch Storage
MediaGit branches are lightweight:
- Stored as references (refs/heads/
) - Simply point to commit OIDs
- No data duplication on creation
- Instant creation and deletion
$ mediagit branch feature/test
Created branch 'feature/test' (takes 0.001s)
$ ls -lh .mediagit/refs/heads/feature/test
-rw-r--r-- 1 user group 65 Jan 15 10:30 .mediagit/refs/heads/feature/test
$ cat .mediagit/refs/heads/feature/test
c5e9f2b4764f2dbcee52635b91fedb1b3dcf7ab4d5e6f7a8b9c0d1e2f3a4b5c6d7e8
Performance
Branch operations are extremely fast:
- List branches: < 10ms (even with 1000+ branches)
- Create branch: < 1ms
- Delete branch: < 5ms
- Rename branch: < 5ms
- List with details (-v): < 50ms
Exit Status
- 0: Operation completed successfully
- 1: Branch not found or operation failed
- 2: Invalid options or branch name
Configuration
[branch]
# Automatically set up tracking
autosetupmerge = true # always | true | false
# Rebase on pull by default
autosetuprebase = never # always | local | remote | never
# Sort order for branch listing
sort = "-committerdate"
[color.branch]
# Branch name colors
current = "green bold"
local = "normal"
remote = "red"
upstream = "blue"
Branch Protection
MediaGit supports branch protection rules:
[branch "main"]
# Require review before merge
protected = true
# Prevent force push
allow_force_push = false
# Require status checks
require_checks = true
Remote Tracking
Set up tracking for collaboration:
# Automatic tracking on push
$ mediagit push -u origin feature/new-feature
# Manual tracking setup
$ mediagit branch -u origin/feature/new-feature
# View tracking relationships
$ mediagit branch -vv
* feature/new-feature a3c8f9d [origin/feature/new-feature: ahead 2] Latest work
main c5e9f2b [origin/main] Update README
Notes
Detached HEAD
When not on a branch:
$ mediagit checkout a3c8f9d
You are in 'detached HEAD' state...
$ mediagit branch
* (HEAD detached at a3c8f9d)
main
feature/test
Branch Deletion Safety
MediaGit prevents accidental deletion:
- Refuses to delete unmerged branches with
-d - Requires
-Dfor force deletion - Shows warning when deleting unmerged branches
Large Repository Performance
For repositories with many branches:
- Use pattern matching:
--list 'feature/*' - Use
--no-mergedto focus on active work - Sort by date:
--sort=-committerdate
See Also
- mediagit checkout - Switch branches
- mediagit merge - Merge branches
- mediagit rebase - Rebase branches
- mediagit log - View branch history
- mediagit remote - Manage remote repositories
mediagit merge
Join two or more development histories together.
Synopsis
mediagit merge [OPTIONS] <commit>...
mediagit merge --abort
mediagit merge --continue
Description
Incorporates changes from named commits (typically branch heads) into the current branch. MediaGit performs a new commit representing the merged result (merge commit).
MediaGit provides media-aware merging strategies that intelligently handle conflicts in binary media files based on file type, modification time, and content analysis.
Options
Merge Strategy
--ff
Fast-forward when possible (default).
--no-ff
Create merge commit even when fast-forward is possible.
--ff-only
Refuse to merge unless fast-forward is possible.
--squash
Create working tree and index state but don’t create merge commit.
Merge Strategy Selection
-s <strategy>, --strategy=<strategy>
Use given merge strategy:
- ours: Always prefer our version for conflicts
- theirs: Always prefer their version for conflicts
- latest-mtime: Choose file with latest modification time (media default)
- largest-size: Choose largest file version
- highest-quality: Choose highest quality based on metadata analysis
- manual: Require manual conflict resolution
-X <option>, --strategy-option=<option>
Pass option to merge strategy.
Commit Options
--commit
Perform merge and commit result (default).
--no-commit
Perform merge but don’t commit, allowing inspection.
-m <message>
Set merge commit message.
--edit, -e
Open editor to modify merge commit message.
--no-edit
Accept auto-generated merge message.
Conflict Resolution
--abort
Abort current conflict resolution and restore pre-merge state.
--continue
Continue merge after resolving conflicts.
--quit
Forget about current merge in progress.
Fast-Forward Options
--ff
Allow fast-forward (default).
--no-ff
Always create merge commit.
--ff-only
Only allow fast-forward, abort otherwise.
MediaGit-Specific Options
--media-strategy=<strategy>
Set media-specific merge strategy:
- latest-mtime: Latest modification time (default)
- largest-size: Largest file size
- highest-bitrate: Highest bitrate (video/audio)
- highest-resolution: Highest resolution (video/images)
- manual: Always require manual resolution
--analyze-quality
Perform quality analysis to determine best version.
--preserve-both
Keep both versions with conflict markers.
Examples
Fast-forward merge
$ mediagit merge feature/video-optimization
Updating a3c8f9d..b4d7e1a
Fast-forward
videos/promo.mp4 | Binary: 245.8 MB → 198.3 MB (-47.5 MB)
config.json | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
Three-way merge
$ mediagit merge feature/new-assets
Merge made by the 'recursive' strategy.
assets/logo.png | Binary: 156.3 KB added
assets/banner.jpg | Binary: 2.4 MB added
metadata.json | 5 insertions(+)
3 files changed, 5 insertions(+)
Created merge commit c5e9f2b
No fast-forward merge
$ mediagit merge --no-ff feature/hotfix
Merge branch 'feature/hotfix'
# Even though fast-forward was possible, creates merge commit
# to preserve branch history
Merge with custom message
$ mediagit merge -m "Merge video optimization improvements" feature/optimize
Merge made by the 'recursive' strategy.
videos/promo_1080p.mp4 | Binary: 245.8 MB → 198.3 MB (-19.3%)
videos/promo_4k.mp4 | Binary: 856.3 MB → 712.5 MB (-16.8%)
2 files changed
Media-aware merge (automatic)
$ mediagit merge feature/audio-update
Auto-merging audio.wav using 'latest-mtime' strategy
CONFLICT (content): Merge conflict in video.mp4
MediaGit analyzed conflicting file:
- Local version: modified 2024-01-15 14:30
- Remote version: modified 2024-01-14 09:00
- Strategy: latest-mtime
- Resolution: Keeping local version (newer)
Automatic merge successful.
audio.wav | Binary: auto-merged (latest-mtime)
video.mp4 | Binary: auto-merged (latest-mtime, kept local)
2 files changed
Media conflict with analysis
$ mediagit merge --analyze-quality feature/video-remaster
Auto-merging videos/promo.mp4
CONFLICT (media): Both sides modified videos/promo.mp4
Quality Analysis:
Local version:
Size: 245.8 MB
Resolution: 1920x1080
Bitrate: 8.5 Mbps
Codec: H.264
Modified: 2024-01-15 14:30
Remote version:
Size: 198.3 MB
Resolution: 1920x1080
Bitrate: 7.2 Mbps
Codec: H.265 (better compression)
Modified: 2024-01-14 09:00
Recommendation: Remote version (H.265, better compression, minimal quality loss)
Auto-resolved using 'highest-quality' strategy: keeping remote
Automatic merge successful.
Manual merge with conflicts
$ mediagit merge feature/concurrent-edits
Auto-merging metadata.json
CONFLICT (content): Merge conflict in metadata.json
Auto-merging video.mp4 using 'latest-mtime'
CONFLICT (media): Manual resolution required for image.jpg
Automatic merge failed; fix conflicts and then commit the result.
Conflicting files:
- metadata.json: text conflict, manual edit required
- image.jpg: both modified, resolution strategy unclear
Use "mediagit merge --abort" to cancel merge.
Resolve conflicts and continue
$ mediagit status
On branch main
You have unmerged paths.
(fix conflicts and run "mediagit commit")
Unmerged paths:
(use "mediagit add <file>..." to mark resolution)
both modified: metadata.json
both modified: image.jpg
# Manually resolve conflicts
$ vim metadata.json
$ mediagit add metadata.json
# Choose version for media file
$ mediagit checkout --ours image.jpg
$ mediagit add image.jpg
$ mediagit commit -m "Merge feature/concurrent-edits with conflict resolution"
[main d6f0a3c] Merge feature/concurrent-edits
Abort merge
$ mediagit merge feature/experimental
CONFLICT (content): Merge conflict in config.json
Automatic merge failed; fix conflicts and then commit the result.
$ mediagit merge --abort
Merge aborted, returning to pre-merge state.
Squash merge
$ mediagit merge --squash feature/multiple-commits
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
$ mediagit commit -m "Add all video optimization changes"
[main e7g1b4d] Add all video optimization changes
12 files changed
Merge specific strategy
$ mediagit merge --strategy=ours feature/keep-our-config
Merge made by the 'ours' strategy.
# All conflicts automatically resolved using our version
Media strategy: largest size
$ mediagit merge --media-strategy=largest-size feature/high-res
Auto-merging image.jpg using 'largest-size' strategy
CONFLICT (media): Comparing file sizes
- Local: 2.4 MB (1920x1080)
- Remote: 3.6 MB (2560x1440)
- Resolution: Keeping remote (larger, higher resolution)
Automatic merge successful.
Preserve both versions
$ mediagit merge --preserve-both feature/alternative-edit
CONFLICT (media): Both versions preserved
Created versions:
- video.mp4.ours (local version)
- video.mp4.theirs (remote version)
- video.mp4 (requires manual selection)
Please review both versions and keep the desired one.
Merge Commit Format
Default merge commit message:
Merge branch 'feature/branch-name'
# Conflicts resolved:
# video.mp4: kept ours (latest-mtime)
# audio.wav: kept theirs (highest-quality)
Merge Strategies
For Text Files
- three-way merge: Standard git-style merge with common ancestor
- ours: Keep our version
- theirs: Keep their version
For Media Files (MediaGit-Specific)
-
latest-mtime (default): Choose file with latest modification time
- Best for: Active editing workflows
- Assumption: Latest edit is the intended version
-
largest-size: Choose largest file
- Best for: Resolution upgrades, lossless workflows
- Assumption: Larger = higher quality or more content
-
highest-quality: Analyze metadata to determine quality
- Best for: Re-encoding workflows
- Considers: Bitrate, resolution, codec efficiency
-
highest-resolution: Choose highest resolution (images/video)
- Best for: Archival, print media
- Considers: Pixel dimensions only
-
highest-bitrate: Choose highest bitrate (audio/video)
- Best for: Audio mastering, video production
- Considers: Data rate regardless of codec
-
manual: Always require explicit choice
- Best for: Critical assets, legal requirements
- User must explicitly choose version
Conflict Resolution
Text File Conflicts
<<<<<<< HEAD (ours)
{
"format": "mp4",
"quality": "high"
}
=======
{
"format": "webm",
"quality": "ultra"
}
>>>>>>> feature/updates (theirs)
Edit file to resolve, then:
$ mediagit add config.json
$ mediagit commit
Media File Conflicts
# List conflict status
$ mediagit status
Unmerged paths:
both modified: video.mp4
# Choose our version
$ mediagit checkout --ours video.mp4
$ mediagit add video.mp4
# Or choose their version
$ mediagit checkout --theirs video.mp4
$ mediagit add video.mp4
# Or keep both
$ mediagit checkout --ours video.mp4 --to video_ours.mp4
$ mediagit checkout --theirs video.mp4 --to video_theirs.mp4
# Manually decide, then add chosen version
Fast-Forward Merge
When possible, MediaGit performs fast-forward:
Before:
A---B---C main
\
D---E feature
After (fast-forward):
A---B---C---D---E main, feature
Use --no-ff to always create merge commit:
After (no fast-forward):
A---B---C-------F main
\ /
D---E feature
Three-Way Merge
When branches have diverged:
Before:
A---B---C---D main
\
E---F feature
After:
A---B---C---D---G main
\ /
E---F---- feature
G is the merge commit with parents D and F
Merge Conflicts Statistics
$ mediagit merge feature/large-update
Auto-merging 47 files...
Merge Summary:
Fast-forward: 12 files
Auto-merged (text): 23 files
Auto-merged (media): 10 files
- latest-mtime: 7 files
- highest-quality: 3 files
Manual resolution required: 2 files
- metadata.json (text conflict)
- video.mp4 (unclear strategy)
Please resolve conflicts and commit.
Performance
MediaGit merge is optimized for media repositories:
- Fast-forward: < 50ms
- Small merge (<10 files): < 500ms
- Large merge (100+ files): < 5s
- Media analysis: 50-100 MB/s
Exit Status
- 0: Merge completed successfully
- 1: Conflicts detected, manual resolution required
- 2: Merge aborted or invalid operation
Configuration
[merge]
# Default merge strategy
default_strategy = "recursive"
# Fast-forward mode
ff = true # true | false | only
# Conflict style
conflict_style = "merge" # merge | diff3 | zdiff3
# Show stat after merge
stat = true
[merge.media]
# Default media merge strategy
strategy = "latest-mtime" # latest-mtime | largest-size | highest-quality | manual
# Perform quality analysis
analyze_quality = false
# Preserve both versions on conflict
preserve_both = false
# Media file extensions to auto-merge
auto_merge_types = ["mp4", "mov", "avi", "jpg", "png", "wav", "mp3"]
Notes
Best Practices
-
Before Merging:
- Ensure working tree is clean
- Review changes with
mediagit log - Consider impact with
mediagit diff
-
During Merge:
- Read conflict messages carefully
- Test media files after resolution
- Verify quality hasn’t degraded
-
After Merge:
- Test merged assets thoroughly
- Push changes to remote
- Delete merged feature branch
Media Merge Guidelines
- Video files: Prefer latest-mtime or highest-quality
- Images: Consider resolution and file size
- Audio: Consider bitrate and sample rate
- Documents: Use manual resolution for critical files
Large Binary Merges
For very large media files:
- Merge uses chunk-level comparison (fast)
- No content extraction needed
- Metadata analysis is quick
- Storage impact calculated efficiently
See Also
- mediagit branch - Manage branches
- mediagit rebase - Reapply commits on top of another branch
- mediagit diff - Show changes between commits
- mediagit log - Show commit history
- mediagit status - Show working tree status
mediagit rebase
Reapply commits on top of another base.
Synopsis
mediagit rebase [OPTIONS] [<upstream> [<branch>]]
mediagit rebase --continue
mediagit rebase --skip
mediagit rebase --abort
Description
Reapply commits from current branch on top of another base branch. This creates a linear history by moving the entire branch to begin from a different commit.
MediaGit rebase is media-aware, handling large binary files efficiently during the reapplication process and preserving compression and deduplication benefits.
Options
Basic Rebase
<upstream>
Upstream branch to rebase onto (default: configured upstream).
<branch>
Branch to rebase (default: current branch).
Interactive Rebase
-i, --interactive
Make a list of commits to be rebased and open in editor for modification.
--edit-todo
Edit rebase todo list during --continue.
Rebase Control
--continue
Continue rebase after resolving conflicts.
--skip
Skip current commit and continue rebase.
--abort
Abort rebase and return to original branch state.
--quit
Abort rebase but HEAD stays at current position.
Strategy Options
-s <strategy>, --strategy=<strategy>
Use given merge strategy for rebase.
-X <option>, --strategy-option=<option>
Pass option to merge strategy.
--merge
Use merging strategies to rebase (instead of apply).
Commit Handling
--keep-empty
Keep commits that become empty during rebase.
--empty=<mode>
How to handle commits that become empty: drop, keep, ask.
--rebase-merges[=<mode>]
Preserve merge commits during rebase.
Other Options
-f, --force-rebase
Force rebase even if branch is up to date.
--fork-point
Use reflog to find better common ancestor.
--ignore-date
Use current timestamp instead of original author date.
--committer-date-is-author-date
Use author date as committer date.
Examples
Basic rebase
$ mediagit rebase main
First, rewinding head to replay your work on top of it...
Applying: Add video optimization
Applying: Update compression settings
Applying: Add quality metrics
Successfully rebased and updated refs/heads/feature/optimize.
Rebase with conflicts
$ mediagit rebase main
Applying: Update video.mp4
CONFLICT (content): Merge conflict in video.mp4
error: could not apply a3c8f9d... Update video.mp4
Resolve all conflicts manually, mark them as resolved with
"mediagit add/rm <conflicted_files>", then run "mediagit rebase --continue".
You can instead skip this commit: run "mediagit rebase --skip".
To abort and get back to the state before "mediagit rebase", run "mediagit rebase --abort".
Could not apply a3c8f9d... Update video.mp4
$ mediagit status
rebase in progress; onto b4d7e1a
You are currently rebasing branch 'feature/optimize' on 'b4d7e1a'.
(fix conflicts and run "mediagit rebase --continue")
(use "mediagit rebase --skip" to skip this patch)
(use "mediagit rebase --abort" to check out the original branch)
Unmerged paths:
both modified: video.mp4
# Resolve conflict
$ mediagit checkout --ours video.mp4
$ mediagit add video.mp4
$ mediagit rebase --continue
Applying: Update video.mp4
Applying: Add quality metrics
Successfully rebased and updated refs/heads/feature/optimize.
Interactive rebase
$ mediagit rebase -i HEAD~3
# Editor opens with:
pick a3c8f9d Add video optimization
pick b4d7e1a Update compression settings
pick c5e9f2b Add quality metrics
# Rebase b4d7e1a..c5e9f2b onto b4d7e1a (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# d, drop <commit> = remove commit
# Modify to:
pick a3c8f9d Add video optimization
squash b4d7e1a Update compression settings
reword c5e9f2b Add quality metrics
# Save and close editor
[detached HEAD d6f0a3c] Add video optimization with compression updates
Date: Mon Jan 15 14:30:22 2024 -0800
2 files changed
# Editor opens for reword
Add comprehensive quality metrics
Added detailed quality tracking for video optimization workflow.
Successfully rebased and updated refs/heads/feature/optimize.
Rebase onto different branch
$ mediagit checkout feature/audio-fix
$ mediagit rebase --onto main feature/base feature/audio-fix
# Rebase commits from feature/audio-fix that aren't in feature/base
# onto main branch
Skip commit during rebase
$ mediagit rebase main
Applying: Temporary debug changes
CONFLICT (content): Multiple conflicts
# Don't want this commit
$ mediagit rebase --skip
Applying: Add important feature
Successfully rebased and updated refs/heads/feature/cleanup.
Abort rebase
$ mediagit rebase main
CONFLICT (content): Merge conflict in config.json
$ mediagit rebase --abort
Rebase aborted, returning to original branch state.
Rebase with strategy
$ mediagit rebase -s recursive -X theirs main
# Automatically resolve conflicts using 'theirs' version
Squash commits interactively
$ mediagit rebase -i HEAD~5
# Editor shows:
pick a3c8f9d Add video file
pick b4d7e1a Fix typo
pick c5e9f2b Update video
pick d6f0a3c Fix formatting
pick e7g1b4d Final video version
# Change to:
pick a3c8f9d Add video file
fixup b4d7e1a Fix typo
fixup c5e9f2b Update video
fixup d6f0a3c Fix formatting
fixup e7g1b4d Final video version
# Results in single commit with all changes
Rebase preserving merges
$ mediagit rebase --rebase-merges main
Successfully rebased and updated refs/heads/feature/complex.
# Preserves merge commits in branch history
Before and After Rebase
Before Rebase
A---B---C feature/optimize
/
D---E---F---G main
After Rebase
A'--B'--C' feature/optimize
/
D---E---F---G main
Note: A’, B’, C’ are new commits with same changes but different OIDs.
Interactive Rebase Commands
Available Commands
- pick (p): Use commit as-is
- reword (r): Use commit but edit message
- edit (e): Use commit but stop to amend
- squash (s): Meld into previous commit, combine messages
- fixup (f): Meld into previous commit, discard message
- drop (d): Remove commit
- exec (x): Run shell command
- break (b): Stop here (continue with
mediagit rebase --continue)
Example Todo List
pick a3c8f9d Add initial video processing
reword b4d7e1a Update compression algo
edit c5e9f2b Optimize for size
squash d6f0a3c Small compression tweak
fixup e7g1b4d Fix typo
exec cargo test
pick f8h2c5e Add quality metrics
drop g9i3d6f Experimental change that didn't work
break
pick h0j4e7g Final optimization pass
Media-Aware Rebase
MediaGit handles media files efficiently during rebase:
$ mediagit rebase main
Applying: Update promo video
Processing: video.mp4 (245.8 MB)
Reusing chunks: 142 chunks (85% of file)
New chunks: 23 chunks (15% of file)
Compression: Preserved from original commit
Deduplication: Maintained
Applying: Add thumbnail
Processing: thumbnail.jpg (2.4 MB)
Delta encoding: Applied against base
Compression: Zstd level 3
Successfully rebased 2 commits in 3.2s
Media processing: 248.2 MB in 2.8s (88.6 MB/s)
Rebase vs Merge
Use Rebase When
- Cleaning up local branch before pushing
- Keeping linear history
- Working on feature branch alone
- Want to avoid merge commits
Use Merge When
- Collaborating on shared branch
- Want to preserve context of branch
- Branch represents significant feature
- Need to show when features were integrated
Performance
MediaGit rebase performance:
- Small rebase (<10 commits): < 1s
- Medium rebase (10-50 commits): < 5s
- Large rebase (50+ commits): ~0.1s per commit
- Media files: Chunk reuse makes it efficient (50-100 MB/s)
Exit Status
- 0: Rebase completed successfully
- 1: Conflicts detected or rebase in progress
- 2: Invalid operation or error
Configuration
[rebase]
# Automatically stash before rebase
autostash = true
# Automatically squash fixup! commits
autosquash = true
# Use abbreviate commands in todo list
abbreviate_commands = false
# Update refs during rebase
update_refs = true
[rebase.media]
# Preserve compression during rebase
preserve_compression = true
# Maintain deduplication
maintain_dedup = true
# Chunk reuse optimization
chunk_reuse = true
Common Workflows
Clean up commits before push
$ mediagit rebase -i origin/main
# Squash "fix typo" commits
# Reword commit messages for clarity
# Drop experimental commits
Update feature branch with latest main
$ mediagit checkout feature/my-feature
$ mediagit rebase main
# Apply feature commits on top of latest main
Fix commit in middle of history
$ mediagit rebase -i HEAD~5
# Mark commit as 'edit'
# Make changes
$ mediagit add .
$ mediagit commit --amend
$ mediagit rebase --continue
Split commit into multiple
$ mediagit rebase -i HEAD~3
# Mark commit as 'edit'
$ mediagit reset HEAD^
# Stage and commit changes in multiple commits
$ mediagit add file1.mp4
$ mediagit commit -m "Add first video"
$ mediagit add file2.mp4
$ mediagit commit -m "Add second video"
$ mediagit rebase --continue
Resolving Conflicts
During Rebase
$ mediagit rebase main
CONFLICT (content): Merge conflict in config.json
# Check status
$ mediagit status
rebase in progress
# Resolve conflicts
$ vim config.json
$ mediagit add config.json
# Continue rebase
$ mediagit rebase --continue
Multiple Conflicts
# Resolve first conflict
$ mediagit add file1.txt
$ mediagit rebase --continue
# Another conflict appears
CONFLICT (content): Merge conflict in file2.json
# Resolve and continue
$ vim file2.json
$ mediagit add file2.json
$ mediagit rebase --continue
# Repeat until complete
Autosquash Feature
Create fixup commits automatically:
# Make commit
$ mediagit commit -m "Add video processing"
# OID: a3c8f9d
# Later, fix something in that commit
$ mediagit add video.mp4
$ mediagit commit --fixup a3c8f9d
# When rebasing
$ mediagit rebase -i --autosquash main
# Fixup commits automatically placed and marked
Notes
Golden Rule of Rebasing
Never rebase commits that have been pushed to a public repository.
Rebasing rewrites history, creating new commit OIDs. This causes problems for others who have based work on the old commits.
Safe Rebase Scenarios
✅ Safe:
- Local commits not yet pushed
- Feature branch only you work on
- After force-push to your fork
❌ Dangerous:
- Shared branches (main, develop)
- Commits already pulled by others
- Public release branches
Force Push After Rebase
After rebasing pushed commits:
$ mediagit rebase main
$ mediagit push --force-with-lease origin feature/my-branch
# Use --force-with-lease to prevent overwriting others' work
Large Media File Considerations
MediaGit optimizes rebase for media files:
- Chunks are reused across commits
- Compression preserved from original
- Deduplication maintained
- Fast processing (50-100 MB/s)
Troubleshooting
Rebase got messy
$ mediagit rebase --abort
# Start over with clean state
Lost commits during rebase
$ mediagit reflog
# Find lost commits
$ mediagit reset --hard <commit-before-rebase>
Too many conflicts
# Consider merge instead
$ mediagit rebase --abort
$ mediagit merge main
See Also
- mediagit merge - Join branches together
- mediagit branch - Manage branches
- mediagit commit - Record changes
- mediagit reset - Reset current HEAD
- mediagit reflog - Show reference log
mediagit cherry-pick
Apply commits from another branch onto the current branch.
Synopsis
mediagit cherry-pick [OPTIONS] <COMMITS>...
mediagit cherry-pick --continue
mediagit cherry-pick --abort
mediagit cherry-pick --skip
Description
Applies the changes introduced by the specified commits to the current branch, creating new commits. Useful for porting specific fixes or features from one branch to another without merging the full branch.
Short commit hashes (e.g., from mediagit log --oneline) are supported.
Arguments
<COMMITS>
One or more commits to apply. Applied in order (first to last). Accepts full 64-char OIDs or abbreviated short hashes.
Options
-n, --no-commit
Apply changes to the working tree without committing. Allows editing before the commit is created.
-e, --edit
Open an editor to modify the commit message before committing.
-x, --append-message
Append the original commit hash to the commit message for traceability:
(cherry picked from commit abc1234...).
--continue
Continue cherry-pick after resolving conflicts.
--abort
Abort the cherry-pick sequence and restore the pre-operation state.
--skip
Skip the current commit and continue with the rest of the sequence.
-q, --quiet
Suppress output.
Examples
Cherry-pick a single commit
# Find the commit to pick
$ mediagit log feature/hotfix --oneline
abc1234 Fix audio sync regression
# Apply it to current branch
$ mediagit cherry-pick abc1234
[main ghi9012] Fix audio sync regression
1 file changed, 2.3 MB modified
Cherry-pick multiple commits
$ mediagit cherry-pick abc1234 def5678 ghi9012
Applying: Fix audio sync regression
Applying: Update hero texture pack
Applying: Adjust lighting parameters
3 commits cherry-picked.
Cherry-pick with traceability
$ mediagit cherry-pick --append-message abc1234
[main xyz5678] Fix audio sync regression
(cherry picked from commit abc1234def5678...)
Handle conflicts
$ mediagit cherry-pick abc1234
CONFLICT: Apply commit abc1234 to current HEAD
Automatic merge failed in: audio/master.wav
# Resolve the conflict:
$ mediagit add audio/master.wav
$ mediagit cherry-pick --continue
# Or skip this commit:
$ mediagit cherry-pick --skip
# Or abort:
$ mediagit cherry-pick --abort
Apply without auto-committing
$ mediagit cherry-pick --no-commit abc1234 def5678
Changes applied but not committed. Review and then commit:
mediagit commit -m "Apply hotfixes from v1.1 branch"
Cherry-Pick vs Merge vs Rebase
| Scenario | Recommended |
|---|---|
| Bring specific fix to another branch | cherry-pick |
| Integrate all work from a branch | merge |
| Move a series of commits onto new base | rebase |
| Undo a specific commit | revert |
Exit Status
- 0: Success
- 1: Conflicts detected, manual resolution required
- 2: Commit not found or invalid operation
See Also
- mediagit revert - Undo a commit with an inverse commit
- mediagit rebase - Reapply a series of commits
- mediagit merge - Merge a full branch
- mediagit log - Find commits to cherry-pick
mediagit bisect
Find the commit that introduced a problem using binary search.
Synopsis
mediagit bisect start [<BAD>] [<GOOD>]
mediagit bisect good [<COMMIT>]
mediagit bisect bad [<COMMIT>]
mediagit bisect skip [<COMMIT>]
mediagit bisect reset [<COMMIT>]
mediagit bisect log
mediagit bisect replay <LOGFILE>
Description
Performs a binary search through commit history to efficiently find the commit that introduced a regression. Given a “bad” (broken) commit and a “good” (working) commit, MediaGit checks out the midpoint and asks you to test it. After O(log N) iterations, it identifies the first bad commit.
Short commit hashes (from mediagit log --oneline) are supported.
Subcommands
start
Begin a bisect session.
mediagit bisect start [<BAD>] [<GOOD>]
BAD— Known-broken commit (default:HEAD)GOOD— Known-working commit (must provide during session)
good
Mark the current (or specified) commit as working.
mediagit bisect good [<COMMIT>]
bad
Mark the current (or specified) commit as broken.
mediagit bisect bad [<COMMIT>]
skip
Skip a commit that cannot be tested (e.g., does not compile).
mediagit bisect skip [<COMMIT>]
reset
End the bisect session and return to the original branch.
mediagit bisect reset [<COMMIT>]
log
Show the bisect session log (good/bad/skip decisions made so far).
mediagit bisect log
replay
Replay a bisect session from a log file.
mediagit bisect replay <LOGFILE>
Examples
Full bisect session
# Start: HEAD is broken, commit from 2 weeks ago was good
$ mediagit bisect start
$ mediagit bisect bad HEAD
$ mediagit bisect good abc1234
Bisecting: 7 revisions left to test (about 3 steps)
[def5678] Add dynamic lighting rig
# Test the checked-out commit, then mark it:
$ mediagit bisect good # if this revision works
# or:
$ mediagit bisect bad # if this revision is broken
Bisecting: 3 revisions left (about 2 steps)
...
# After a few more iterations:
abc1234 is the first bad commit
Start with explicit commits
$ mediagit bisect start HEAD~20 HEAD~5
# HEAD~5 is bad, HEAD~20 is good
Skip untestable commits
$ mediagit bisect skip
View decisions so far
$ mediagit bisect log
good: abc1234 (Initial asset set)
bad: def5678 (Reprocess render outputs)
skip: ghi9012 (Corrupt file, untestable)
bad: jkl3456 (Add V2 textures)
Save and replay a bisect session
$ mediagit bisect log > bisect.log
# Later:
$ mediagit bisect replay bisect.log
End the session
$ mediagit bisect reset
Returned to branch 'main'
Session State
Bisect state is stored in .mediagit/BISECT_HEAD, .mediagit/BISECT_LOG, and
.mediagit/BISECT_TERMS. Running mediagit bisect reset clears these files.
Exit Status
- 0: Success / first bad commit found
- 1: No active bisect session or commit not found
See Also
- mediagit log - Browse commit history
- mediagit reflog - Track HEAD movements during bisect
- mediagit revert - Undo the identified bad commit
mediagit stash
Save and restore uncommitted changes.
Synopsis
mediagit stash save [-m <MESSAGE>] [-u] [PATHS...]
mediagit stash push [-m <MESSAGE>] [-u] [PATHS...]
mediagit stash list
mediagit stash show [<STASH>]
mediagit stash apply [<STASH>]
mediagit stash pop [<STASH>]
mediagit stash drop [<STASH>]
mediagit stash clear [--force]
Description
Stash allows you to save uncommitted changes to a stack and restore them later. Useful when you need to switch branches without committing work-in-progress.
Stash entries are stored in .mediagit/stash/ as numbered entries.
Subcommands
save / push
Save current changes to the stash. push is a git-compatible alias for save and accepts
identical flags and arguments.
mediagit stash save [-m <MESSAGE>] [-u] [PATHS...]
Options:
-m,--message <MESSAGE>— Descriptive message for the stash entry-u,--include-untracked— Also stash untracked filesPATHS— Stash only specific files/directories (optional)-q,--quiet— Suppress output
list
Show all stash entries.
mediagit stash list
show
Show the diff of a stash entry.
mediagit stash show [<STASH>]
STASH defaults to stash@{0} (most recent).
apply
Apply a stash entry without removing it from the stack.
mediagit stash apply [<STASH>]
pop
Apply and remove the most recent (or specified) stash entry.
mediagit stash pop [<STASH>]
drop
Remove a stash entry without applying it.
mediagit stash drop [<STASH>]
clear
Remove all stash entries. Prompts for confirmation unless --force is specified.
mediagit stash clear [--force]
Options:
-f,--force— Skip confirmation prompt (useful in scripts/CI)
Examples
Save current changes
$ mediagit stash save -m "WIP: texture adjustments"
Stashed changes in stash@{0}: WIP: texture adjustments
List stashes
$ mediagit stash list
stash@{0}: WIP: texture adjustments (3 files, 145 MB)
stash@{1}: Experimental lighting rig
stash@{2}: Audio sync fixes
Apply and remove latest stash
$ mediagit stash pop
Applying stash@{0}: WIP: texture adjustments
3 files restored
Apply an older stash
$ mediagit stash apply stash@{2}
Stash including untracked files
$ mediagit stash save --include-untracked -m "Work in progress"
Clear all stashes in a script
$ mediagit stash clear --force
All stash entries cleared.
Exit Status
- 0: Success
- 1: No stash entries found or stash index out of range
See Also
- mediagit status - Show working tree status
- mediagit branch - Switch branches
- mediagit reset - Reset working tree changes
mediagit reset
Reset the current branch to a specified commit.
Synopsis
mediagit reset [--soft | --mixed | --hard] [<COMMIT>]
mediagit reset <COMMIT> [--] <PATHS>...
Description
Moves the current branch pointer to the specified commit. How the working tree and staging area are affected depends on the reset mode.
When paths are specified, only those files are affected (path-specific reset does not move the branch pointer).
Arguments
[COMMIT]
Target commit (default: HEAD). Accepts full 64-char OIDs, short hashes (e.g.,
abc1234), branch names, or HEAD~N notation.
[PATHS]
Specific files to reset. Cannot be combined with --soft or --hard.
Options
--soft
Move the branch pointer to <COMMIT>. Working tree and staging area are
unchanged — changes from undone commits appear as staged.
--mixed (default)
Move the branch pointer and reset the staging area to match <COMMIT>. Working
tree files are unchanged — changes appear as unstaged.
--hard
Move the branch pointer, reset staging area, and discard all working tree changes. Destructive — cannot be undone without the reflog.
-q, --quiet
Suppress output.
Examples
Undo last commit, keep changes staged
$ mediagit reset --soft HEAD~1
Undo last commit, unstage changes (default)
$ mediagit reset HEAD~1
# same as:
$ mediagit reset --mixed HEAD~1
Discard last commit and all changes
$ mediagit reset --hard HEAD~1
Reset to a specific commit
$ mediagit reset --hard abc1234def
HEAD is now at abc1234d Previous stable state
Unstage specific files
$ mediagit reset -- textures/hero.psd
Unstaged: textures/hero.psd
Recover from accidental –hard reset
# Find the lost commit in the reflog
$ mediagit reflog --count 10
HEAD@{0}: reset: moving to HEAD~1
HEAD@{1}: commit: Add hero texture
# Restore the lost commit
$ mediagit reset --hard HEAD@{1}
Reset Modes Comparison
| Mode | Branch pointer | Staging area | Working tree |
|---|---|---|---|
--soft | Moved | Unchanged | Unchanged |
--mixed | Moved | Reset | Unchanged |
--hard | Moved | Reset | Reset (destructive) |
Exit Status
- 0: Success
- 1: Commit not found or invalid options
See Also
- mediagit revert - Undo a commit by creating an inverse commit
- mediagit reflog - Recover from accidental resets
- mediagit stash - Stash changes without committing
mediagit revert
Revert a commit by creating a new inverse commit.
Synopsis
mediagit revert [OPTIONS] <COMMITS>...
mediagit revert --continue
mediagit revert --abort
mediagit revert --skip
Description
Creates new commits that undo the changes introduced by the specified commits.
Unlike mediagit reset, revert preserves history — the original commits
remain, and new “revert” commits are added. Safe to use on pushed commits.
Multiple commits are reverted in reverse order (newest first).
Arguments
<COMMITS>
One or more commits to revert. Accepts full or short OIDs and branch-relative
refs (e.g., HEAD~2).
Options
-n, --no-commit
Apply the inverse changes to the working tree without creating commits. Allows inspection and editing before committing.
-m <MESSAGE>, --message <MESSAGE>
Override the auto-generated revert commit message.
--continue
Continue reverting after manually resolving conflicts.
--abort
Abort a multi-commit revert in progress and restore pre-revert state.
--skip
Skip the current commit during a multi-commit revert sequence.
-q, --quiet
Suppress output.
Examples
Revert the most recent commit
$ mediagit revert HEAD
[main abc1234] Revert "Add experimental render pass"
1 file changed, 145 MB removed
Revert a specific commit
$ mediagit revert def5678
[main ghi9012] Revert "Update hero texture"
Revert multiple commits
$ mediagit revert HEAD~3..HEAD
Reverting: Update audio mix (3/3)
Reverting: Add V2 render assets (2/3)
Reverting: Adjust lighting rig (1/3)
3 revert commits created.
Revert without committing (inspect first)
$ mediagit revert --no-commit HEAD~2..HEAD
Changes staged but not committed. Review and then:
mediagit commit -m "Revert recent changes"
Handle conflicts during revert
$ mediagit revert abc1234
CONFLICT (content): Merge conflict in scene.psd
error: could not revert abc1234 -- resolve conflicts manually
# Resolve conflicts, then:
$ mediagit add scene.psd
$ mediagit revert --continue
# Or skip this commit:
$ mediagit revert --skip
# Or abort entirely:
$ mediagit revert --abort
When to Use Revert vs Reset
| Situation | Command |
|---|---|
| Undo commits that haven’t been pushed | reset --hard |
| Undo pushed commits (preserve history) | revert |
| Keep the change but remove from branch | reset --soft |
| Undo a specific old commit in history | revert <hash> |
Exit Status
- 0: Success
- 1: Conflicts detected, manual resolution required
- 2: Commit not found or invalid operation
See Also
- mediagit reset - Reset branch pointer (rewrites history)
- mediagit cherry-pick - Apply commits from another branch
- mediagit log - Find commits to revert
mediagit tag
Create and manage tags.
Synopsis
mediagit tag create <NAME> [<COMMIT>] [-m <MESSAGE>]
mediagit tag list [--pattern <PATTERN>]
mediagit tag delete <NAME>
mediagit tag show <NAME>
Description
Tags mark specific commits with meaningful names (e.g., release versions,
approved milestone snapshots). MediaGit stores tags as refs under
.mediagit/refs/tags/.
Subcommands
create
Create a new tag pointing to a commit.
mediagit tag create <NAME> [<COMMIT>] [-m <MESSAGE>]
Arguments:
NAME— Tag name (e.g.,v1.0,release/2025-q1)COMMIT— Commit to tag (default:HEAD)
Options:
-m,--message <MESSAGE>— Annotated tag message
list
List all tags.
mediagit tag list [--pattern <PATTERN>]
Aliases: ls
Options:
-p,--pattern <PATTERN>— Filter by glob pattern (e.g.,v1.*)-v,--verbose— Show tag messages and commit info
delete
Delete a tag.
mediagit tag delete <NAME>
Aliases: rm
show
Show tag details.
mediagit tag show <NAME>
Examples
Create a lightweight tag at HEAD
$ mediagit tag create v1.0
Tag 'v1.0' created at HEAD (abc1234d)
Create an annotated tag with a message
$ mediagit tag create v2.0 -m "Q2 2025 approved asset set"
Tag 'v2.0' created: Q2 2025 approved asset set
Tag a specific commit
$ mediagit tag create approved-2025-06 def5678
List all tags
$ mediagit tag list
v1.0
v1.1
v2.0
approved-2025-06
List tags matching a pattern
$ mediagit tag list --pattern "v*"
v1.0
v1.1
v2.0
Show tag details
$ mediagit tag show v2.0
tag v2.0
Tagger: Alice Smith <alice@example.com>
Date: Mon Jun 09 2025 14:30:00
Q2 2025 approved asset set
commit def5678...
Delete a tag
$ mediagit tag delete v1.0
Deleted tag 'v1.0'
Tag Naming Conventions
Recommended patterns:
- Version releases:
v1.0,v1.2.3 - Quarterly approvals:
approved/2025-q2 - Milestones:
milestone/alpha,milestone/beta
Tag names may not contain spaces. Use / for namespacing.
Exit Status
- 0: Success
- 1: Tag already exists (create) or tag not found (delete/show)
See Also
- mediagit log - View commit history with tag decorations
- mediagit show - Show tag or commit details
- mediagit branch - Manage branches
Remote Operations
Commands for working with remote repositories.
Commands
- clone - Clone a remote repository locally
- remote - Add, remove, and list remote connections
- fetch - Download objects from remote without merging
- push - Push commits to remote
- pull - Fetch and merge from remote
Typical Workflow
# Push to remote
mediagit push origin main
# Pull from remote
mediagit pull origin main
mediagit clone
Clone a remote MediaGit repository.
Synopsis
mediagit clone [OPTIONS] <URL> [DIRECTORY]
Description
Creates a local copy of a remote MediaGit repository, downloading all objects and
setting up a remote named origin pointing to the source URL.
Arguments
<URL>
Remote repository URL. Supports http://, https://, and file:// schemes.
[DIRECTORY]
Local directory to clone into. Defaults to the repository name derived from the URL.
Options
-b <BRANCH>, --branch <BRANCH>
Check out the specified branch after cloning instead of the default (main).
-q, --quiet
Suppress progress output.
-v, --verbose
Show detailed transfer information.
Examples
Basic clone
$ mediagit clone http://media-server.example.com/my-project
Cloning into 'my-project'...
Receiving objects: 100% (1,234 objects, 2.4 GB)
✓ Cloned 'my-project' in 12.3s
Clone into specific directory
$ mediagit clone http://media-server.example.com/vfx-shots game-assets
Cloning into 'game-assets'...
Clone specific branch
$ mediagit clone --branch production http://media-server.example.com/my-project
After Cloning
cd my-project
mediagit log --oneline # view history
mediagit status # check working tree
Exit Status
- 0: Success
- 1: Network error or repository not found
- 2: Destination directory already exists
See Also
- mediagit remote - Manage remote repositories
- mediagit fetch - Fetch from remote
- mediagit pull - Fetch and merge from remote
mediagit remote
Manage remote repository connections.
Synopsis
mediagit remote add <NAME> <URL> [--fetch]
mediagit remote remove <NAME>
mediagit remote list [--verbose]
mediagit remote rename <OLD> <NEW>
mediagit remote set-url <NAME> <URL>
mediagit remote show <NAME>
Description
Manages the set of remotes whose branches you track. Remote URLs are stored in
.mediagit/config.toml.
Subcommands
add
Add a new remote.
mediagit remote add <NAME> <URL>
Options:
-f,--fetch— Immediately fetch from the new remote after adding
remove
Remove a remote and all its tracking refs.
mediagit remote remove <NAME>
Alias: rm
list
List all configured remotes.
mediagit remote list [--verbose]
Options:
-v,--verbose— Show URLs alongside remote names
rename
Rename a remote.
mediagit remote rename <OLD-NAME> <NEW-NAME>
set-url
Change the URL of an existing remote.
mediagit remote set-url <NAME> <NEW-URL>
show
Show detailed information about a remote.
mediagit remote show <NAME>
Examples
Add a remote
$ mediagit remote add origin http://media-server.example.com/my-project
Add a remote and fetch immediately
$ mediagit remote add upstream http://media-server.example.com/upstream --fetch
List remotes
$ mediagit remote list
origin
upstream
$ mediagit remote list --verbose
origin http://media-server.example.com/my-project (fetch)
origin http://media-server.example.com/my-project (push)
upstream http://media-server.example.com/upstream (fetch)
upstream http://media-server.example.com/upstream (push)
Rename a remote
$ mediagit remote rename origin production
Change URL
$ mediagit remote set-url origin https://new-server.example.com/my-project
Remove a remote
$ mediagit remote remove old-server
Configuration
Remotes are stored in .mediagit/config.toml:
[remotes.origin]
url = "http://media-server.example.com/my-project"
[remotes.backup]
url = "http://backup-server.example.com/my-project"
Exit Status
- 0: Success
- 1: Remote not found or URL invalid
See Also
- mediagit fetch - Fetch from a remote
- mediagit push - Push to a remote
- mediagit pull - Fetch and merge from remote
- mediagit clone - Clone a remote repository
mediagit fetch
Download objects and refs from a remote repository without merging.
Synopsis
mediagit fetch [OPTIONS] [REMOTE] [BRANCH]
Description
Fetches branches and objects from a remote repository, updating remote-tracking
refs. Does not modify the local working tree — use mediagit pull to fetch
and merge in one step.
Arguments
[REMOTE]
Remote name (default: origin).
[BRANCH]
Specific branch to fetch. If omitted, fetches all branches.
Options
--all
Fetch from all configured remotes.
-p, --prune
Remove remote-tracking refs that no longer exist on the remote.
-q, --quiet
Suppress progress output.
-v, --verbose
Show detailed transfer information.
Examples
Fetch from origin
$ mediagit fetch
From http://media-server.example.com/my-project
abc1234..def5678 main -> origin/main
new branch feature/vfx -> origin/feature/vfx
Fetch specific branch
$ mediagit fetch origin feature/lighting
Fetch from all remotes
$ mediagit fetch --all
Prune deleted remote branches
$ mediagit fetch --prune
From http://media-server.example.com/my-project
- [deleted] (none) -> origin/feature/old
After Fetching
# Review changes from remote
mediagit log origin/main..main --oneline
# Merge fetched changes
mediagit merge origin/main
Exit Status
- 0: Success
- 1: Network error or remote not found
See Also
- mediagit pull - Fetch and merge in one step
- mediagit remote - Manage remotes
- mediagit merge - Merge branches
mediagit push
Update remote repository with local commits.
Synopsis
mediagit push [OPTIONS] [<repository> [<refspec>...]]
Description
Updates remote repository with local commits and objects. Transfers commits, trees, and blobs from local repository to remote, ensuring remote has all objects needed to reconstruct the history.
MediaGit push is optimized for large media files, using:
- Incremental uploads (only new chunks)
- Parallel transfer for multiple objects
- Compression-aware transfers
- Deduplication across pushes
Options
Repository and Refspec
<repository>
Remote repository name or URL (default: origin).
<refspec>
Source and destination refs (default: current branch).
Push Behavior
-u, --set-upstream
Set upstream tracking for current branch.
--all
Push all branches.
--tags
Push all tags.
--follow-tags
Push tags reachable from pushed commits.
--mirror
Mirror all refs (branches and tags).
Force Options
-f, --force
Force update remote refs (dangerous).
--force-with-lease[=<refname>[:<expect>]]
Safer force push, refuses if remote changed unexpectedly.
--force-if-includes
Force push only if remote has commits we’ve seen.
Execution Options
-n, --dry-run
Show what would be pushed without actually pushing.
--receive-pack=<git-receive-pack>
Path to receive-pack program on remote.
--progress
Force progress reporting.
-q, --quiet
Suppress all output.
-v, --verbose
Show detailed information.
Ref Management
--delete
Delete remote ref.
--prune
Remove remote branches that don’t exist locally.
MediaGit-Specific Options
--optimize-transfer
Enable transfer optimizations for media files.
--parallel=<n>
Number of parallel upload threads (default: 4).
--chunk-size=<size>
Chunk size for large file transfers (default: 4MB).
--compression-level=<n>
Compression level for transfer (0-9).
Examples
Push current branch
$ mediagit push
Enumerating objects: 47, done.
Counting objects: 100% (47/47), done.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (24/24), 63.6 MB | 8.2 MB/s, done.
Total 24 (delta 3), reused 18 (delta 1)
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> main
Push with upstream tracking
$ mediagit push -u origin feature/video-optimization
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 75.9 MB | 9.8 MB/s, done.
Total 8 (delta 2), reused 0 (delta 0)
To https://github.com/user/mediagit-project.git
* [new branch] feature/video-optimization -> feature/video-optimization
Branch 'feature/video-optimization' set up to track 'origin/feature/video-optimization'.
Push all branches
$ mediagit push --all origin
Enumerating objects: 84, done.
Counting objects: 100% (84/84), done.
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> main
c5e9f2b..d6f0a3c feature/optimize -> feature/optimize
* [new branch] feature/new-assets -> feature/new-assets
Push with tags
$ mediagit push --follow-tags
Enumerating objects: 24, done.
Writing objects: 100% (24/24), 63.6 MB | 8.2 MB/s, done.
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> main
* [new tag] v1.0.0 -> v1.0.0
Force push with lease
$ mediagit push --force-with-lease
Enumerating objects: 18, done.
Writing objects: 100% (12/12), 45.2 MB | 7.8 MB/s, done.
To https://github.com/user/mediagit-project.git
+ a3c8f9d...b4d7e1a main -> main (forced update)
warning: Force-pushed to main branch
Dry run
$ mediagit push --dry-run
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> main
Dry run: Would push 3 commits (63.6 MB)
No changes were made to the remote repository.
Delete remote branch
$ mediagit push origin --delete feature/old-branch
To https://github.com/user/mediagit-project.git
- [deleted] feature/old-branch
Push specific branch
$ mediagit push origin feature/video-optimization
Enumerating objects: 8, done.
Writing objects: 100% (8/8), 75.9 MB | 9.8 MB/s, done.
To https://github.com/user/mediagit-project.git
c5e9f2b..d6f0a3c feature/video-optimization -> feature/video-optimization
Push to different remote name
$ mediagit push origin main:production
Total 12 (delta 3), reused 8 (delta 2)
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> production
Optimized transfer for large media
$ mediagit push --optimize-transfer --parallel=8
Enumerating objects: 47, done.
Counting objects: 100% (47/47), done.
Transfer optimization enabled:
Deduplication: Skipping 142 chunks already on remote
New chunks: 293 chunks to upload
Total data: 410.2 MB → 63.6 MB (84.5% reduction)
Parallel upload (8 threads):
Thread 1: 36.7 MB/s
Thread 2: 38.2 MB/s
Thread 3: 37.1 MB/s
Thread 4: 35.9 MB/s
Thread 5: 36.4 MB/s
Thread 6: 37.8 MB/s
Thread 7: 36.2 MB/s
Thread 8: 38.5 MB/s
Uploading objects: 100% (293/293), 63.6 MB | 296.8 MB/s (aggregate), done.
To https://s3.amazonaws.com/mediagit-prod-assets
a3c8f9d..b4d7e1a main -> main
Verbose output
$ mediagit push -v
Pushing to https://github.com/user/mediagit-project.git
Enumerating objects: 24, done.
Counting objects: 100% (24/24), done.
Objects to push:
Commits: 3
Trees: 5
Blobs: 16
Total size: 410.2 MB (original)
Compressed: 63.6 MB
Upload progress:
[============================] 100% (24/24 objects)
[============================] 100% (63.6/63.6 MB)
Average speed: 8.2 MB/s
Time elapsed: 7.8s
To https://github.com/user/mediagit-project.git
a3c8f9d..b4d7e1a main -> main
Post-push statistics:
Remote objects: 5,028 → 5,052 (+24)
Remote size: 421.7 MB → 485.3 MB (+63.6 MB)
Transfer Optimization
Chunk Deduplication
MediaGit avoids re-uploading existing chunks:
$ mediagit push
Analyzing remote objects...
Remote already has 142 chunks (58.2 MB)
Uploading only new chunks: 293 chunks (63.6 MB)
Upload: 63.6 MB instead of 121.8 MB (47.8% savings)
Parallel Transfers
$ mediagit push --parallel=8
Parallel upload enabled (8 threads)
Chunk batch 1: 8 chunks → Thread 1
Chunk batch 2: 8 chunks → Thread 2
...
Chunk batch 37: 5 chunks → Thread 5
Aggregate throughput: 296.8 MB/s
Compression During Transfer
# Already compressed objects
$ mediagit push
Objects already compressed (Zstd level 3)
Transfer compression: None (efficient)
Upload speed: 8.2 MB/s
# Additional transfer compression
$ mediagit push --compression-level=6
Transfer compression: Gzip level 6
Network transfer: 63.6 MB → 58.1 MB (8.6% additional savings)
Upload speed: 7.5 MB/s (slightly slower due to compression overhead)
Push Rejection
Non-Fast-Forward Update
$ mediagit push
To https://github.com/user/mediagit-project.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/user/mediagit-project.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'mediagit pull ...') before pushing again.
hint: See the 'Note about fast-forwards' for details.
$ mediagit pull --rebase
$ mediagit push
# Success
Force Push Required
$ mediagit push --force-with-lease
# Safer than --force, checks remote hasn't changed unexpectedly
Push Refspecs
Format
[+]<src>:<dst>
- +: Force update (optional)
- src: Local ref
- dst: Remote ref
Examples
# Push local main to remote main
$ mediagit push origin main:main
# Push local feature to remote with different name
$ mediagit push origin feature/local:feature/remote
# Force push
$ mediagit push origin +main:main
# Delete remote branch
$ mediagit push origin :feature/old-branch
# or
$ mediagit push origin --delete feature/old-branch
# Push all branches
$ mediagit push origin 'refs/heads/*:refs/heads/*'
# Push all tags
$ mediagit push origin 'refs/tags/*:refs/tags/*'
Performance
Small Push
Objects: 5-10
Size: < 10 MB
Time: 1-3 seconds
Medium Push
Objects: 10-50
Size: 10-100 MB
Time: 5-15 seconds
Large Push
Objects: 50-200
Size: 100 MB - 1 GB
Time: 30-120 seconds
Optimization: Critical
Very Large Push
Objects: 200+
Size: > 1 GB
Time: 2-10 minutes
Optimization: Essential
Recommendation: Use --optimize-transfer --parallel=8
Exit Status
- 0: Push completed successfully
- 1: Push rejected or failed
- 2: Invalid options or configuration
Configuration
[push]
# Default push behavior
default = "simple" # nothing | current | upstream | simple | matching
# Push tags automatically
follow_tags = false
# Require force-with-lease instead of force
use_force_if_includes = true
# Recurse into submodules
recurse_submodules = "check" # check | on-demand | only | no
[push.transfer]
# Parallel upload threads
parallel = 4
# Chunk size for large files
chunk_size = "4MB"
# Enable transfer optimization
optimize = true
# Transfer compression level (0-9)
compression_level = 0 # 0 = none
# Progress reporting
show_progress = true
Remote Storage Backends
S3-Compatible Storage
$ mediagit push
To s3://mediagit-prod-assets/repo.git
a3c8f9d..b4d7e1a main -> main
Transfer details:
Endpoint: s3.us-west-2.amazonaws.com
Bucket: mediagit-prod-assets
Objects uploaded: 24
Data transferred: 63.6 MB
Estimated cost: $0.0012
Azure Blob Storage
$ mediagit push
To azure://mediagitprod.blob.core.windows.net/repo.git
a3c8f9d..b4d7e1a main -> main
Transfer details:
Account: mediagitprod
Container: repo
Objects uploaded: 24
Data transferred: 63.6 MB
Google Cloud Storage
$ mediagit push
To gs://mediagit-prod-assets/repo.git
a3c8f9d..b4d7e1a main -> main
Transfer details:
Bucket: mediagit-prod-assets
Region: us-central1
Objects uploaded: 24
Data transferred: 63.6 MB
Best Practices
Before Pushing
-
Review changes:
$ mediagit log origin/main..HEAD $ mediagit diff origin/main..HEAD -
Ensure tests pass:
$ mediagit push --dry-run -
Check remote state:
$ mediagit fetch $ mediagit status
When Pushing
- Use descriptive branch names
- Set upstream tracking (
-uon first push) - Avoid force push to shared branches
- Use
--force-with-leaseinstead of--force
After Pushing
-
Verify success:
$ mediagit log origin/main -
Clean up local branches:
$ mediagit branch -d feature/merged-branch
Troubleshooting
Authentication Failed
error: Authentication failed
hint: Check your credentials or access token
Solution: Update credentials or regenerate access token.
Large File Timeout
error: RPC failed; HTTP 500 curl 22 timeout
Solution: Use --optimize-transfer and --parallel:
$ mediagit push --optimize-transfer --parallel=8
Storage Quota Exceeded
error: Remote storage quota exceeded
hint: Current usage: 9.8 GB / 10 GB
Solution: Run garbage collection or upgrade storage plan.
Notes
Force Push Warning
⚠️ Force pushing rewrites remote history
Only force push when:
- Working on personal feature branch
- Coordinated with team
- Absolutely necessary
Always prefer --force-with-lease over --force.
Media File Efficiency
MediaGit push is highly efficient for media files:
- Deduplication prevents re-uploading unchanged chunks
- Compression reduces transfer size
- Parallel uploads maximize bandwidth
- Incremental transfers save time and costs
Network Interruption
If push is interrupted:
$ mediagit push
# Network interruption
$ mediagit push
# Resumes from where it left off
# Already-uploaded chunks are skipped
See Also
- mediagit pull - Fetch and merge from remote
- mediagit fetch - Download from remote
- mediagit remote - Manage remote repositories
- mediagit branch - Manage branches
mediagit pull
Fetch from and integrate with remote repository.
Synopsis
mediagit pull [OPTIONS] [<repository> [<refspec>...]]
Description
Fetch changes from remote repository and integrate them into current branch. Equivalent to running mediagit fetch followed by mediagit merge (or mediagit rebase if configured).
MediaGit pull is optimized for large media repositories, using:
- Incremental downloads (only new objects)
- Parallel transfers for faster downloads
- Smart chunk reuse and deduplication
- Efficient merge strategies for media files
Options
Integration Method
--rebase[=<mode>]
Rebase current branch on top of upstream after fetch. Modes: false, true, merges, interactive.
--no-rebase
Merge instead of rebase (default).
--ff-only
Only allow fast-forward merge.
--no-ff
Create merge commit even when fast-forward is possible.
Fetch Options
-a, --all
Fetch from all remotes.
--depth=<depth>
Limit fetching to specified number of commits.
--unshallow
Convert shallow repository to complete one.
--tags
Fetch all tags.
--no-tags
Don’t fetch tags.
Merge/Rebase Options
-s <strategy>, --strategy=<strategy>
Use given merge strategy.
-X <option>, --strategy-option=<option>
Pass option to merge strategy.
--commit
Perform merge and commit (default).
--no-commit
Perform merge but don’t commit.
Execution Options
-n, --dry-run
Show what would be done without actually doing it.
-q, --quiet
Suppress output.
-v, --verbose
Show detailed information.
--progress
Force progress reporting.
MediaGit-Specific Options
--optimize-transfer
Enable download optimizations for media files.
--parallel=<n>
Number of parallel download threads (default: 4).
--verify-checksums
Verify chunk integrity during download.
Examples
Basic pull
$ mediagit pull
Fetching origin
Enumerating objects: 24, done.
Counting objects: 100% (24/24), done.
Compressing objects: 100% (12/12), done.
Receiving objects: 100% (24/24), 63.6 MB | 9.2 MB/s, done.
Resolving deltas: 100% (3/3), done.
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Updating a3c8f9d..b4d7e1a
Fast-forward
videos/promo.mp4 | Binary: 245.8 MB → 198.3 MB (-19.3%)
assets/logo.png | Binary: 156.3 KB added
2 files changed, 1 insertion(+), 1 deletion(-)
Pull with rebase
$ mediagit pull --rebase
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Rebasing on top of origin/main...
Applying: Local commit 1
Applying: Local commit 2
Successfully rebased and updated refs/heads/main.
Pull specific branch
$ mediagit pull origin feature/video-optimization
From https://github.com/user/mediagit-project
* branch feature/video-optimization -> FETCH_HEAD
Updating c5e9f2b..d6f0a3c
Fast-forward
videos/optimized.mp4 | Binary: 856.3 MB → 712.5 MB (-16.8%)
1 file changed
Pull with fast-forward only
$ mediagit pull --ff-only
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
fatal: Not possible to fast-forward, aborting.
# Need to merge or rebase
$ mediagit pull --rebase
# or
$ mediagit pull --no-ff
Pull with merge commit
$ mediagit pull --no-ff
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Merge made by the 'recursive' strategy.
videos/promo.mp4 | Binary: 245.8 MB → 198.3 MB
1 file changed
Created merge commit e7g1b4d
Pull with conflicts
$ mediagit pull
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Auto-merging config.json
CONFLICT (content): Merge conflict in config.json
Auto-merging video.mp4 using 'latest-mtime' strategy
Automatic merge failed; fix conflicts and then commit the result.
$ mediagit status
On branch main
You have unmerged paths.
Unmerged paths:
both modified: config.json
# Resolve conflicts
$ vim config.json
$ mediagit add config.json
$ mediagit commit -m "Merge with conflict resolution"
Optimized pull for large media
$ mediagit pull --optimize-transfer --parallel=8
Fetching origin
Analyzing remote objects...
Transfer optimization:
Chunks already local: 847 (2.3 GB)
New chunks to download: 293 (63.6 MB)
Total savings: 97.3% (avoided 2.3 GB download)
Parallel download (8 threads):
Thread 1: 42.1 MB/s
Thread 2: 43.7 MB/s
Thread 3: 41.5 MB/s
Thread 4: 42.9 MB/s
Thread 5: 43.2 MB/s
Thread 6: 42.4 MB/s
Thread 7: 41.8 MB/s
Thread 8: 43.6 MB/s
Receiving objects: 100% (293/293), 63.6 MB | 341.2 MB/s (aggregate), done.
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Updating a3c8f9d..b4d7e1a
Fast-forward
videos/promo_4k.mp4 | Binary: 856.3 MB added (145.2 MB compressed)
1 file changed
Pull with verification
$ mediagit pull --verify-checksums
Fetching origin
Receiving objects: 100% (24/24), 63.6 MB | 9.2 MB/s, done.
Verifying checksums: 100% (24/24), done.
Verifying chunk integrity: 100% (293/293), done.
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
All objects verified successfully ✓
Dry run
$ mediagit pull --dry-run
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
Dry run: Would update main
Fast-forward a3c8f9d..b4d7e1a
Would download: 24 objects (63.6 MB)
No changes were made to the local repository.
Interactive rebase during pull
$ mediagit pull --rebase=interactive
Fetching origin
From https://github.com/user/mediagit-project
a3c8f9d..b4d7e1a main -> origin/main
# Editor opens with rebase todo list
# Modify, save, and close
Successfully rebased and updated refs/heads/main.
Verbose output
$ mediagit pull -v
Fetching origin
POST git-upload-pack (175 bytes)
From https://github.com/user/mediagit-project
= [up to date] main -> origin/main
* [new branch] feature/new -> origin/feature/new
Receiving objects: 100% (24/24), 63.6 MB | 9.2 MB/s, done.
Download statistics:
Objects received: 24
Bytes received: 63.6 MB
Chunks received: 293
Chunks reused: 142
Download time: 6.9s
Average speed: 9.2 MB/s
Updating a3c8f9d..b4d7e1a
Fast-forward
videos/promo.mp4 | Binary: 245.8 MB added
Pull Strategies
Fast-Forward (Default)
Before pull:
A---B---C origin/main
\
D main (local)
After pull (fast-forward):
A---B---C origin/main, main
Merge (Non-Fast-Forward)
Before pull:
A---B---C origin/main
\
D---E main (local)
After pull (merge):
A---B---C-------F main
\ /
D---E----
Rebase
Before pull:
A---B---C origin/main
\
D---E main (local)
After pull (rebase):
A---B---C---D'---E' main
\
origin/main
Transfer Optimization
Chunk Deduplication
MediaGit avoids re-downloading existing chunks:
$ mediagit pull
Analyzing local objects...
Local repository has 847 chunks (2.3 GB)
Remote objects reference 1,140 chunks (2.4 GB)
Downloading only new chunks: 293 chunks (63.6 MB)
Download: 63.6 MB instead of 2.4 GB (97.3% savings)
Parallel Downloads
$ mediagit pull --parallel=8
Parallel download enabled (8 threads)
Chunk batch 1: 37 chunks → Thread 1
Chunk batch 2: 37 chunks → Thread 2
...
Chunk batch 8: 36 chunks → Thread 8
Aggregate throughput: 341.2 MB/s
Time saved: 82% (1.2s vs 6.9s)
Delta Resolution
$ mediagit pull
Receiving objects: 100% (24/24), done.
Resolving deltas: 100% (3/3), done.
Delta resolution:
Base objects: 3
Delta objects: 3
Resolved size: 1.2 KB → 4.5 KB (reconstructed)
Conflict Resolution
Automatic Media Merge
$ mediagit pull
Auto-merging video.mp4 using 'latest-mtime' strategy
Local: modified 2024-01-15 14:30
Remote: modified 2024-01-14 09:00
Resolution: Keeping local version (newer)
Merge successful.
Manual Resolution Required
$ mediagit pull
CONFLICT (media): Both versions modified at same time
video.mp4: both modified 2024-01-15 14:30
Please choose version:
$ mediagit checkout --ours video.mp4 # Keep local
$ mediagit checkout --theirs video.mp4 # Use remote
Then: $ mediagit add video.mp4
$ mediagit commit
Configuration
[pull]
# Rebase by default instead of merge
rebase = false # false | true | merges | interactive
# Fast-forward only
ff = "only" # false | true | only
# Octopus merge for multiple branches
octopus = false
[pull.transfer]
# Parallel download threads
parallel = 4
# Enable transfer optimization
optimize = true
# Verify checksums
verify = true
# Progress reporting
show_progress = true
[pull.media]
# Default media merge strategy
merge_strategy = "latest-mtime"
Pull vs Fetch + Merge
Pull (One Command)
$ mediagit pull
# Fetch + merge/rebase in one step
Fetch + Merge (Two Commands)
$ mediagit fetch
# Review changes
$ mediagit log origin/main..HEAD
$ mediagit diff origin/main..HEAD
# Then merge or rebase
$ mediagit merge origin/main
# or
$ mediagit rebase origin/main
Performance
Small Pull
Objects: 5-10
Size: < 10 MB
Time: 1-3 seconds
Medium Pull
Objects: 10-50
Size: 10-100 MB
Time: 5-15 seconds
Large Pull
Objects: 50-200
Size: 100 MB - 1 GB
Time: 30-120 seconds
Optimization: Important
Very Large Pull
Objects: 200+
Size: > 1 GB
Time: 2-10 minutes
Optimization: Critical
Recommendation: Use --optimize-transfer --parallel=8
Exit Status
- 0: Pull completed successfully
- 1: Merge/rebase conflicts detected
- 2: Invalid options or fetch failed
Best Practices
Before Pulling
-
Commit or stash local changes:
$ mediagit status $ mediagit commit -m "Save work in progress" # or $ mediagit stash -
Review remote changes:
$ mediagit fetch $ mediagit log ..origin/main
When Pulling
-
Use rebase for clean history (feature branches):
$ mediagit pull --rebase -
Use merge for shared branches (main, develop):
$ mediagit pull --no-ff -
Enable optimization for large repositories:
$ mediagit pull --optimize-transfer --parallel=8
After Pulling
-
Verify changes:
$ mediagit log -3 $ mediagit status -
Test changes:
$ cargo test # or your project's test command
Troubleshooting
Uncommitted Changes
$ mediagit pull
error: Your local changes would be overwritten by merge.
Please commit or stash them before pulling.
$ mediagit stash
$ mediagit pull
$ mediagit stash pop
Cannot Fast-Forward
$ mediagit pull --ff-only
fatal: Not possible to fast-forward, aborting.
# Solution 1: Rebase
$ mediagit pull --rebase
# Solution 2: Merge
$ mediagit pull --no-ff
Large Download Timeout
error: RPC failed; HTTP 500 timeout
# Solution: Use optimization
$ mediagit pull --optimize-transfer --parallel=8
Merge Conflicts
$ mediagit pull
CONFLICT (content): Merge conflict in config.json
$ mediagit status
# Fix conflicts
$ vim config.json
$ mediagit add config.json
$ mediagit commit
Notes
Fetch vs Pull
- fetch: Only downloads, doesn’t integrate
- pull: Downloads and integrates (fetch + merge/rebase)
Use fetch when you want to review changes before integrating.
Media File Efficiency
MediaGit pull is highly efficient:
- Deduplication prevents re-downloading unchanged chunks (97%+ savings typical)
- Compression reduces transfer size (80%+ compression typical)
- Parallel downloads maximize bandwidth (8x faster with 8 threads)
- Incremental transfers save time and bandwidth costs
Network Interruption
If pull is interrupted:
$ mediagit pull
# Network interruption
$ mediagit pull
# Resumes from where it left off
# Already-downloaded chunks are skipped
Shallow Pulls
For very large repositories, consider shallow clone:
$ mediagit clone --depth 1 <url>
$ mediagit pull --depth 1
# Later, unshallow if needed
$ mediagit pull --unshallow
See Also
- mediagit fetch - Download from remote
- mediagit merge - Join branches together
- mediagit rebase - Reapply commits
- mediagit push - Update remote repository
- mediagit remote - Manage remotes
Maintenance Commands
Repository maintenance and health check commands.
Commands
- gc - Garbage collection and optimization
- fsck - File system consistency check
- verify - Verify object integrity
- stats - Repository statistics
- reflog - History of HEAD and branch movements
Recommended Schedule
# Weekly: Garbage collection
mediagit gc
# Monthly: Full verification
mediagit verify
# As needed: Check stats
mediagit stats
mediagit gc
Cleanup unnecessary files and optimize repository.
Synopsis
mediagit gc [OPTIONS]
Description
Runs garbage collection to optimize the repository by:
- Removing unreachable objects
- Compressing loose objects into packfiles
- Removing redundant packfiles
- Optimizing deduplication and compression
- Building or updating commit graph
- Pruning old reflog entries
For media repositories, garbage collection is particularly important to:
- Reclaim space from deleted large files
- Optimize chunk storage and deduplication
- Improve performance of object retrieval
- Reduce storage costs for remote backends
Options
Garbage Collection Mode
--aggressive
More aggressive optimization (slower but better compression).
--auto
Run only if repository needs optimization (default behavior).
--prune[=<date>]
Prune loose objects older than date (default: 2 weeks ago).
--no-prune
Do not prune any loose objects.
Performance Options
--quiet, -q
Suppress all output.
--force
Force garbage collection even if another gc is running.
MediaGit-Specific Options
--optimize-chunks
Reoptimize chunk storage and deduplication.
--rebuild-index
Rebuild object database index.
--compress-level=<n>
Recompress objects with specified level (0-9).
--repack
Repack loose objects into pack files for better compression and storage efficiency.
--max-pack-size=<size>
Maximum size per pack file (e.g., 100MB, 1GB). Default: unlimited.
--verify
Verify object integrity during gc.
Examples
Basic garbage collection
$ mediagit gc
Enumerating objects: 8,875, done.
Counting objects: 100% (8,875/8,875), done.
Compressing objects: 100% (4,238/4,238), done.
Writing objects: 100% (8,875/8,875), done.
Building commit graph: 100% (142/142), done.
Garbage collection complete:
Objects processed: 8,875
Objects removed: 247 (unreachable)
Objects compressed: 4,238
Space reclaimed: 127.3 MB
Repository size: 612.6 MB → 485.3 MB
Time: 12.4s
Aggressive optimization
$ mediagit gc --aggressive
Running aggressive garbage collection...
Phase 1: Enumerating objects
Objects found: 8,875
Time: 2.1s
Phase 2: Removing unreachable objects
Unreachable objects: 247
Space reclaimed: 127.3 MB
Time: 1.8s
Phase 3: Recompressing objects
Algorithm: Zstd level 9 (max compression)
Objects recompressed: 8,628
Original size: 3.2 GB
Compressed size: 485.3 MB → 412.8 MB
Additional savings: 72.5 MB (14.9%)
Time: 45.7s
Phase 4: Optimizing deduplication
Duplicate chunks found: 89
Deduplication savings: 45.2 MB
Time: 5.3s
Phase 5: Building commit graph
Commits: 142
Time: 0.4s
Total time: 55.3s
Final repository size: 340.3 MB (89.4% compression from original)
Prune old objects
$ mediagit gc --prune=1.week.ago
Pruning objects older than 1 week...
Pruned objects:
Commits: 12
Trees: 34
Blobs: 156
Total space reclaimed: 89.4 MB
Remaining objects: 8,673
Repository size: 485.3 MB → 395.9 MB
Optimize chunk storage
$ mediagit gc --optimize-chunks
Analyzing chunk storage...
Chunk optimization:
Total chunks: 2,847
Duplicate chunks: 89
Fragmented chunks: 23
Suboptimal compression: 12
Reoptimizing chunks:
Deduplication: 89 chunks → 45.2 MB saved
Defragmentation: 23 chunks → 12.1 MB saved
Recompression: 12 chunks → 3.8 MB saved
Total savings: 61.1 MB
Final chunk count: 2,735 (-112)
Repository size: 485.3 MB → 424.2 MB
Repack loose objects into pack files
Basic repack:
$ mediagit gc --repack
Repacking objects...
Packed 4,238 objects into pack file (2,847 deltas)
Pack file: objects/pack/pack_abc123.pack (127.3 MB)
Loose objects removed: 4,238
Space reclaimed: 89.4 MB
With size limit:
$ mediagit gc --repack --max-pack-size=500MB
Creating pack files with 500MB limit...
Pack file 1: objects/pack/pack_abc123.pack (500 MB)
Pack file 2: objects/pack/pack_def456.pack (287 MB)
Total packed: 4,238 objects
Verify packing:
$ mediagit stats
Object database:
Loose objects: 0
Pack files: 2
Total objects: 4,238
Rebuild object index
$ mediagit gc --rebuild-index
Rebuilding object database index...
Index statistics:
Objects indexed: 8,875
Chunks indexed: 2,847
Index size: 2.4 MB
Build time: 3.7s
Index verification: ✓ All objects accessible
Recompress with different level
$ mediagit gc --compress-level=9
Recompressing objects with Zstd level 9...
Compression analysis:
Current level: 3
New level: 9
Objects to recompress: 8,628
Recompression progress:
[============================] 100% (8,628/8,628)
Results:
Original compressed size: 485.3 MB (level 3)
New compressed size: 412.8 MB (level 9)
Additional savings: 72.5 MB (14.9%)
Compression time: 38.2s
Decompression impact: ~15% slower
Recommendation: Level 9 trades 15% slower access for 14.9% storage savings.
Verify during gc
$ mediagit gc --verify
Running garbage collection with verification...
Phase 1: Object enumeration and verification
Verifying checksums: 100% (8,875/8,875) ✓
Verifying chunk integrity: 100% (2,847/2,847) ✓
All objects verified successfully
Phase 2: Garbage collection
Objects removed: 247
Space reclaimed: 127.3 MB
Phase 3: Post-gc verification
Verifying object database: ✓
Verifying commit graph: ✓
Verifying refs: ✓
Garbage collection complete with full verification ✓
Auto mode
$ mediagit gc --auto
Repository does not need garbage collection yet.
(Last gc: 2 days ago, objects: 8,875, fragmentation: 12%)
Next gc recommended when:
- Objects > 10,000 OR
- Fragmentation > 25% OR
- Time since last gc > 1 week
Use 'mediagit gc' to run now anyway.
Quiet mode
$ mediagit gc --quiet
# No output, runs in background
# Check status with:
$ echo $?
0 # Success
Garbage Collection Phases
Phase 1: Object Enumeration
Enumerating objects: 8,875, done.
Scans repository to find all reachable objects from refs (branches, tags).
Phase 2: Unreachable Object Removal
Removing unreachable objects: 247
Deletes objects not reachable from any ref (orphaned by deleted branches, amended commits, etc.).
Phase 3: Object Compression
Compressing objects: 100% (4,238/4,238), done.
Compresses loose objects into efficient storage format.
Phase 4: Deduplication Optimization
Optimizing deduplication: 2,847 chunks
Identifies and removes duplicate chunks across files.
Phase 5: Commit Graph
Building commit graph: 100% (142/142), done.
Builds commit graph for fast traversal operations (log, merge-base, etc.).
When to Run GC
Automatic Triggers
MediaGit automatically suggests gc when:
- Loose objects > 1,000
- Repository fragmentation > 25%
- Time since last gc > 1 week
- Space waste > 500 MB
Manual Triggers
Run gc manually:
- After deleting large branches
- After rebasing or amending many commits
- Before pushing to save bandwidth
- Before archiving repository
- When storage costs are concern
Repack for Efficiency
Use --repack when:
- Space is limited (consolidates objects)
- Preparing for push (single pack file transfers faster)
- Before backup/archival (easier restoration)
- In CI/CD pipelines (regular maintenance)
Note: Repack is automatic during aggressive GC, can be run standalone
Performance Impact
During GC
Repository operations may be slower:
- Read operations: ~10-20% slower
- Write operations: Not recommended during gc
- Duration: 10s - 5 minutes depending on size
After GC
Repository operations are faster:
- Read operations: 20-40% faster
- Object retrieval: 30-50% faster
- Clone/fetch: Faster due to smaller size
- Push: Faster due to better compression
Storage Savings
Typical Savings
Small repository (<100 MB):
Unreachable objects: 5-15 MB
Better compression: 10-20 MB
Deduplication: 5-10 MB
Total savings: 20-45 MB (20-45%)
Medium repository (100 MB - 1 GB):
Unreachable objects: 50-150 MB
Better compression: 100-200 MB
Deduplication: 50-100 MB
Total savings: 200-450 MB (30-50%)
Large repository (>1 GB):
Unreachable objects: 100-500 MB
Better compression: 200-800 MB
Deduplication: 100-400 MB
Total savings: 400-1,700 MB (40-60%)
Configuration
[gc]
# Run gc automatically after certain operations
auto = true
# Threshold for auto gc (loose objects)
auto_limit = 1000
# Prune objects older than this
prune_expire = "2.weeks.ago"
# Aggressive compression
aggressive = false
# Verify during gc
verify = false
[gc.compression]
# Compression level (0-9)
level = 3
# Recompress during gc
recompress = false
# Target compression level
target_level = 3
[gc.dedup]
# Enable deduplication optimization
optimize = true
# Deduplication threshold
threshold = "4MB"
[gc.repack]
# Enable object repacking
enabled = true
# Maximum size per pack file (0 = unlimited)
max_size = 0
# Build delta chains during repack
build_deltas = true
[gc.performance]
# Parallel object processing
parallel = true
# Number of threads
threads = 4
Remote Storage Backends
S3 Storage
$ mediagit gc
Garbage collection for S3 backend...
Local cleanup:
Objects removed: 247
Space reclaimed: 127.3 MB
Remote cleanup:
Analyzing remote objects...
Orphaned objects: 89
Remote space reclaimed: 245.8 MB
Storage cost reduction: $0.0056/month
Note: Remote objects pruned after 30-day grace period
Azure/GCS Storage
Similar optimizations apply to all storage backends with additional benefits:
- Reduced API calls
- Lower storage costs
- Faster transfers
- Improved cache hit rates
Exit Status
- 0: GC completed successfully
- 1: GC failed or was interrupted
- 2: Invalid options
Best Practices
Regular Maintenance
# Weekly gc for active repositories
$ mediagit gc
# Monthly aggressive gc
$ mediagit gc --aggressive
# Before major operations
$ mediagit gc --verify
Before Sharing
# Optimize before push
$ mediagit gc
$ mediagit push
# Optimize before archive
$ mediagit gc --aggressive
$ tar czf repo-backup.tar.gz .mediagit/
After Bulk Operations
# After branch cleanup
$ mediagit branch -d old-feature-1 old-feature-2 old-feature-3
$ mediagit gc --prune=now
# After rebase/amend
$ mediagit rebase -i HEAD~10
$ mediagit gc
# After large file removal
$ mediagit rm large-file.mp4
$ mediagit commit -m "Remove large file"
$ mediagit gc --aggressive
Troubleshooting
GC Taking Too Long
# Use auto mode to check if needed
$ mediagit gc --auto
# Run with less aggressive settings
$ mediagit gc --no-prune
Disk Space Issues
# Aggressive cleanup
$ mediagit gc --aggressive --prune=now
# Verify space reclaimed
$ du -sh .mediagit/
Corrupted Objects
# Run gc with verification
$ mediagit gc --verify
# If corruption found
$ mediagit fsck
$ mediagit gc --rebuild-index
Notes
Safety
Garbage collection is safe:
- Never deletes reachable objects
- Maintains repository integrity
- Can be interrupted and resumed
- Verifies data when requested
Concurrent GC
MediaGit prevents concurrent gc:
$ mediagit gc
fatal: gc is already running (pid 1234)
hint: Use --force to run anyway (not recommended)
Media Repository Benefits
For media-heavy repositories, gc provides:
- Massive space savings (40-60% typical)
- Faster operations (20-40% improvement)
- Lower storage costs
- Better deduplication efficiency
- Improved cache performance
See Also
- mediagit fsck - Verify repository integrity
- mediagit prune - Prune unreachable objects
- mediagit verify - Verify object integrity
- mediagit stats - Show repository statistics
mediagit fsck
Verify integrity and connectivity of objects in repository.
Synopsis
mediagit fsck [OPTIONS] [<object>...]
Description
Verifies the connectivity and validity of objects in the repository database. Checks for:
- Corrupt or missing objects
- Broken links between objects
- Orphaned or unreachable objects
- Invalid object references
- Checksum mismatches
- Chunk integrity for media files
MediaGit fsck provides media-aware verification including chunk-level integrity checks, compression validation, and deduplication consistency.
Options
Verification Mode
--full
Perform complete verification of all objects (default).
--connectivity-only
Check only connectivity, skip detailed validation.
--dangling
Print dangling (unreachable but valid) objects.
--no-dangling
Suppress dangling object reports (default).
--unreachable
Show all unreachable objects.
--lost-found
Write dangling objects to .mediagit/lost-found/.
Object Selection
<object>...
Check specific objects instead of entire repository.
--cache
Check index file consistency.
--commit-graph
Verify commit graph integrity.
Output Options
-v, --verbose
Show detailed verification information.
--progress
Show progress during verification.
--no-progress
Suppress progress reporting.
-q, --quiet
Suppress all output except errors.
MediaGit-Specific Options
--verify-chunks
Verify chunk integrity and checksums.
--verify-compression
Validate compressed object integrity.
--verify-dedup
Check deduplication consistency.
--repair
Attempt to repair minor issues (use with caution).
Examples
Basic fsck
$ mediagit fsck
Checking object directory: .mediagit/objects
Checking objects: 100% (8,875/8,875), done.
Object verification:
Commits: 142 ✓
Trees: 1,847 ✓
Blobs: 6,886 ✓
Total: 8,875 objects verified
Connectivity check:
All objects reachable ✓
All refs valid ✓
No broken links found ✓
Repository integrity: OK
Full verification with chunks
$ mediagit fsck --verify-chunks
Checking object directory: .mediagit/objects
Checking objects: 100% (8,875/8,875), done.
Object verification:
Commits: 142 ✓
Trees: 1,847 ✓
Blobs: 6,886 ✓
Chunk verification:
Total chunks: 2,847
Verifying checksums: 100% (2,847/2,847) ✓
Verifying integrity: 100% (2,847/2,847) ✓
Corrupted chunks: 0 ✓
Deduplication verification:
Duplicate references: 847
Reference consistency: 100% ✓
No dedup errors ✓
Repository integrity: OK
Show dangling objects
$ mediagit fsck --dangling
Checking objects: 100% (8,875/8,875), done.
Dangling objects:
dangling commit a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
dangling blob b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
dangling tree c5e9f2b4764f2dbcee52635b91fedb1b3dcf7ab4d5e6f7a8b9c0d1e2f3a4b5c6d7e8
Total dangling objects: 3 (127.3 MB)
hint: Run 'mediagit fsck --lost-found' to save these objects
hint: Run 'mediagit gc' to remove dangling objects
Show unreachable objects
$ mediagit fsck --unreachable
Checking objects: 100% (8,875/8,875), done.
Unreachable objects:
unreachable commit a3c8f9d (from deleted branch 'feature/old')
Author: Alice <alice@example.com>
Date: 2024-01-10
Message: "Old feature work"
Size: 2.3 KB
unreachable blob b4d7e1a (deleted file 'old-video.mp4')
Size: 245.8 MB (compressed to 42.1 MB)
unreachable tree c5e9f2b
Size: 1.2 KB
Total unreachable: 3 objects (245.8 MB original, 42.1 MB stored)
hint: These objects will be pruned by 'mediagit gc --prune'
Lost-found recovery
$ mediagit fsck --lost-found
Checking objects: 100% (8,875/8,875), done.
Dangling objects written to .mediagit/lost-found/:
commit/a3c8f9d
blob/b4d7e1a
tree/c5e9f2b
3 objects saved for recovery
Verify specific objects
$ mediagit fsck HEAD main feature/video-optimization
Checking specified objects...
HEAD (a3c8f9d):
Type: commit ✓
Tree: valid ✓
Parents: valid ✓
Author/Committer: valid ✓
main (a3c8f9d):
Points to valid commit ✓
feature/video-optimization (b4d7e1a):
Points to valid commit ✓
3 objects verified, all OK
Verify index
$ mediagit fsck --cache
Checking index file...
Index statistics:
Version: 2
Entries: 247
Size: 12.4 KB
Index verification:
Entry checksums: 100% (247/247) ✓
Object references: 100% (247/247) ✓
Path ordering: valid ✓
Extension data: valid ✓
Index integrity: OK
Verify commit graph
$ mediagit fsck --commit-graph
Checking commit graph...
Commit graph statistics:
Version: 1
Commits: 142
Size: 24.7 KB
Commit graph verification:
Commit OIDs: 100% (142/142) ✓
Parent links: 100% (128/128) ✓
Generation numbers: valid ✓
Bloom filters: valid ✓
Commit graph integrity: OK
Verbose output
$ mediagit fsck -v
Checking object directory: .mediagit/objects
Checking objects: 100% (8,875/8,875), done.
Detailed verification:
Commits (142):
Checking commit a3c8f9d... OK
Checking commit b4d7e1a... OK
[140 more commits]
All commits valid ✓
Trees (1,847):
Checking tree c5e9f2b... OK
Checking tree d6f0a3c... OK
[1,845 more trees]
All trees valid ✓
Blobs (6,886):
Checking blob e7g1b4d... OK (video.mp4, 42.1 MB)
Checking blob f8h2c5e... OK (image.jpg, 0.8 MB)
[6,884 more blobs]
All blobs valid ✓
Connectivity:
Checking refs... 5 refs checked ✓
Checking reflog... 42 entries checked ✓
Checking HEAD... valid ✓
No errors found
Repository integrity: EXCELLENT
Compression verification
$ mediagit fsck --verify-compression
Checking objects: 100% (8,875/8,875), done.
Compression verification:
Total compressed objects: 6,886
Decompression test: 100% (6,886/6,886) ✓
Checksum validation: 100% (6,886/6,886) ✓
Compression ratio verification: ✓
Compression statistics:
Average ratio: 82.3%
Corrupted objects: 0 ✓
Invalid compression: 0 ✓
All compression valid ✓
Deduplication verification
$ mediagit fsck --verify-dedup
Checking objects: 100% (8,875/8,875), done.
Deduplication verification:
Total chunks: 2,847
Chunk references: 8,472
Duplicate chunks: 847
Dedup consistency checks:
Reference integrity: 100% (8,472/8,472) ✓
Chunk checksums: 100% (2,847/2,847) ✓
Reference counts: valid ✓
No orphaned chunks: ✓
Deduplication savings: 2.3 GB (45.2%)
All dedup structures valid ✓
Repair mode (cautious)
$ mediagit fsck --repair
WARNING: Repair mode may modify repository
Create backup before proceeding? [y/N] y
Creating backup...
Backup created: .mediagit-backup-20240115-143022
Checking objects: 100% (8,875/8,875), done.
Issues found:
Missing chunk reference in blob e7g1b4d
Attempting repair... SUCCESS ✓
Invalid checksum in blob f8h2c5e
Attempting repair from backup... SUCCESS ✓
Repairs completed: 2
Failed repairs: 0
Re-verifying repository...
Repository integrity: OK
Backup location: .mediagit-backup-20240115-143022
Error Detection
Corrupt Object
$ mediagit fsck
Checking objects: 100% (8,875/8,875), done.
ERROR: Corrupt blob b4d7e1a
Expected checksum: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Actual checksum: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
File: video.mp4
Size: 245.8 MB
Repository integrity: DAMAGED
Run 'mediagit fsck --repair' to attempt recovery
Missing Object
$ mediagit fsck
Checking objects: 100% (8,875/8,875), done.
ERROR: Missing blob c5e9f2b
Referenced by: tree d6f0a3c
Path: assets/logo.png
Expected size: 156.3 KB
ERROR: Broken link in tree d6f0a3c
Missing child: c5e9f2b
Repository integrity: DAMAGED
2 errors found
Broken Chain
$ mediagit fsck
Checking connectivity...
ERROR: Broken chain detected
Commit a3c8f9d references parent b4d7e1a
Parent b4d7e1a: NOT FOUND
ERROR: Unreachable commit d6f0a3c
Orphaned by broken chain
Repository integrity: DAMAGED
Verification Levels
Quick (Connectivity Only)
$ mediagit fsck --connectivity-only
Quick verification: Checking reachability only
Checking refs: 100% (5/5), done.
All refs reachable ✓
Repository connectivity: OK
Note: Run full fsck to verify object integrity
Standard (Default)
$ mediagit fsck
Full verification with checksum validation
Time: 10-30 seconds for typical repository
Complete (All Checks)
$ mediagit fsck --verify-chunks --verify-compression --verify-dedup -v
Comprehensive verification including media-specific checks
Time: 30-120 seconds for large media repository
Performance
Small Repository (<100 MB)
Objects: < 1,000
Time: 1-3 seconds
Medium Repository (100 MB - 1 GB)
Objects: 1,000-10,000
Time: 5-15 seconds
Large Repository (>1 GB)
Objects: 10,000+
Time: 30-120 seconds
With --verify-chunks: 2-5 minutes
Exit Status
- 0: No errors found, repository OK
- 1: Errors detected, repository damaged
- 2: Invalid options or fsck failed to run
Configuration
[fsck]
# Verify chunks by default
verify_chunks = false
# Verify compression
verify_compression = false
# Verify deduplication
verify_dedup = false
# Show dangling objects
show_dangling = false
# Progress reporting
show_progress = true
[fsck.repair]
# Allow automatic repair
auto_repair = false
# Create backup before repair
backup_before_repair = true
# Repair attempts
max_attempts = 3
Best Practices
Regular Checks
# Weekly fsck for active repositories
$ mediagit fsck
# Monthly comprehensive check
$ mediagit fsck --verify-chunks --verify-compression --verify-dedup
Before Important Operations
# Before backup
$ mediagit fsck --verify-chunks
$ tar czf backup.tar.gz .mediagit/
# Before migration
$ mediagit fsck --full
$ mediagit push --mirror new-remote
After Errors
# After system crash
$ mediagit fsck --verify-chunks
$ mediagit gc --verify
# After transfer interruption
$ mediagit fsck
$ mediagit pull --verify-checksums
Troubleshooting
Corrupt Objects Found
# Try repair
$ mediagit fsck --repair
# If repair fails, restore from backup
$ cp -r .mediagit-backup/* .mediagit/
$ mediagit fsck
Missing Objects
# Check if available in remote
$ mediagit fetch
$ mediagit fsck
# Restore from lost-found
$ mediagit fsck --lost-found
$ ls .mediagit/lost-found/
Performance Issues
# Quick check first
$ mediagit fsck --connectivity-only
# Full check if quick check passes
$ mediagit fsck
Notes
Safety
fsck is safe and read-only by default:
- Never modifies repository without –repair
- Can be run at any time
- Does not interfere with other operations
- Creates backups before repairs
Media Repository Checks
For media-heavy repositories:
- Chunk verification essential for integrity
- Compression validation ensures quality
- Deduplication checks prevent storage waste
- Regular fsck prevents gradual corruption
Automation
# Daily fsck in CI/CD
$ mediagit fsck --quiet && echo "Repository OK" || echo "INTEGRITY ERROR"
# Weekly comprehensive check
$ mediagit fsck --verify-chunks --verify-compression
See Also
- mediagit gc - Garbage collection and optimization
- mediagit verify - Verify specific objects
- mediagit stats - Repository statistics
- mediagit prune - Prune unreachable objects
mediagit verify
Verify integrity of specific objects or files.
Synopsis
mediagit verify [COMMIT]
mediagit verify [OPTIONS] --path <file>...
Description
Verifies the integrity of a commit and its reachable objects, or specific files. Unlike fsck
which checks the entire repository, verify can target a single commit (OID, abbreviated hash,
branch name, or HEAD) or individual files for quick validation.
Useful for:
- Verifying specific media files after download
- Checking object integrity before important operations
- Validating chunks after recovery
- Confirming successful transfers
- Quick integrity spot-checks
Options
Verification Mode
--full
Perform complete verification including chunk integrity.
--quick
Quick checksum validation only (default).
--deep
Deep verification with decompression and content validation.
Target Selection
<object>...
Verify specific object OIDs.
--path <file>...
Verify files in working tree.
--staged
Verify files in staging area.
--commit <commit>
Verify all objects in specified commit.
--tree <tree>
Verify all objects in specified tree.
Output Options
-v, --verbose
Show detailed verification information.
-q, --quiet
Suppress output except errors.
--json
Output results in JSON format.
MediaGit-Specific Options
--verify-chunks
Verify chunk integrity for large files.
--verify-compression
Validate compression integrity.
--verify-metadata
Check media metadata consistency.
--parallel=<n>
Number of parallel verification threads.
Examples
Verify specific object
$ mediagit verify a3c8f9d
Verifying object a3c8f9d...
Object: a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Type: commit
Size: 2.3 KB
Checksum: ✓ Valid
Object verification: OK
Verify multiple objects
$ mediagit verify a3c8f9d b4d7e1a c5e9f2b
Verifying 3 objects...
a3c8f9d (commit): ✓ Valid
b4d7e1a (blob): ✓ Valid
c5e9f2b (tree): ✓ Valid
All objects verified successfully
Verify file in working tree
$ mediagit verify --path video.mp4
Verifying file: video.mp4
File information:
Path: video.mp4
Size: 245.8 MB
Type: video/mp4
Object reference:
OID: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Stored size: 42.1 MB (compressed)
Compression: 82.9%
Verification:
Checksum: ✓ Valid
Content match: ✓ Identical
File verification: OK
Verify with chunks
$ mediagit verify --verify-chunks b4d7e1a
Verifying blob b4d7e1a with chunk integrity check...
Object information:
Type: blob
File: video.mp4
Size: 245.8 MB
Compressed: 42.1 MB
Chunk verification:
Total chunks: 63
Verifying checksums: 100% (63/63) ✓
Verifying content: 100% (63/63) ✓
Decompression test: ✓ All chunks valid
Chunk integrity: EXCELLENT
Verify entire commit
$ mediagit verify --commit HEAD
Verifying commit HEAD (a3c8f9d)...
Commit verification:
Commit object: ✓ Valid
Tree: ✓ Valid
Parents: ✓ Valid (1 parent)
Author/Committer: ✓ Valid
Tree contents (247 objects):
Checking trees: 100% (47/47) ✓
Checking blobs: 100% (200/200) ✓
All objects in commit verified successfully
Deep verification
$ mediagit verify --deep b4d7e1a
Deep verification of blob b4d7e1a...
Object validation:
Checksum: ✓ Valid
Size: ✓ Matches expected (245.8 MB)
Compression validation:
Decompression test: ✓ Success
Recompression test: ✓ Matches original
Compression integrity: ✓ Perfect
Content validation:
Format: video/mp4
Codec: H.264/AVC
Container: Valid MP4
Media integrity: ✓ Playable
Deep verification: PASSED
Verify staged files
$ mediagit verify --staged
Verifying staged files...
Staged files (5):
video.mp4: ✓ Valid (245.8 MB → 42.1 MB)
image.jpg: ✓ Valid (2.4 MB → 0.8 MB)
audio.wav: ✓ Valid (45.2 MB → 8.7 MB)
config.json: ✓ Valid (1.2 KB)
README.md: ✓ Valid (4.5 KB)
All staged files verified
Verify with metadata
$ mediagit verify --verify-metadata --path video.mp4
Verifying file: video.mp4 with metadata check
File verification:
Checksum: ✓ Valid
Size: ✓ Matches (245.8 MB)
Metadata verification:
Format: MP4
Video codec: H.264/AVC ✓
Audio codec: AAC ✓
Duration: 00:03:45 ✓
Resolution: 1920x1080 ✓
Frame rate: 29.97 fps ✓
Bitrate: 8.5 Mbps ✓
Metadata stored vs actual:
All metadata matches ✓
No corruption detected ✓
Complete verification: PASSED
Parallel verification
$ mediagit verify --parallel=8 --commit HEAD~5..HEAD
Verifying commits HEAD~5..HEAD with 8 threads...
Parallel verification (8 threads):
Thread 1: 38 objects ✓
Thread 2: 42 objects ✓
Thread 3: 35 objects ✓
Thread 4: 41 objects ✓
Thread 5: 37 objects ✓
Thread 6: 39 objects ✓
Thread 7: 36 objects ✓
Thread 8: 40 objects ✓
Total: 308 objects verified in 2.3s
All objects valid ✓
Verbose output
$ mediagit verify -v b4d7e1a
Detailed verification of blob b4d7e1a...
Object Header:
Type: blob
Size: 245,787,392 bytes
Compressed size: 42,143,128 bytes
Compression ratio: 82.9%
Compression algorithm: Zstd level 3
Checksum Verification:
Algorithm: SHA-256
Expected: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Computed: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Result: ✓ MATCH
Chunk Structure:
Chunk size: 4 MB
Total chunks: 63
Last chunk: 2,787,392 bytes
Decompression Test:
Decompressing: 100% (42.1 MB → 245.8 MB)
Result: ✓ Success
Time: 1.2s
Content Hash:
Rehashing decompressed content...
Hash: b4d7e1a9... ✓ Matches original
Verification: COMPLETE
Status: VALID
JSON output
$ mediagit verify --json b4d7e1a
{
"object": "b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9",
"type": "blob",
"size": 245787392,
"compressed_size": 42143128,
"compression_ratio": 0.829,
"checksum_valid": true,
"decompression_valid": true,
"chunks": {
"total": 63,
"verified": 63,
"corrupted": 0
},
"status": "valid",
"verification_time_ms": 1247
}
Quiet mode
$ mediagit verify --quiet b4d7e1a c5e9f2b
$ echo $?
0 # Success (all valid)
$ mediagit verify --quiet corrupted-object
$ echo $?
1 # Failure (invalid object)
Verification Levels
Quick (Default)
Verification: Checksum only
Time: < 10ms per object
Use case: Fast spot-checks
Full
Verification: Checksum + chunk integrity
Time: 50-100ms per MB
Use case: After downloads, before operations
Deep
Verification: Full + decompression + content validation
Time: 100-200ms per MB
Use case: After recovery, corruption investigation
Error Detection
Corrupt Object
$ mediagit verify b4d7e1a
Verifying object b4d7e1a...
ERROR: Checksum mismatch
Expected: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
Actual: b4d7e1a9f2c3d4e5f6a7b8c9d0e1f2a3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Object verification: FAILED
Missing Chunks
$ mediagit verify --verify-chunks b4d7e1a
Verifying blob b4d7e1a with chunks...
ERROR: Missing chunks detected
Total chunks: 63
Present: 60
Missing: 3 (chunks 23, 47, 58)
Chunk verification: FAILED
Missing data: 12 MB
Compression Corruption
$ mediagit verify --verify-compression b4d7e1a
Verifying compression integrity...
ERROR: Decompression failed
Chunk: 23
Compressed size: 4,194,304 bytes
Error: Invalid compressed data
Compression verification: FAILED
Use Cases
After Download
# Verify after pull
$ mediagit pull
$ mediagit verify --commit HEAD
# Verify specific large file
$ mediagit verify --path video.mp4 --verify-chunks
Before Important Operations
# Before commit
$ mediagit verify --staged
# Before push
$ mediagit verify --commit HEAD
Corruption Investigation
# Deep check of suspected file
$ mediagit verify --deep --verify-chunks video.mp4
# Verify entire branch
$ mediagit verify --commit main
Batch Verification
# Verify all media files
$ find . -name "*.mp4" -exec mediagit verify --path {} \;
# Verify recent commits
$ mediagit verify --commit HEAD~10..HEAD
Performance
Quick Verification
Single object: < 10ms
100 objects: < 1s
1000 objects: < 10s
Full Verification (with chunks)
Small file (<10 MB): 100-200ms
Medium file (10-100 MB): 1-5s
Large file (>100 MB): 5-20s
Deep Verification
Small file: 200-500ms
Medium file: 2-10s
Large file: 10-60s
Exit Status
- 0: All objects valid
- 1: One or more objects invalid or corrupted
- 2: Invalid options or verification failed to run
Configuration
[verify]
# Default verification level
level = "quick" # quick | full | deep
# Verify chunks by default
verify_chunks = false
# Verify compression
verify_compression = false
# Verify metadata
verify_metadata = false
# Parallel threads
parallel = 4
# Show progress
show_progress = true
Best Practices
Regular Spot-Checks
# Daily verification of recent work
$ mediagit verify --commit HEAD~5..HEAD
# Weekly verification of large files
$ mediagit verify --verify-chunks --path *.mp4
After Transfers
# After pull
$ mediagit pull
$ mediagit verify --commit FETCH_HEAD
# After clone
$ mediagit clone <url>
$ cd <repo>
$ mediagit verify --commit HEAD --verify-chunks
Before Critical Operations
# Before backup
$ mediagit verify --commit HEAD --full
$ tar czf backup.tar.gz .mediagit/
# Before migration
$ mediagit verify --commit --all
$ mediagit push --mirror new-remote
Troubleshooting
Verification Fails
# Try deep verification for more info
$ mediagit verify --deep <object>
# Check fsck for repository-wide issues
$ mediagit fsck
# Attempt recovery
$ mediagit fsck --repair
Slow Verification
# Use quick mode
$ mediagit verify --quick <object>
# Reduce parallelism
$ mediagit verify --parallel=2 <objects>
# Verify without chunks
$ mediagit verify --path <file> # skip --verify-chunks
Notes
Safety
Verify is read-only and safe:
- Never modifies repository
- Can be run at any time
- Does not interfere with other operations
- Useful for automated checks
Verify vs Fsck
- verify: Specific objects, quick, targeted
- fsck: Entire repository, comprehensive, slower
Use verify for spot-checks, fsck for complete validation.
Media Files
For media-heavy repositories:
- Quick verification (checksum) is usually sufficient
- Use
--verify-chunksafter downloads - Use
--deeponly when investigating corruption - Batch verification with
--parallelfor efficiency
See Also
- mediagit fsck - Full repository verification
- mediagit gc - Garbage collection with verification
- mediagit stats - Repository statistics
- mediagit show - Show object contents
mediagit stats
Display repository statistics and metrics.
Synopsis
mediagit stats [OPTIONS] [<path>...]
Description
Shows comprehensive statistics about the repository including:
- Object counts and sizes
- Compression ratios and savings
- Deduplication effectiveness
- Storage backend information
- Performance metrics
- Commit history analysis
Particularly useful for:
- Understanding repository growth
- Analyzing storage efficiency
- Identifying optimization opportunities
- Capacity planning
- Cost analysis for cloud storage
Options
Report Scope
--all
Show all available statistics (default).
--objects
Show object database statistics only.
--compression
Show compression statistics only.
--dedup
Show deduplication statistics only.
--commits
Show commit history statistics only.
--storage
Show storage backend statistics only.
Analysis Depth
--detailed
Show detailed breakdown by type and category.
--summary
Show high-level summary only.
--trends
Include historical trends and growth analysis.
Path Filtering
<path>...
Show statistics for specific paths only.
--branch=<branch>
Analyze specific branch.
--since=<date>
Statistics since specified date.
--until=<date>
Statistics until specified date.
Output Format
--human-readable, -h
Use human-readable sizes (default).
--bytes
Show sizes in bytes.
--json
Output in JSON format.
--csv
Output in CSV format for analysis.
MediaGit-Specific Options
--media-analysis
Include media-specific statistics (formats, codecs, resolutions).
--chunk-analysis
Show chunk-level statistics and efficiency.
--cost-analysis
Show estimated storage costs by backend.
Examples
Basic statistics
$ mediagit stats
MediaGit Repository Statistics
================================
Repository Overview:
Location: /path/to/repo
Created: 2024-01-01
Age: 15 days
Branches: 5
Commits: 142
Object Database:
Total objects: 8,875
Commits: 142
Trees: 1,847
Blobs: 6,886
Object size: 3.2 GB (original)
Stored size: 485.3 MB (compressed)
Compression ratio: 84.8%
Deduplication:
Total chunks: 2,847
Unique chunks: 2,000
Duplicate chunks: 847 (29.8%)
Space saved: 267.4 MB (11.6%)
Effective compression: 87.2%
Storage Backend:
Type: AWS S3
Region: us-west-2
Bucket: mediagit-prod-assets
Objects stored: 8,875
Estimated cost: $0.0112/month
Compression statistics
$ mediagit stats --compression
Compression Statistics
======================
Overview:
Algorithm: Zstd (level 3)
Total objects: 8,875
Compressed objects: 6,886
Uncompressed objects: 1,989 (commits, trees)
Size Analysis:
Original size: 3.2 GB
Compressed size: 485.3 MB
Compression ratio: 84.8%
Space saved: 2.7 GB
By File Type:
Video files (mp4, mov, avi):
Count: 47
Original: 2.8 GB
Compressed: 398.7 MB
Ratio: 85.8%
Image files (jpg, png, psd):
Count: 123
Original: 347.2 MB
Compressed: 78.4 MB
Ratio: 77.4%
Audio files (wav, mp3):
Count: 18
Original: 89.5 MB
Compressed: 16.8 MB
Ratio: 81.2%
Compression Performance:
Average compression time: 0.8s per 100 MB
Average decompression time: 0.2s per 100 MB
Throughput: 125 MB/s (compression)
Throughput: 500 MB/s (decompression)
Deduplication statistics
$ mediagit stats --dedup
Deduplication Statistics
========================
Chunk Analysis:
Total chunks: 2,847
Unique chunks: 2,000 (70.2%)
Duplicate chunks: 847 (29.8%)
Chunk size: 4 MB (standard)
Deduplication Savings:
Total data: 2.9 GB (chunked)
Unique data: 2.6 GB
Duplicate data: 267.4 MB
Space saved: 267.4 MB (9.2%)
Deduplication Patterns:
Single reference: 1,423 chunks (71.2%)
2-5 references: 412 chunks (20.6%)
6-10 references: 127 chunks (6.4%)
>10 references: 38 chunks (1.9%)
Most Deduplicated Chunk:
Chunk: a8b9c0d1e2f3...
Size: 4 MB
References: 23
Savings: 88 MB
Files: video_1080p.mp4, video_720p.mp4, video_480p.mp4 (intro sequence)
Efficiency:
Deduplication ratio: 9.2%
Combined with compression: 87.2% total efficiency
Commit history statistics
$ mediagit stats --commits
Commit History Statistics
=========================
Overview:
Total commits: 142
First commit: 2024-01-01 10:30:00
Latest commit: 2024-01-15 14:30:22
Time span: 15 days
Commit Activity:
Commits per day: 9.5 (average)
Busiest day: 2024-01-10 (23 commits)
Quietest day: 2024-01-03 (2 commits)
Contributors:
Total contributors: 3
1. Alice Developer: 89 commits (62.7%)
2. Bob Designer: 47 commits (33.1%)
3. Charlie Editor: 6 commits (4.2%)
Commit Size Distribution:
Small (<10 MB): 78 commits (54.9%)
Medium (10-100 MB): 52 commits (36.6%)
Large (>100 MB): 12 commits (8.5%)
Largest commit: a3c8f9d (410.2 MB original, 75.9 MB stored)
Smallest commit: e7g1b4d (1.2 KB)
Storage Growth:
Starting size: 0 MB
Current size: 485.3 MB
Growth rate: 32.4 MB/day
Projected (30 days): 970.7 MB
Projected (90 days): 2.9 GB
Storage backend statistics
$ mediagit stats --storage
Storage Backend Statistics
==========================
Backend Configuration:
Type: AWS S3
Region: us-west-2
Bucket: mediagit-prod-assets
Storage class: Standard
Versioning: Disabled
Encryption: AES-256
Storage Usage:
Total objects: 8,875
Total size: 485.3 MB
Largest object: 145.2 MB
Smallest object: 128 bytes
Average object: 54.7 KB
Transfer Statistics (last 30 days):
Uploads: 247 objects (342.8 MB)
Downloads: 89 objects (127.3 MB)
Data transfer: 470.1 MB total
Cost Analysis:
Storage cost: $0.0112/month
Request cost: $0.0003/month
Transfer cost: $0.0021/month
Total cost: $0.0136/month
Projected (1 year): $0.16
Cost per GB: $0.023
Performance Metrics:
Average upload speed: 8.2 MB/s
Average download speed: 9.4 MB/s
Average latency: 45ms
Media analysis
$ mediagit stats --media-analysis
Media File Analysis
===================
Overview:
Total media files: 188
Total size: 2.8 GB (original)
Stored size: 423.9 MB (compressed)
Video Files (47):
Formats: MP4 (35), MOV (8), AVI (4)
Total size: 2.4 GB → 398.7 MB
Resolutions:
4K (3840x2160): 8 files (1.2 GB)
1080p (1920x1080): 23 files (945.3 MB)
720p (1280x720): 12 files (234.7 MB)
480p (854x480): 4 files (67.2 MB)
Codecs:
H.265/HEVC: 18 files (better compression)
H.264/AVC: 27 files (wider compatibility)
Other: 2 files
Duration Distribution:
<1 minute: 12 files
1-5 minutes: 28 files
>5 minutes: 7 files
Total duration: 3 hours 47 minutes
Image Files (123):
Formats: JPEG (89), PNG (28), PSD (6)
Total size: 347.2 MB → 78.4 MB
Resolutions:
>4K: 12 files
1080p-4K: 47 files
<1080p: 64 files
Audio Files (18):
Formats: WAV (12), MP3 (6)
Total size: 89.5 MB → 16.8 MB
Sample rates: 44.1 kHz (12), 48 kHz (6)
Bit depths: 16-bit (12), 24-bit (6)
Detailed statistics
$ mediagit stats --detailed
Detailed Repository Statistics
===============================
[... includes all above sections plus ...]
Object Type Breakdown:
Commits:
Count: 142
Average size: 2.3 KB
Total size: 326.6 KB
Trees:
Count: 1,847
Average size: 847 bytes
Total size: 1.5 MB
Blobs:
Small (<1 MB): 6,234 blobs (89.2 MB)
Medium (1-10 MB): 478 blobs (2.1 GB)
Large (>10 MB): 174 blobs (1.0 GB)
Total: 6,886 blobs (3.2 GB)
Chunk Distribution:
0-10 references: 1,835 chunks (91.8%)
11-20 references: 127 chunks (6.4%)
21-30 references: 32 chunks (1.6%)
>30 references: 6 chunks (0.3%)
Performance Characteristics:
Index size: 2.4 MB
Commit graph size: 24.7 KB
Reflog size: 8.2 KB
Average lookup time: 0.3ms
Cache hit rate: 92.3%
Trend analysis
$ mediagit stats --trends --since="1 week ago"
Repository Trends (Last 7 Days)
================================
Growth Analysis:
Starting size: 398.2 MB
Current size: 485.3 MB
Growth: +87.1 MB (+21.9%)
Daily average: +12.4 MB
Commit Activity Trend:
Day 1: 8 commits (45.2 MB)
Day 2: 12 commits (67.8 MB)
Day 3: 6 commits (23.4 MB)
Day 4: 15 commits (89.7 MB)
Day 5: 9 commits (34.5 MB)
Day 6: 11 commits (56.3 MB)
Day 7: 7 commits (28.9 MB)
Compression Efficiency Trend:
Day 1: 82.1% compression
Day 2: 83.5% compression
Day 3: 84.2% compression
Day 4: 83.8% compression
Day 5: 84.7% compression
Day 6: 85.1% compression
Day 7: 84.9% compression
Trend: Improving (+2.8%)
Deduplication Trend:
Week start: 8.2% dedup savings
Week end: 9.2% dedup savings
Trend: Improving (+1.0%)
JSON output
$ mediagit stats --json
{
"repository": {
"location": "/path/to/repo",
"created": "2024-01-01T10:30:00Z",
"age_days": 15,
"branches": 5,
"commits": 142
},
"objects": {
"total": 8875,
"commits": 142,
"trees": 1847,
"blobs": 6886,
"original_size": 3435973836,
"stored_size": 509012992,
"compression_ratio": 0.848
},
"deduplication": {
"total_chunks": 2847,
"unique_chunks": 2000,
"duplicate_chunks": 847,
"savings_bytes": 280475648,
"dedup_ratio": 0.092
},
"storage_backend": {
"type": "s3",
"region": "us-west-2",
"bucket": "mediagit-prod-assets",
"cost_per_month_usd": 0.0136
}
}
Path-specific statistics
$ mediagit stats videos/
Statistics for path: videos/
Objects: 47 files
Original size: 2.4 GB
Stored size: 398.7 MB
Compression: 83.4%
File breakdown:
promo_4k.mp4: 856.3 MB → 145.2 MB (83.0%)
promo_1080p.mp4: 245.8 MB → 42.1 MB (82.9%)
training_*.mp4: 1.2 GB → 189.3 MB (84.2%)
[44 more files]
Deduplication savings: 45.2 MB (18.9%)
Cost Analysis
$ mediagit stats --cost-analysis
Storage Cost Analysis
=====================
Current Costs (Monthly):
AWS S3 Standard:
Storage: $0.0112 (485.3 MB @ $0.023/GB)
Requests: $0.0003 (247 PUT, 89 GET)
Transfer: $0.0021 (470.1 MB @ $0.09/GB)
Total: $0.0136/month
Projected Costs:
1 month: $0.014
3 months: $0.042
6 months: $0.084
1 year: $0.168
Alternative Storage Classes:
S3 Infrequent Access: $0.0081/month (40% savings)
S3 Glacier: $0.0023/month (83% savings)
S3 Deep Archive: $0.0005/month (96% savings)
Cost Optimization Recommendations:
1. Run gc: Potential savings $0.0032/month
2. Use S3 IA for old objects: Savings $0.0054/month
3. Enable lifecycle policy: Savings $0.0089/month
Total potential savings: $0.0175/month (128%)
Performance
Statistics generation is fast:
- Summary: < 100ms
- Detailed: < 500ms
- Full analysis (all options): < 2s
- Trends (historical): < 5s
Exit Status
- 0: Statistics generated successfully
- 1: Error generating statistics
- 2: Invalid options
Configuration
[stats]
# Default output format
format = "human" # human | json | csv
# Show detailed stats by default
detailed = false
# Include trends
include_trends = false
# Cache statistics
cache_enabled = true
cache_ttl = "5 minutes"
[stats.display]
# Use colors in output
color = true
# Show ASCII charts
charts = true
# Number precision
precision = 1
Best Practices
Regular Monitoring
# Weekly stats check
$ mediagit stats --summary
# Monthly detailed analysis
$ mediagit stats --detailed --trends
Before/After Comparison
# Before optimization
$ mediagit stats > stats-before.txt
# Run optimization
$ mediagit gc --aggressive
# After optimization
$ mediagit stats > stats-after.txt
$ diff stats-before.txt stats-after.txt
Capacity Planning
# Analyze growth trends
$ mediagit stats --trends --since="30 days ago"
# Project future size
$ mediagit stats --commits --detailed
# Calculate: current_size + (daily_growth * days_ahead)
Cost Optimization
# Analyze costs
$ mediagit stats --cost-analysis
# Identify optimization opportunities
$ mediagit gc
$ mediagit stats --cost-analysis # Compare savings
Notes
Accuracy
Statistics are accurate as of last gc:
- Run
mediagit gcfor most accurate stats - Statistics cached for performance (5 min TTL)
- Use
--forceto bypass cache
Media Repository Benefits
For media-heavy repositories, stats reveal:
- Compression effectiveness by media type
- Deduplication opportunities
- Storage cost trends
- Growth patterns
Helps optimize:
- Compression settings
- Storage backend selection
- Garbage collection schedule
- Cost management
See Also
- mediagit gc - Optimize repository
- mediagit fsck - Verify integrity
- mediagit verify - Verify specific objects
- mediagit log - Show commit history with storage stats
mediagit reflog
Show the history of HEAD and branch movements.
Synopsis
mediagit reflog [OPTIONS] [REF]
mediagit reflog expire
mediagit reflog delete
Description
The reflog records every time HEAD or a branch pointer moves — including commits, merges, rebases, resets, checkouts, and cherry-picks. It is the safety net for recovering from accidental resets and history rewrites.
Reflog entries are local to your repository and not shared when pushing.
Arguments
[REF]
Reference to show the reflog for (default: HEAD). Examples: main,
feature/vfx, HEAD.
Options
-n <COUNT>, --count <COUNT>
Limit output to the most recent N entries.
-q, --quiet
Show only OIDs without messages.
Subcommands
expire
Remove reflog entries older than the configured retention period (default: 90 days).
delete
Remove all reflog entries for a specific ref.
Examples
View HEAD reflog
$ mediagit reflog
HEAD@{0} abc1234 reset: moving to HEAD~1
HEAD@{1} def5678 commit: Add hero texture v3
HEAD@{2} ghi9012 cherry-pick: Pick lighting fix
HEAD@{3} jkl3456 merge: Merge branch 'feature/audio'
HEAD@{4} mno7890 checkout: switching from main to feature/audio
Limit to recent entries
$ mediagit reflog --count 5
View reflog for a branch
$ mediagit reflog main
main@{0} abc1234 reset: moving to HEAD~1
main@{1} def5678 commit: Add hero texture v3
Recover from accidental reset
# Accidentally reset too far back
$ mediagit reset --hard HEAD~5
# Find the lost commit in the reflog
$ mediagit reflog --count 10
HEAD@{0} oldoid reset: moving to HEAD~5
HEAD@{1} abc1234 commit: Add final render pass (THIS IS WHAT WE WANT)
# Restore
$ mediagit reset --hard HEAD@{1}
HEAD is now at abc1234 Add final render pass
Recover after accidental branch deletion
# View reflog to find the last commit on the deleted branch
$ mediagit reflog
...
HEAD@{3} abc1234 checkout: moving from feature/vfx to main
# Recreate the branch at that commit
$ mediagit branch create feature/vfx abc1234
When Reflog Entries Are Created
commit— New commit createdreset— Branch pointer moved withresetcheckout— Switched branch withbranch switchmerge— Branches mergedrebase— Commits rebasedcherry-pick— Commits applied via cherry-pickrevert— Revert commit created
Exit Status
- 0: Success
- 1: Ref not found or reflog is empty
See Also
- mediagit reset - Reset branch (use reflog to recover)
- mediagit log - Show commit history
- mediagit branch - Manage branches
Architecture Overview
MediaGit-Core is designed as a modular, extensible version control system optimized for large media files. The architecture follows a layered approach with clear separation of concerns.
System Architecture
graph TB
CLI[CLI Layer<br/>clap commands] --> Core[Core Logic Layer]
Core --> ODB[Object Database<br/>ODB]
Core --> Versioning[Versioning Engine<br/>Merge/LCA]
Core --> Media[Media Intelligence<br/>PSD/Video/Audio]
ODB --> Storage[Storage Abstraction<br/>trait Backend]
Versioning --> Storage
Storage --> Compression[Compression Layer<br/>zstd/brotli/delta]
Compression --> Local[Local Storage]
Compression --> S3[Amazon S3]
Compression --> Azure[Azure Blob]
Compression --> GCS[Google Cloud Storage]
Compression --> B2[Backblaze B2]
Compression --> MinIO[MinIO]
Compression --> Spaces[DigitalOcean Spaces]
style CLI fill:#e1f5ff
style Core fill:#fff4e1
style Storage fill:#e8f5e9
style Compression fill:#f3e5f5
Core Components
1. CLI Layer
- Technology: Clap derive macros for type-safe command parsing
- Responsibility: User interface, command validation, help system
- Location:
crates/mediagit-cli/
2. Core Logic
- Object Database (ODB): Content-addressable storage with SHA-256 hashing
- Versioning Engine: Branch management, merge strategies, LCA algorithms
- Media Intelligence: Format-aware parsing and merging for PSD, video, audio
- Location:
crates/mediagit-versioning/,crates/mediagit-media/
3. Storage Abstraction
- Design: Trait-based abstraction (
Backendtrait) - Implementations: 7 storage backends (local, S3, Azure, GCS, B2, MinIO, Spaces)
- Benefits: Easy backend switching, testability, cloud-agnostic design
- Location:
crates/mediagit-storage/
4. Compression Layer
- Algorithms: zstd (default), brotli, delta (zstd dictionary)
- Strategy: Automatic algorithm selection based on file type
- Performance: Async compression with tokio runtime
- Location:
crates/mediagit-compression/
Data Flow
sequenceDiagram
participant User
participant CLI
participant ODB
participant Compression
participant Storage
User->>CLI: mediagit add large-file.psd
CLI->>ODB: Store object
ODB->>ODB: Calculate SHA-256 hash
ODB->>Compression: Compress with zstd
Compression->>Storage: Write to backend
Storage-->>User: ✓ Object stored
User->>CLI: mediagit commit -m "Update"
CLI->>ODB: Create commit object
ODB->>ODB: Link to tree & parent
ODB->>Storage: Store commit metadata
Storage-->>User: ✓ Commit created
Design Principles
Content-Addressable Storage
- Why: Automatic deduplication, data integrity verification
- How: SHA-256 hashing of all objects (blobs, trees, commits)
- Benefit: Identical files stored only once across all branches
Async-First Architecture
- Why: Handle large file I/O without blocking
- How: Tokio runtime with async/await throughout
- Benefit: Concurrent operations, better resource utilization
Media-Aware Intelligence
- Why: Generic byte-level merging fails for structured media
- How: Format parsers for PSD layers, video tracks, audio channels
- Benefit: Preserve layer hierarchies, avoid corruption
Trait-Based Abstraction
- Why: Decouple logic from storage implementation
- How:
Backendtrait with 7 implementations - Benefit: Easy testing (mock backends), cloud provider flexibility
Performance Characteristics
| Operation | Local Backend | S3 Backend | Optimization |
|---|---|---|---|
| Add 1GB file | ~2-3 seconds | ~15-20 seconds | Delta encoding for updates |
| Commit | <100ms | ~200-500ms | Metadata-only operation |
| Checkout | ~3-5 seconds | ~20-30 seconds | Parallel object fetch |
| Merge | ~1-2 seconds | ~5-10 seconds | Media-aware strategies |
Security Model
Authentication
- Local: File system permissions
- S3/Azure/GCS: IAM roles, service principals, service accounts
- B2/MinIO/Spaces: Application keys with bucket-level permissions
Integrity
- SHA-256 content verification on all read operations
- Cryptographic hashing prevents data tampering
mediagit verifyfor repository health checks
Encryption
- At-rest: AES-256-GCM client-side encryption + cloud provider encryption (SSE-S3, Azure SSE)
- In-transit: TLS 1.3 for all network operations
- Client-side encryption: Fully implemented with Argon2id key derivation
Scalability
Repository Size
- Tested with repositories up to 500GB
- Object count: Millions of objects supported
- Recommendation: Use cloud backends for >100GB repos
Concurrency
- Parallel object fetch during checkout (configurable workers)
- Async I/O prevents thread pool exhaustion
- Lock-free read operations for status/log/diff
Network Optimization
- HTTP/2 support for cloud backends
- Connection pooling (reqwest library)
- Automatic retry with exponential backoff
Monitoring and Observability
Metrics
- Crate:
mediagit-metrics - Export: Prometheus format
- Metrics: Operation latency, object size, cache hit rate, error rate
Logging
- Crate:
mediagit-observability - Levels: ERROR, WARN, INFO, DEBUG, TRACE
- Format: Structured JSON logging for production
Health Checks
mediagit fsck: Repository integrity verificationmediagit verify: Cryptographic object verificationmediagit stats: Repository statistics and health metrics
Extension Points
Custom Merge Strategies
- Implement
MergeStrategytrait - Register strategy in
MergeEngine - Example: Custom video frame merging
Storage Backend Development
- Implement
Backendtrait - Provide
get,put,exists,delete,listoperations - Example: IPFS backend, SFTP backend
Media Format Support
- Implement format parser (e.g., FBX, Blender, CAD)
- Register with
MediaIntelligencemodule - Example: 3D model layer-aware merging
Technology Stack
- Language: Rust 1.92.0
- Async Runtime: Tokio 1.40+
- CLI Framework: Clap 4.5+
- Compression: zstd, brotli, delta (zstd dictionary)
- Cloud SDKs: aws-sdk-s3, azure_storage, google-cloud-storage
- Testing: proptest (property-based), criterion (benchmarking)
Related Documentation
Core Concepts
MediaGit-Core is built on several fundamental concepts that enable efficient version control for large media files.
Content-Addressable Storage (CAS)
What is CAS?
Content-addressable storage identifies objects by their content (via cryptographic hash) rather than by name or location.
How MediaGit Uses CAS
File Content → SHA-256 Hash → Object ID (OID)
"hello" → 5891b5b522... → objects/58/91b5b522...
Every object (blob, tree, commit) is stored under its SHA-256 hash:
- Blobs: Raw file content
- Trees: Directory listings
- Commits: Snapshots with metadata
Benefits
- Automatic Deduplication: Identical files stored only once
- Integrity Verification: Hash mismatch = corruption detected
- Distributed Sync: Objects identifiable across repositories
- Efficient Transfers: Only send missing objects
Object Model
MediaGit uses a four-object model inspired by Git:
graph LR
Commit[Commit Object] --> Tree[Tree Object]
Tree --> Blob1[Blob: file1.psd]
Tree --> Blob2[Blob: file2.mp4]
Tree --> SubTree[Tree: subfolder/]
SubTree --> Blob3[Blob: file3.wav]
Commit --> Parent[Parent Commit]
style Commit fill:#e1f5ff
style Tree fill:#fff4e1
style Blob1 fill:#e8f5e9
style Blob2 fill:#e8f5e9
style Blob3 fill:#e8f5e9
Blob Objects
- Purpose: Store raw file content
- Properties: No filename, no metadata, just bytes
- Example:
large-file.psd→ compressed bytes
Tree Objects
- Purpose: Represent directories
- Contains: List of blobs and sub-trees with filenames and modes
- Example:
100644 blob a3c5d... README.md 100644 blob f7e2a... large-file.psd 040000 tree b8f3c... assets/
Commit Objects
- Purpose: Snapshot of repository at a point in time
- Contains:
- Root tree hash
- Parent commit(s) hash(es)
- Author signature (name, email, timestamp)
- Committer signature
- Commit message
- Example:
tree f3a5d... parent e8c2b... author Alice <alice@example.com> 1699564800 committer Alice <alice@example.com> 1699564800 Add updated PSD with new layers
Reference Objects
- Purpose: Human-readable names for commits
- Types:
refs/heads/main→ points to latest commit on main branchrefs/tags/v1.0→ points to tagged release commitHEAD→ symbolic ref to current branch
Delta Encoding
MediaGit uses zstd dictionary-based delta encoding to store only differences between versions:
When Deltas Are Used
- Scenario: Large file with small changes
- Strategy: Store base version + delta to new version
- Benefit: Significant storage savings (33–83% reduction depending on format; validated March 2026)
Delta Chain Example
Version 1: project.psd (100 MB) → Stored as full blob
Version 2: project.psd (100 MB) → Stored as delta from v1 (5 MB)
Version 3: project.psd (100 MB) → Stored as delta from v2 (3 MB)
Total storage: 108 MB instead of 300 MB (64% reduction)
Delta Chain Limits
- Maximum chain depth: 10 (
MAX_DELTA_DEPTH) - After depth exceeded, next version stored as new base
mediagit gcoptimizes long chains
Compression Strategy
MediaGit employs intelligent compression based on file type:
Compression Algorithms
- zstd (default): Fastest, good ratio for all file types
- brotli: Better ratio for text/code, slower
- delta: Zstd dictionary compression (chunk-level)
Automatic Selection
.psd, .psb → zstd level 3 (preserve layers)
.mp4, .mov → store (already compressed)
.txt, .md → brotli level 6 (high text compression)
.blend → zstd + delta (frequently updated 3D scenes)
Compression Levels
- Fast: Quick compression, lower ratio (zstd level 1)
- Default: Balanced speed/ratio (zstd level 3)
- Best: Maximum compression, slower (zstd level 19)
Branching Model
MediaGit supports lightweight branches similar to Git:
Branch Storage
- Branches are just files in
refs/heads/ - Each file contains a commit hash (64 hex characters for SHA-256)
- Creating a branch = writing a 40-byte file (instant)
Branch Visualization
gitGraph
commit id: "Initial commit"
commit id: "Add base assets"
branch feature-new-character
checkout feature-new-character
commit id: "Character model v1"
commit id: "Character textures"
checkout main
commit id: "Update README"
checkout feature-new-character
commit id: "Character animations"
checkout main
merge feature-new-character
commit id: "Release v1.0"
Branch Protection
- Branches can be marked as protected
- Protected branches require merge requests
- Prevents force-push and deletion
Merge Strategies
MediaGit provides multiple merge strategies:
1. Fast-Forward Merge
- When: Target branch is direct ancestor
- Action: Just move branch pointer forward
- Result: Linear history, no merge commit
- Use: Feature branches with no conflicts
2. Three-Way Merge
- When: Branches have diverged
- Action: Find LCA (Lowest Common Ancestor), apply both changesets
- Result: Merge commit with two parents
- Use: Concurrent work on different files
3. Media-Aware Merge
- When: Merging structured media (PSD, video, audio)
- Action: Parse file format, merge layers/tracks/channels
- Result: Merged media file preserving structure
- Use: Collaborative media editing
4. Rebase
- When: Want linear history
- Action: Replay commits on top of target branch
- Result: No merge commit, clean history
- Use: Preparing feature branch for merge
Conflict Resolution
Text Conflicts
Layer 1: Blue Background
Media Conflicts
MediaGit detects conflicting layers in PSD files:
Conflict in large-file.psd:
- Layer "Background" modified in both branches
- Your version: Blue (#0000FF)
- Their version: Red (#FF0000)
Resolution options:
1. Keep yours (blue)
2. Keep theirs (red)
3. Manual merge (open in Photoshop)
Storage Abstraction
MediaGit separates storage interface from implementation:
graph TB
App[Application Code] --> Trait[Backend Trait]
Trait --> Local[LocalBackend]
Trait --> S3[S3Backend]
Trait --> Azure[AzureBackend]
Trait --> GCS[GCSBackend]
Trait --> B2[B2Backend]
Trait --> MinIO[MinIOBackend]
Trait --> Spaces[SpacesBackend]
style Trait fill:#e1f5ff
Backend Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait Backend: Send + Sync {
async fn get(&self, key: &str) -> Result<Vec<u8>>;
async fn put(&self, key: &str, data: &[u8]) -> Result<()>;
async fn exists(&self, key: &str) -> Result<bool>;
async fn delete(&self, key: &str) -> Result<()>;
async fn list(&self, prefix: &str) -> Result<Vec<String>>;
}
}
Benefits
- Testability: Mock backends for unit tests
- Flexibility: Swap backends without code changes
- Extensibility: Add new backends by implementing trait
Garbage Collection
Over time, unreachable objects accumulate (orphaned by branch deletion, rebases, etc.).
What Gets Collected
- Objects not reachable from any branch or tag
- Dangling blobs from incomplete operations
- Long delta chains (recompressed)
GC Process
- Mark Phase: Traverse from all refs, mark reachable objects
- Sweep Phase: Delete unmarked objects
- Repack Phase: Optimize delta chains, recompress
Safety
- Preserves recent objects (default: 2 weeks grace period)
- Dry-run mode to preview deletions
- Backup recommended before aggressive GC
Repository Structure
.mediagit/
├── config # Repository configuration
├── HEAD # Current branch pointer
├── refs/
│ ├── heads/ # Branch pointers
│ │ ├── main
│ │ └── feature-branch
│ └── tags/ # Tag pointers
│ └── v1.0
├── objects/ # Object database (CAS)
│ ├── 5a/
│ │ └── 91b5b522... # Blob object
│ └── f3/
│ └── a5d3c1e8... # Tree object
└── logs/ # Reflog (operation history)
└── HEAD
Performance Considerations
Object Packing
- Small objects stored individually
- Large objects chunked for streaming
- Frequently accessed objects cached in memory
Network Optimization
- Object transfer uses HTTP/2 multiplexing
- Parallel object fetch (configurable workers)
- Automatic retry with exponential backoff
Disk I/O
- Async I/O prevents thread blocking
- Memory-mapped files for large objects
- Sequential writes for optimal SSD performance
Related Documentation
- Object Database (ODB)
- Content-Addressable Storage
- Delta Encoding
- Compression Strategy
- Storage Backends
Object Database (ODB)
The Object Database (ODB) is the core storage engine for MediaGit, managing content-addressable objects with SHA-256 hashing.
Architecture
graph TB
API[ODB API] --> Cache[In-Memory Cache]
Cache --> Compression[Compression Layer]
Compression --> Backend[Storage Backend]
API --> |Write| Hash[SHA-256 Hasher]
Hash --> Cache
Backend --> Local[Local FS]
Backend --> S3[Amazon S3]
Backend --> Azure[Azure Blob]
Backend --> Cloud[Other Cloud Providers]
style API fill:#e1f5ff
style Cache fill:#fff4e1
style Compression fill:#e8f5e9
Core Operations
Writing Objects
#![allow(unused)]
fn main() {
// 1. Calculate SHA-256 hash
let oid = sha256(&content);
// 2. Check cache
if cache.contains(&oid) {
return Ok(oid); // Already stored
}
// 3. Compress content
let compressed = compress(&content, CompressionAlgorithm::Zstd);
// 4. Write to backend
backend.put(&oid.to_path(), &compressed).await?;
// 5. Update cache
cache.insert(oid, content);
}
Reading Objects
#![allow(unused)]
fn main() {
// 1. Check cache
if let Some(content) = cache.get(&oid) {
return Ok(content);
}
// 2. Read from backend
let compressed = backend.get(&oid.to_path()).await?;
// 3. Decompress
let content = decompress(&compressed)?;
// 4. Verify integrity
let actual_oid = sha256(&content);
if actual_oid != oid {
return Err(CorruptedObject);
}
// 5. Update cache
cache.insert(oid, content.clone());
Ok(content)
}
Object Types
Blob Objects
- Purpose: Store raw file content
- Format: Pure bytes (no metadata)
- Example: PSD file → compressed blob
- Size: Unlimited (automatic chunking for large files)
Large File Handling: For files exceeding type-specific thresholds (5-10MB), MediaGit automatically chunks the content:
- Chunk Size: 1-8 MB adaptive based on file size (via
get_chunk_params()) - Strategy: Content-defined chunking (FastCDC v2020) for deduplication
- Overhead: Minimal (chunk index ~0.1% of file size)
- Benefit: Parallel processing and efficient delta compression
Tree Objects
- Purpose: Represent directories
- Format:
<mode> <type> <oid> <name> 100644 blob a3c5d... README.md 100644 blob f7e2a... large.psd 040000 tree b8f3c... assets/ - Sorted: Entries sorted by name for consistent hashing
Commit Objects
- Purpose: Snapshot with metadata
- Format:
tree <tree-oid> parent <parent-oid> author <name> <email> <timestamp> committer <name> <email> <timestamp> <commit message>
Tag Objects
- Purpose: Annotated tags with metadata
- Format:
object <commit-oid> type commit tag v1.0.0 tagger <name> <email> <timestamp> <tag message>
Object Addressing
OID (Object ID)
- Hash: SHA-256 (64 hex characters)
- Example:
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Path Mapping
Objects stored with 2-character prefix for directory sharding:
OID: 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Path: objects/58/91b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Benefit: Prevents single directory with millions of files (filesystem optimization)
Caching Strategy
Memory Cache
- Implementation: LRU cache (Least Recently Used)
- Default Size: 100 MB
- Eviction: Oldest unused objects evicted first
- Hit Rate Target: >80% for typical workflows
Cache Warming
Pre-load frequently accessed objects:
- HEAD commit and tree
- Recent commits (last 10)
- Currently checked out files
Cache Invalidation
- Object modification (rare due to immutability)
- Explicit cache clear (
mediagit gc --clear-cache) - Repository verification failures
Compression Integration
Algorithm Selection
#![allow(unused)]
fn main() {
fn select_compression(path: &Path, size: u64) -> CompressionAlgorithm {
match path.extension() {
// Already compressed media
Some("mp4" | "mov" | "jpg" | "png") => CompressionAlgorithm::None,
// Lossless audio (uncompressed — good zstd ratio)
Some("wav" | "flac" | "aiff") => CompressionAlgorithm::Zstd,
// Text and code
Some("txt" | "md" | "rs" | "py") => CompressionAlgorithm::Brotli,
// Large binaries
Some("psd" | "blend" | "fbx") if size > 10_MB => {
CompressionAlgorithm::ZstdWithDelta
}
// Default
_ => CompressionAlgorithm::Zstd,
}
}
}
Compression Levels
- Fast: zstd level 1 (150 MB/s compression)
- Default: zstd level 3 (100 MB/s, better ratio)
- Best: zstd level 19 (slow, maximum compression)
Delta Encoding
When to Use Deltas
- File size > 10 MB
- Multiple versions exist
- File type supports delta (PSD, Blender, FBX)
Delta Chain Management
Base Object (v1) 100 MB
↓ delta
Object v2 + 5 MB (delta)
↓ delta
Object v3 + 3 MB (delta)
↓ delta
Object v4 + 2 MB (delta)
Total: 110 MB (instead of 400 MB)
Chain depth: 3
Chain Breaking
- Maximum depth: 10 (
MAX_DELTA_DEPTH) - After depth exceeded, new base created
mediagit gcoptimizes chains
Integrity Verification
Read-Time Verification
Every object read is verified:
#![allow(unused)]
fn main() {
let content = backend.get(&oid.to_path()).await?;
let actual_oid = sha256(&content);
if actual_oid != oid {
return Err(OdbError::CorruptedObject {
expected: oid,
actual: actual_oid,
});
}
}
Bulk Verification
mediagit verify checks all objects:
- Read every object
- Verify SHA-256 hash
- Report corrupted objects
- Optionally repair from remote
Repair Operations
# Verify repository
mediagit verify
# Fetch missing/corrupted objects from remote
mediagit verify --fetch-missing
# Aggressive repair (expensive)
mediagit verify --repair --fetch-missing
Performance Optimization
Parallel Object Access
#![allow(unused)]
fn main() {
// Fetch multiple objects concurrently
let futures: Vec<_> = oids.iter()
.map(|oid| odb.read(oid))
.collect();
let objects = futures::future::join_all(futures).await;
}
Batch Operations
#![allow(unused)]
fn main() {
// Write multiple objects in one backend call
odb.write_batch(&[
(oid1, content1),
(oid2, content2),
(oid3, content3),
]).await?;
}
Memory Management
- Stream large objects (chunking)
- Memory-mapped files for very large blobs
- Automatic cache eviction under memory pressure
Large File Chunking
MediaGit implements intelligent chunking for efficient large file storage and processing.
Chunking Strategy
Content-Defined Chunking (CDC):
#![allow(unused)]
fn main() {
// Chunks split at natural content boundaries
// Uses FastCDC v2020 gear-table hash for O(1)/byte
// Average chunk size: 1-8 MB (adaptive by file size)
// Range: 512 KB - 32 MB
}
Benefits:
- Deduplication: Identical chunks shared across files
- Parallel Processing: Chunks processed concurrently
- Delta Efficiency: Small changes affect few chunks
- Memory Efficiency: Stream without loading entire file
Automatic Chunking Thresholds
| File Size | Chunking Strategy | Chunk Count |
|---|---|---|
| < 5-10 MB (type-dependent) | No chunking (single blob) | 1 |
| 5-100 MB | FastCDC (1 MB avg) | 5-100 |
| 100 MB - 10 GB | FastCDC (2 MB avg) | 50-5000 |
| > 10 GB | FastCDC (4-8 MB avg) | 2500+ |
Chunking Configuration
[storage.chunking]
# Enable automatic chunking
enabled = true
# Chunk sizes are adaptive by file size (from get_chunk_params()):
# < 100 MB: avg 1 MB, min 512 KB, max 4 MB
# 100 MB-10 GB: avg 2 MB, min 1 MB, max 8 MB
# 10-100 GB: avg 4 MB, min 1 MB, max 16 MB
# > 100 GB: avg 8 MB, min 1 MB, max 32 MB
Chunking Performance
Validated with 6GB Test File:
- Chunks Created: 1,541 chunks
- Average Chunk Size: 4.12 MB (adaptive based on content)
- Processing: Parallel chunk compression and delta encoding
- Throughput: 35.5 MB/s (streaming mode)
- Memory Usage: < 256 MB (constant, regardless of file size)
Chunk Storage
Chunks stored as individual objects:
File: large-video.mp4 (6 GB)
→ Chunk 1: 58/91b5b522... (2 MB)
→ Chunk 2: a3/c5d7e2f... (2 MB)
→ Chunk 3: f7/e2a1b8c... (2 MB)
...
→ Chunk Index: 5a/2b3c4d... (metadata)
Chunk Index contains:
- Chunk OIDs (SHA-256 hashes)
- Chunk offsets in original file
- Chunk sizes
- Reconstruction order
Deduplication Benefits
When same content appears in multiple files:
File A (5 GB):
→ Chunks: [C1, C2, C3, C4, C5]
File B (5 GB with 60% overlap):
→ Chunks: [C1, C2, C3, C6, C7]
→ Only C6, C7 stored (2 GB)
→ C1-C3 reused (deduplication)
Storage: 7 GB instead of 10 GB (30% savings)
Storage Backend Integration
Backend Requirements
#![allow(unused)]
fn main() {
#[async_trait]
pub trait Backend {
async fn get(&self, key: &str) -> Result<Vec<u8>>;
async fn put(&self, key: &str, data: &[u8]) -> Result<()>;
async fn exists(&self, key: &str) -> Result<bool>;
async fn delete(&self, key: &str) -> Result<()>;
}
}
Object Key Format
objects/{prefix}/{oid}
objects/58/91b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Backend-Specific Optimizations
- S3: Multipart upload for large objects
- Azure: Parallel block upload
- Local: Direct file I/O, no network overhead
Garbage Collection
Reachability Analysis
graph LR
Refs[refs/heads/main<br/>refs/tags/v1.0] --> C1[Commit 1]
C1 --> T1[Tree 1]
T1 --> B1[Blob 1]
T1 --> B2[Blob 2]
Orphan[Orphaned Blob]
style Refs fill:#e1f5ff
style Orphan fill:#ffcccc
GC Process
- Mark: Traverse from all refs
- Sweep: Delete unmarked objects
- Repack: Optimize delta chains
- Verify: Check repository integrity
Safety Mechanisms
- Grace period (14 days default)
- Reflog preservation
- Dry-run mode
- Backup recommendations
Error Handling
Common Errors
- ObjectNotFound: OID not in database
- CorruptedObject: Hash mismatch
- BackendError: Storage backend failure
- CompressionError: Decompression failure
Recovery Strategies
- Retry with exponential backoff (transient errors)
- Fetch from remote (missing objects)
- Repair with verification (corruption)
- Fallback to uncompressed storage (compression errors)
Monitoring Metrics
Key Metrics
- Object count
- Total size (compressed vs uncompressed)
- Cache hit rate
- Average object size
- Delta chain depth distribution
Performance Metrics
- Read latency (p50, p99)
- Write latency (p50, p99)
- Compression ratio
- Backend throughput
API Reference
See API Documentation for detailed Rust API documentation.
Related Documentation
Content-Addressable Storage
Content-Addressable Storage (CAS) is the foundation of MediaGit’s deduplication and integrity verification.
Concept
In CAS, data is retrieved by its content (hash) rather than by name or location:
- Traditional FS:
path/to/file.txt→ content - CAS:
SHA-256(content)→ content
SHA-256 Hashing
MediaGit uses SHA-256 for all objects:
#![allow(unused)]
fn main() {
use sha2::{Sha256, Digest};
let content = b"hello world";
let mut hasher = Sha256::new();
hasher.update(content);
let oid = hasher.finalize();
// oid = b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
}
Benefits
1. Automatic Deduplication
Identical files stored only once:
Branch A: large-file.psd (100 MB) → 5891b5b522...
Branch B: large-file.psd (100 MB) → 5891b5b522... (same hash, no duplication)
2. Data Integrity
Hash mismatch immediately detected:
#![allow(unused)]
fn main() {
let stored_oid = "5891b5b522...";
let content = read_object(stored_oid);
let actual_oid = sha256(&content);
if actual_oid != stored_oid {
panic!("Corruption detected!");
}
}
3. Distributed Synchronization
Objects identifiable across repositories without central server.
Object Identification
Full OID
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Short OID
Abbreviated to 7-12 characters (Git-style):
5891b5b // Unique prefix
MediaGit accepts short OIDs if unambiguous:
mediagit show 5891b5b
mediagit show 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
Storage Layout
Directory Sharding
Objects stored with 2-character prefix:
objects/
58/
91b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
a3/
c5d3e8f2a1b7c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9
Rationale: Prevents millions of files in single directory (filesystem optimization).
Collision Resistance
SHA-256 has 2^256 possible outputs (approximately 10^77):
- Probability of collision: Negligible (< 10^-60 for millions of objects)
- Comparison: More atoms in observable universe than SHA-256 outputs
Collision Handling
If collision detected (theoretical):
- Verify content matches
- If content differs, abort (catastrophic error)
- If content identical, continue (deduplication worked)
Performance Characteristics
Hashing Speed
- Small files (<1 MB): <1ms
- Medium files (10-100 MB): 10-100ms
- Large files (>1 GB): Streaming hash (chunked)
Memory Usage
- Fixed memory (streaming hash): 32 bytes (hash state)
- No need to load entire file into memory
Implementation Details
Rust Code
#![allow(unused)]
fn main() {
use sha2::{Sha256, Digest};
use std::io::Read;
pub fn hash_object(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().into()
}
pub fn hash_stream<R: Read>(reader: &mut R) -> std::io::Result<[u8; 32]> {
let mut hasher = Sha256::new();
let mut buffer = [0u8; 8192];
loop {
let n = reader.read(&mut buffer)?;
if n == 0 {
break;
}
hasher.update(&buffer[..n]);
}
Ok(hasher.finalize().into())
}
}
Related Documentation
Delta Encoding
Delta encoding stores only differences between file versions, dramatically reducing storage requirements for large binary files.
Concept
Instead of storing full copies:
Version 1: 100 MB (full)
Version 2: 100 MB (full)
Version 3: 100 MB (full)
Total: 300 MB
Store base + deltas:
Version 1: 100 MB (base)
Version 2: 5 MB (delta from v1)
Version 3: 3 MB (delta from v2)
Total: 108 MB (64% reduction!)
Delta Algorithm
MediaGit uses zstd dictionary compression for chunk-level delta encoding:
Zstd Dictionary Mode (Chunk-Level Delta)
- Crate:
mediagit-versioning—DeltaEncoderusing zstd dictionary compression - When: Applied by the ODB at chunk level for similar chunks
- Algorithm: Base chunk serves as a raw zstd dictionary (level 19) to compress target chunk
How It Works
- Compare new chunk with similar base chunk (via
SimilarityDetector) - Use base chunk as a zstd dictionary:
zstd::bulk::Compressor::with_dictionary(19, base) - Compress target chunk against the dictionary
- Store as wire format v2:
[0x5A, 0x44]magic + varint(base_size) + varint(result_size) + zstd bytes
Delta Chain Management
Chain Depth
Base → Delta 1 → Delta 2 → Delta 3 → ... → Delta N
- Default Max Depth: 10 (
MAX_DELTA_DEPTHinodb.rs) - Reason: Deeper chains = slower reconstruction
- Solution: After depth 10, the next version is stored as a new full base
Optimal Chain Depth
- Depth 1-5: Fast reconstruction, excellent savings
- Depth 6-10: Good reconstruction speed, good savings
- Depth >10: Automatically triggers new base creation
When to Use Deltas
Good Candidates
- Large files (>10 MB)
- Small changes between versions
- Frequently updated files
Poor Candidates
- Already compressed media (MP4, JPG, PNG)
- Small files (<1 MB)
- Completely rewritten files
Automatic Detection
#![allow(unused)]
fn main() {
// Simplified from add.rs — type-based eligibility
fn should_use_delta(filename: &str, data: &[u8]) -> bool {
match ext.to_lowercase().as_str() {
// Text-based: Always eligible
"txt" | "md" | "json" | "xml" | "rs" | "py" | "js" => true,
// Uncompressed media: Always eligible
"psd" | "tiff" | "bmp" | "wav" | "aiff" => true,
// Uncompressed video: Always eligible
"avi" | "mov" => true,
// Compressed video: Only for very large files
"mp4" | "mkv" | "flv" => data.len() > 100_MB,
// PDF/Creative: Only for large files
"ai" | "indd" | "pdf" => data.len() > 50_MB,
// 3D text formats: Always eligible
"obj" | "gltf" | "ply" | "stl" => true,
// 3D binary: Only for files >1MB
"glb" | "fbx" | "blend" | "usd" => data.len() > 1_MB,
// Compressed images/archives: Never
"jpg" | "png" | "webp" | "zip" | "gz" => false,
// Unknown: Only for large files
_ => data.len() > 50_MB,
}
}
}
Similarity Detection
MediaGit automatically determines whether to apply delta compression based on file similarity:
How It Works
#![allow(unused)]
fn main() {
// Pseudo-code for similarity decision
if file_size > minimum_threshold {
similarity = calculate_content_similarity(previous_version, new_version);
if similarity > type_specific_threshold {
delta_size = encode_delta(previous_version, new_version);
if delta_size < full_size * 0.9 { // At least 10% savings
use_delta_compression();
} else {
store_full_copy(); // Not worth it
}
}
}
}
Configuration by File Type
MediaGit uses intelligent thresholds based on file characteristics:
| File Type | Example | Threshold | Rationale |
|---|---|---|---|
| Creative/PDF | AI, InDesign, PDF | 0.15 | Compressed streams shift bytes; structural similarity remains |
| Office | DOCX, XLSX, PPTX | 0.20 | ZIP containers with shared structure |
| Video | MP4, MOV, AVI, MKV | 0.50 | Metadata/timeline changes significant |
| Audio | WAV, AIFF, MP3, FLAC | 0.65 | Medium threshold |
| Images | JPG, PNG, PSD | 0.70 | Perceptual similarity |
| 3D Models | OBJ, FBX, BLEND, glTF, GLB | 0.70 | Vertex/animation changes |
| Text/Code | TXT, PY, RS, JS | 0.85 | Small changes matter |
| Config | JSON, YAML, TOML, XML | 0.95 | Exact matches preferred |
| Default | Unknown types | 0.30 | Global minimum (MIN_SIMILARITY_THRESHOLD) |
Lower threshold = more aggressive compression (more files use delta) Higher threshold = more conservative (only very similar files use delta)
Similarity Configuration
Customize thresholds in .mediagit/config:
[compression.delta]
# Enable similarity detection (default: true)
auto_detect = true
# Minimum savings threshold (default: 10%, 0.1)
min_savings = 0.1
# Per-file-type similarity thresholds (from similarity.rs)
[compression.delta.thresholds]
psd = 0.70 # Images (perceptual similarity)
blend = 0.70 # 3D models
fbx = 0.70 # 3D models
wav = 0.65 # Audio files
mp4 = 0.50 # Video (metadata changes)
mov = 0.50 # Video
ai = 0.15 # Creative/PDF containers
pdf = 0.15 # PDF containers
rs = 0.85 # Text/code
default = 0.30 # Global minimum
Change similarity aggressiveness:
# Be more aggressive (compress more files)
$ mediagit config set compression.delta.thresholds.default 0.65
# Be more conservative (fewer deltas, safer)
$ mediagit config set compression.delta.thresholds.default 0.85
Disable delta for specific types:
# Treat MP4s as already compressed (skip delta)
$ mediagit config set compression.delta.thresholds.mp4 1.0
Similarity Detection Performance
The similarity checking process:
| File Size | Detection Time | Typical Savings |
|---|---|---|
| 10 MB | 0.1s | 15–45% |
| 100 MB | 0.5s | 20–50% |
| 1 GB | 2-3s | 25–65% |
Trade-off: Small detection cost for significant storage savings
Delta Generation
Process
- Read base version from ODB
- Read new version from working directory
- Generate delta (zstd dictionary at chunk level)
- If delta < 80% of full object, store delta
- If delta larger, store full object (no benefit)
Example (Chunk-Level Delta in ODB)
#![allow(unused)]
fn main() {
// From odb.rs — chunk-level delta using zstd dictionary
let delta = DeltaEncoder::encode(&base_data, &chunk.data)?;
let delta_bytes = delta.to_bytes();
let delta_ratio = delta_bytes.len() as f64 / chunk.data.len() as f64;
if delta_ratio < 0.80 {
// Store as delta (already zstd-compressed via dictionary)
backend.put(&delta_key, &delta_bytes).await?;
} else {
// Store full chunk
backend.put(&chunk_key, &compressed_chunk).await?;
}
}
Delta Reconstruction
Process
- Identify delta chain: target ← delta3 ← delta2 ← delta1 ← base
- Read base object
- Apply deltas in sequence
- Verify final content hash
Example (Chunk-Level Reconstruction)
#![allow(unused)]
fn main() {
// From odb.rs — reconstruct from zstd dictionary delta
let delta = Delta::from_bytes(&delta_bytes)?;
let reconstructed = DeltaDecoder::apply(&base_data, &delta)?;
// Verify integrity
let actual_hash = sha256(&reconstructed);
assert_eq!(actual_hash, expected_hash);
}
Performance Optimization
Parallel Reconstruction
For multiple files:
#![allow(unused)]
fn main() {
let futures: Vec<_> = oids.iter()
.map(|oid| reconstruct(odb, *oid))
.collect();
let contents = futures::future::join_all(futures).await;
}
Delta Chain Caching
- Cache intermediate reconstructions
- Speeds up repeated access to same chain
- LRU eviction policy
Base Selection
Choose base to minimize average reconstruction time:
- Prefer recent versions as bases
- Avoid deep chains for frequently accessed versions
mediagit gc --optimize-deltasreoptimizes chains
Garbage Collection Integration
Recompression
mediagit gc optimizes delta chains:
- Identify long chains (depth >10)
- Create new base from most recent version
- Regenerate deltas from new base
- Delete old chain
Example
Before GC:
Base (v1) → Δ2 → Δ3 → ... → Δ12 (depth 11)
After GC:
Base (v12) → Δ1 → ... → Δ5 (depth 5, rebalanced)
Storage Savings
Typical Scenarios
PSD Files (Photoshop documents):
- Layer additions: 35–65% savings
- Small edits: 37–64% savings (validated: 37% on 71 MB, 64% on 181 MB)
- Complete redesign: 0–10% savings
3D Models (GLB, FBX, STL, PLY, DAE):
- Mesh tweaks: 33–83% savings (validated: GLB 33–52%, FBX 47%, STL 70%, PLY 73%, DAE 83%)
- Material changes: 20–45% savings
- New scene: 0–10% savings
Audio Files (WAV, FLAC):
- Clip edits: 20–55% savings (validated: WAV 54%)
- Effects applied: 15–30% savings
- Re-recording: 0–5% savings
Delta Efficiency Benchmarks (v0.2.6-beta.1)
Measured via standalone deep test suite, 2026-04-03. All
fsckverified.
| Format | Delta Efficiency | Overhead |
|---|---|---|
| GLB (13–24MB) | 100% | 3–4 KB |
| AI-lg (123MB) | 100% | 4.5 KB |
| PSD-xl (213MB) | 99.8% | 424 KB |
| WAV (54MB) | 99.8% | 139 KB |
| ZIP (656MB) | 99.9% | 569 KB |
| FLAC (37MB) | 98.5% | 593 KB |
| FBX-ascii (16MB) | 99.4% | 100 KB |
| DAE (8.6MB) | 94.9% | 455 KB |
Related Documentation
Compression Strategy
MediaGit employs intelligent compression based on file type and size to minimize storage while maintaining performance.
Algorithms
zstd (Default)
- Speed: 100-500 MB/s compression, 500-2000 MB/s decompression
- Ratio: 2-3x for binaries, 5-10x for text
- Use: Default for all file types
brotli
- Speed: 10-50 MB/s compression, 200-400 MB/s decompression
- Ratio: 3-5x for binaries, 10-20x for text
- Use: Text and code files when size matters more than speed
delta (Zstd Dictionary Delta Encoding)
- Algorithm: Zstd dictionary compression (chunk-level delta via
mediagit-versioning) - How: Base chunk serves as a raw zstd dictionary (level 19) to compress target chunk
- Ratio: 33–83% reduction for updated files (type-dependent; validated March 2026)
- Use: Large files with incremental changes
Algorithm Selection
#![allow(unused)]
fn main() {
fn select_algorithm(path: &Path, size: u64) -> CompressionAlgorithm {
match path.extension().and_then(|s| s.to_str()) {
// Already compressed (store as-is)
Some("mp4" | "mov" | "mkv" | "avi") => None,
Some("jpg" | "jpeg" | "png" | "webp") => None,
Some("mp3" | "aac" | "m4a") => None,
// Lossless audio (zstd Best — uncompressed, good ratio)
Some("flac" | "wav" | "aiff") => Zstd,
// Text and code (brotli for better ratio)
Some("txt" | "md" | "rs" | "py" | "js" | "ts") => Brotli,
// Large binaries (zstd + delta)
Some("psd" | "psb") if size > 10_MB => ZstdWithDelta,
Some("blend") if size > 10_MB => ZstdWithDelta,
Some("fbx" | "obj") if size > 10_MB => ZstdWithDelta,
// Default
_ => Zstd,
}
}
}
Compression Levels
Fast (Level 1)
- zstd: ~150 MB/s, 2x ratio
- Use: Quick commits, local repos
- Command:
mediagit config compression.level fast
Default (Level 3)
- zstd: ~100 MB/s, 2.5x ratio
- Use: Balanced performance
- Command:
mediagit config compression.level default
Best (Level 19)
- zstd: ~10 MB/s, 3.5x ratio
- Use: Archival, cloud storage (bandwidth limited)
- Command:
mediagit config compression.level best
Performance Benchmarks
Verified via standalone deep test suite (v0.2.6-beta.1, 2026-04-03).
| File Type | Size | Algorithm | Savings | Throughput |
|---|---|---|---|---|
| PSD-xl (Photoshop) | 213 MB | zstd-19 | 70.9% (3.44x) | 4.0 MB/s |
| FBX-ascii (3D) | 16 MB | zstd/brotli | 81.0% (5.27x) | 0.27 MB/s |
| DAE (Collada 3D) | 8.6 MB | zstd/brotli | 81.4% (5.37x) | 0.39 MB/s |
| SVG (Vector) | 496 KB | brotli | 80.8% (5.20x) | 1.90 MB/s |
| WAV (Uncompressed Audio) | 54 MB | zstd-19 | 54.1% (2.18x) | 1.04 MB/s |
| GLB (3D Binary) | 13 MB | zstd | 50.6% (2.03x) | 0.77 MB/s |
| MP4 (Video) | 4.9 MB | Store | 0% (1.00x) | 27 MB/s |
| FLAC (Audio) | 37 MB | Store | 0% (1.00x) | 1.28 MB/s |
| ZIP (Archive) | 656 MB | Store | 0% (1.00x) | 6.62 MB/s |
Configuration
Repository-Level
# .mediagit/config.toml
[compression]
algorithm = "zstd"
level = 3 # zstd: 1 (fastest) – 22 (best compression)
min_size = 1024 # bytes; files smaller than this skip compression
Per-File Override
[compression.overrides]
"*.psd" = { algorithm = "zstd", level = 22 }
"*.txt" = { algorithm = "brotli", level = 6 }
"*.mp4" = { algorithm = "none" }
Related Documentation
Storage Backends
MediaGit supports 7 storage backends through a unified trait-based abstraction.
Available Backends
- Local - File system storage
- S3 - Amazon S3
- Azure - Azure Blob Storage
- GCS - Google Cloud Storage
- B2 - Backblaze B2
- MinIO - Self-hosted S3-compatible
- Spaces - DigitalOcean Spaces
Backend Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait Backend: Send + Sync {
async fn get(&self, key: &str) -> Result<Vec<u8>>;
async fn put(&self, key: &str, data: &[u8]) -> Result<()>;
async fn exists(&self, key: &str) -> Result<bool>;
async fn delete(&self, key: &str) -> Result<()>;
async fn list(&self, prefix: &str) -> Result<Vec<String>>;
}
}
Configuration
See individual backend documentation:
Choosing a Backend
| Backend | Best For | Cost | Performance |
|---|---|---|---|
| Local | Development, small teams | Free | Fastest |
| S3 | Production, global teams | $$$ | Excellent |
| Azure | Microsoft ecosystem | $$$ | Excellent |
| GCS | Google Cloud users | $$$ | Excellent |
| B2 | Cost-effective archival | $ | Good |
| MinIO | Self-hosted, compliance | Free* | Excellent |
| Spaces | Simple cloud storage | $$ | Good |
*MinIO requires infrastructure costs
Migration Between Backends
# Clone from S3 to local
mediagit clone s3://my-bucket/repo.git ./repo
# Push to different backend
cd repo
mediagit remote add azure azure://my-account/my-container/repo.git
mediagit push azure main
Local Storage Backend
Local file system storage for development and small teams.
Configuration
[storage]
backend = "filesystem"
base_path = "./data"
create_dirs = true
Usage
mediagit init
# Automatically uses local backend
Performance
- Read: Direct file system access
- Write: Direct file system writes
- Latency: <1ms
- Throughput: Limited by disk I/O
Best For
- Development
- Single machine workflows
- Small teams with network shares
s3 Storage Backend
Cloud storage backend for S3.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
azure Storage Backend
Cloud storage backend for AZURE.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
b2 Storage Backend
Cloud storage backend for B2.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
gcs Storage Backend
Cloud storage backend for GCS.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
minio Storage Backend
Cloud storage backend for MINIO.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
do Storage Backend
Cloud storage backend for DO.
Configuration
See Storage Backend Configuration for detailed setup.
Authentication
Requires appropriate credentials configured via environment variables or config file.
Performance
Cloud-based storage with network latency. Use for distributed teams and backup.
Media-Aware Merging
MediaGit understands structured media formats for intelligent merging.
Supported Formats
- PSD/PSB: Layer-aware merging
- Video: Track-based merging
- Audio: Channel-aware merging
How It Works
- Parse file format structure
- Identify layers/tracks/channels
- Merge at structural level
- Preserve hierarchy and metadata
Example: PSD Merging
# Branch A: Added "Background" layer
# Branch B: Added "Foreground" layer
mediagit merge feature-branch
# Result: Both layers preserved in merged file
See User Guide - Merging Media for examples.
Branch Model
MediaGit uses lightweight branches similar to Git.
Branch Storage
Branches are files in refs/heads/ containing commit hashes.
Operations
- Create:
mediagit branch <name> - Switch:
mediagit branch <name> - List:
mediagit branch --list - Delete:
mediagit branch --delete <name>
Branch Protection
Protected branches prevent force-push and deletion.
See CLI Reference - branch for details.
Security
MediaGit security model and best practices.
Authentication
- Local: File system permissions
- Server mode: JWT tokens + API key authentication
- Cloud: IAM roles, service principals, API keys
Data Integrity
- SHA-256 hashing for all objects
- Cryptographic verification on read
mediagit verifyfor repository health
Encryption
- At-rest (client-side): AES-256-GCM with Argon2id key derivation
- At-rest (cloud): Cloud provider encryption (SSE-S3, Azure SSE)
- In-transit: TLS 1.3 for network operations
Best Practices
- Use IAM roles (avoid hardcoded keys)
- Enable bucket versioning
- Regular
mediagit verifychecks - Restrict branch protection rules
- Audit logs for sensitive repositories
See Configuration Reference for security settings.
Basic Workflow
See Quickstart Guide for basic MediaGit workflow.
Branching Strategies
Common branching strategies for media projects.
Git Flow
Feature Branches
Release Branches
Merging Media Files
Guide to media-aware merging in MediaGit.
See Architecture - Media Merging.
Working with Remote Repositories
Guide to remote repository workflows.
Setup
Push/Pull
Collaboration
Storage Backend Configuration
MediaGit supports multiple storage backends. The backend is configured in .mediagit/config.toml under the [storage] section.
For a complete reference of every option, see Configuration Reference — Storage.
Local Filesystem (Default)
No configuration required. MediaGit uses ./data relative to the repo root:
[storage]
backend = "filesystem"
base_path = "./data"
create_dirs = true
sync = false
Set sync = true to flush writes to disk before confirming (slower but safer on crash-prone systems).
Amazon S3
[storage]
backend = "s3"
bucket = "my-media-bucket"
region = "us-east-1"
prefix = "repos/my-project"
encryption = false
Credentials via environment variables (recommended over config file):
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_REGION=us-east-1
For temporary credentials (IAM role or STS):
export AWS_SESSION_TOKEN=...
For named profiles from ~/.aws/credentials:
export AWS_PROFILE=my-profile
MinIO (S3-Compatible)
MinIO uses the same S3 configuration with a custom endpoint:
[storage]
backend = "s3"
bucket = "my-media-bucket"
region = "us-east-1"
prefix = ""
export AWS_ACCESS_KEY_ID=minioadmin
export AWS_SECRET_ACCESS_KEY=minioadmin
export AWS_ENDPOINT_URL=http://localhost:9000
export AWS_REGION=us-east-1
Create the bucket first:
mc alias set local http://localhost:9000 minioadmin minioadmin
mc mb local/my-media-bucket
Azure Blob Storage
[storage]
backend = "azure"
account_name = "mystorageaccount"
container = "media-container"
prefix = ""
Authentication via environment variable (full connection string):
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=mystorageaccount;AccountKey=base64key==;EndpointSuffix=core.windows.net"
Or account name + key:
export AZURE_STORAGE_ACCOUNT=mystorageaccount
export AZURE_STORAGE_KEY=base64key==
Google Cloud Storage
[storage]
backend = "gcs"
bucket = "my-gcs-bucket"
project_id = "my-gcp-project"
prefix = ""
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
For local testing with the GCS emulator:
export GCS_EMULATOR_HOST=http://localhost:4443
Performance Tuning
All backends benefit from increased connection pool and concurrency for large parallel uploads:
[performance]
max_concurrency = 32
[performance.connection_pool]
max_connections = 32
[performance.timeouts]
request = 300 # 5 min — for very large chunks
write = 120
For the local filesystem backend, max_concurrency controls how many concurrent chunk writes are issued.
See Also
- Configuration Reference
- Environment Variables
- Architecture — Storage Backends
- Large File Optimization
Delta Compression Guide
Complete guide to understanding and optimizing delta compression in MediaGit.
What is Delta Compression?
Delta compression stores only the differences between file versions instead of complete copies:
Traditional Storage:
v1.psd: 500 MB
v2.psd: 500 MB (full copy)
v3.psd: 500 MB (full copy)
Total: 1,500 MB
Delta Compression:
v1.psd: 500 MB (base)
v2.psd: 15 MB (delta from v1)
v3.psd: 8 MB (delta from v2)
Total: 523 MB (65% savings!)
How MediaGit Applies Delta Compression
Automatic Detection
MediaGit automatically applies delta compression based on:
- File size - Must be >10MB
- File similarity - Content similarity above threshold
- File type - Media-aware thresholds
- Savings check - Delta must be <90% of full size
Similarity Thresholds by File Type
| File Type | Threshold | Behavior |
|---|---|---|
| AI/PDF/InDesign | 0.15 | Very aggressive (compressed streams, structural similarity) |
| DOCX/XLSX/PPTX (Office) | 0.20 | Aggressive (ZIP containers, shared structure) |
| MP4/MOV (Video) | 0.50 | Moderate (metadata/timeline changes) |
| WAV/AIF (Audio) | 0.65 | Medium (clip edits) |
| PSD/JPG/PNG (Images) | 0.70 | Moderate (perceptual similarity) |
| FBX/OBJ/BLEND (3D Models) | 0.70 | Moderate (geometry changes) |
| TXT/Code | 0.85 | Conservative (small changes matter) |
| JSON/YAML/TOML (Config) | 0.95 | Very conservative (exact matches preferred) |
| Default | 0.30 | Global minimum (MIN_SIMILARITY_THRESHOLD) |
Lower threshold = more files use delta compression Higher threshold = only very similar files use delta
Checking Delta Status
Show Delta Information
# Show file storage info
$ mediagit show --stat large-file.psd
Object: 5891b5b522d5df086d...
Type: blob (delta)
Size: 15.3 MB (delta)
Base: a3c5d7e2f1b8c9a4d... (500 MB)
Compression ratio: 96.9%
Delta chain depth: 3
List Objects with Delta Info
$ mediagit stats --verbose
Object database statistics:
Total objects: 8,875
Loose objects: 247
Packed objects: 8,628
Delta statistics:
Objects with deltas: 2,847 (32%)
Average chain depth: 4.2
Max chain depth: 12
Total delta savings: 3.2 GB (78%)
Configuring Delta Compression
Global Configuration
Edit .mediagit/config:
[compression.delta]
# Enable automatic delta compression
enabled = true
# Minimum file size for delta consideration
min_size = "10MB"
# Minimum savings required (10% = 0.1)
min_savings = 0.1
# Maximum delta chain depth before creating new base
max_depth = 10
# Per-file-type similarity thresholds
[compression.delta.thresholds]
psd = 0.70 # Images (perceptual similarity)
psb = 0.70 # Large Photoshop documents
blend = 0.70 # Blender projects
fbx = 0.70 # FBX 3D models
obj = 0.70 # OBJ 3D models
wav = 0.65 # WAV audio
aif = 0.65 # AIF audio
mp4 = 0.50 # MP4 video
mov = 0.50 # QuickTime video
ai = 0.15 # Creative/PDF containers
pdf = 0.15 # PDF containers
default = 0.30 # Global minimum
Adjust Aggressiveness
# More aggressive (delta more files)
$ mediagit config set compression.delta.thresholds.default 0.65
# More conservative (fewer deltas, safer)
$ mediagit config set compression.delta.thresholds.default 0.85
# Disable delta for specific types
$ mediagit config set compression.delta.thresholds.mp4 1.0
Override for Single File
# Force delta compression
$ mediagit add --force-delta large-file.blend
# Disable delta for this file
$ mediagit add --no-delta huge-video.mp4
Optimizing Delta Chains
Understanding Delta Chains
Delta chains form when multiple versions are stored:
Base (v1) → Δ2 → Δ3 → Δ4 → Δ5
Reconstruction requires applying all deltas in sequence:
- Chain depth 1-5: Fast reconstruction
- Chain depth 6-10: Good performance
- Chain depth >10: New base created automatically
Check Chain Depth
$ mediagit verify --check-deltas
Analyzing delta chains...
Long chains detected:
assets/scene.blend: depth 52 (slow reconstruction)
images/poster.psd: depth 48
models/character.fbx: depth 45
Recommendation: Run 'mediagit gc --aggressive' to optimize chains
Optimize Chains
# Standard GC (optimizes chains >10 depth)
$ mediagit gc
# Aggressive GC (optimizes chains >20 depth)
$ mediagit gc --aggressive
# Result:
Optimizing delta chains...
Chains optimized: 23
New bases created: 23
Average depth reduced: 52 → 8
Repository size: 485 MB → 467 MB
Performance Tuning
Parallel Delta Processing
[compression.delta.performance]
# Enable parallel delta encoding
parallel = true
# Number of threads (0 = auto-detect)
threads = 0
# Chunk size for large file delta
chunk_size = "4MB"
Memory Limits
[compression.delta.memory]
# Maximum memory for delta buffers
max_buffer_size = "512MB"
# Stream large deltas (reduces memory)
streaming_threshold = "100MB"
Troubleshooting
Delta Compression Not Applied
Check file size:
$ ls -lh large-file.psd
-rw-r--r-- 1 user user 8.5M # Too small (<10MB)
Solution: Delta only applies to files >10MB by default
Check similarity:
$ mediagit show --similarity large-file.psd
Previous version similarity: 0.42 (threshold: 0.85)
Reason: File significantly changed, delta not beneficial
Solution: File rewritten, delta won’t help
Slow Reconstruction
Check delta chain depth:
$ mediagit show large-file.psd
Delta chain depth: 87 (very deep!)
Solution: Optimize chains
$ mediagit gc --aggressive
High Memory Usage
Check delta streaming:
[compression.delta.memory]
# Force streaming for large deltas
streaming_threshold = "50MB" # Lower threshold
Best Practices
1. Regular Garbage Collection
# Weekly maintenance
$ mediagit gc
# Monthly aggressive optimization
$ mediagit gc --aggressive
2. Tune for Your Workflow
Photo/Design Work (many small edits):
[compression.delta.thresholds]
psd = 0.80 # More aggressive
blend = 0.80
Video/Audio (large rewrites):
[compression.delta.thresholds]
mp4 = 1.0 # Disable delta
mov = 1.0
wav = 0.95 # Very conservative
3. Monitor Delta Effectiveness
# Check delta savings
$ mediagit stats --delta-report
Delta compression effectiveness:
File type | Files | Avg savings | Total saved
-------------+-------+-------------+-------------
PSD | 1,247 | 92.3% | 2.4 GB
BLEND | 389 | 88.7% | 876 MB
FBX | 156 | 74.2% | 234 MB
WAV | 89 | 45.1% | 89 MB
Other | 203 | 67.8% | 156 MB
-------------+-------+-------------+-------------
Total | 2,084 | 85.4% | 3.75 GB
4. Verify After Major Changes
# After configuration changes
$ mediagit verify --check-deltas
# Ensure chains are healthy
$ mediagit gc --verify
Advanced Topics
Custom Similarity Functions
For specific workflows, you can customize similarity detection (requires building from source):
#![allow(unused)]
fn main() {
// Custom similarity for your file type
fn custom_similarity(old: &[u8], new: &[u8]) -> f64 {
// Your custom similarity logic
// Return 0.0-1.0 (0 = completely different, 1 = identical)
}
}
Delta Debugging
Enable detailed delta logging:
$ RUST_LOG=mediagit_compression::delta=debug mediagit add large-file.psd
DEBUG mediagit_compression::delta: Calculating similarity...
DEBUG mediagit_compression::delta: Similarity: 0.89 (threshold: 0.85) ✓
DEBUG mediagit_compression::delta: Generating delta...
DEBUG mediagit_compression::delta: Delta size: 15.3 MB (full: 500 MB)
DEBUG mediagit_compression::delta: Savings: 96.9% ✓ (min: 10%)
DEBUG mediagit_compression::delta: Delta compression applied
Performance Benchmarks
Delta Encoding Speed
| File Size | Encoding Time | Throughput |
|---|---|---|
| 10 MB | 0.1s | 100 MB/s |
| 100 MB | 0.8s | 125 MB/s |
| 500 MB | 4.2s | 119 MB/s |
| 1 GB | 8.7s | 115 MB/s |
Reconstruction Speed
| Chain Depth | File Size | Reconstruction Time |
|---|---|---|
| 1-5 | 500 MB | 0.5s (1000 MB/s) |
| 6-10 | 500 MB | 1.2s (416 MB/s) |
| 11-20 | 500 MB | 2.8s (178 MB/s) |
| 21-50 | 500 MB | 6.5s (77 MB/s) |
| >50 | 500 MB | 15s+ (33 MB/s) |
Related Documentation
Performance Optimization
Practical tips for maximizing MediaGit throughput and minimizing storage costs.
Parallel Add
The single biggest performance lever. By default, MediaGit uses all available CPU cores.
# Let MediaGit choose (default: all CPUs)
mediagit add assets/
# Explicit job count
mediagit add --jobs 16 assets/
# Disable parallelism (for debugging or resource-constrained systems)
mediagit add --no-parallel assets/
Expected throughput (validated benchmarks, release build):
| File type | Throughput | Notes |
|---|---|---|
| PSD (72–181 MB) | 72–119 MB/s | Zstd Best; layer data compresses well |
| MP4/MOV (5–398 MB) | 146–174 MB/s | Pre-compressed; store-mode, zero CPU overhead |
| GLB (14–25 MB) | 3.0–5.2 MB/s | GLB parser + CDC chunking + Zstd |
| WAV (55–57 MB) | 2.1–3.6 MB/s | RIFF parser + chunking (CPU-bound) |
| Pre-compressed (JPEG, USDZ) | 25–182 MB/s | Direct write, no chunking |
Compression Strategy
MediaGit automatically selects the best compression strategy per file type. You can tune the global defaults:
# .mediagit/config.toml
[compression]
algorithm = "zstd"
level = 3 # 1 (fast) → 22 (best). Default 3 is optimal for most cases.
min_size = 1024 # Don't compress files smaller than 1 KB
Format-Specific Behavior
MediaGit never wastes CPU re-compressing already-compressed formats:
| Format | Strategy | Reason |
|---|---|---|
| JPEG, PNG, WebP | Store (level 0) | Already compressed |
| MP4, MOV, AVI | Store | Already compressed |
| ZIP, DOCX, XLSX | Store | ZIP container |
| PDF, AI, InDesign | Store | Contains compressed streams |
| PSD | Zstd Best | Raw layer data compresses well |
| OBJ, FBX, GLB, STL | Zstd Best | Binary 3D data |
| WAV, FLAC | Zstd Default | Uncompressed audio |
| Text, JSON, TOML | Zstd Default | Highly compressible |
Delta Encoding
For versioned files that change incrementally (e.g., evolving PSD files), MediaGit uses delta encoding to store only the differences between versions:
# Similarity thresholds (in smart_compressor.rs — not yet configurable via TOML)
# AI/PDF files: 15% similarity → try delta encoding
# Office docs: 20% similarity → try delta encoding
# General: 80% similarity threshold
Delta chains are capped at depth 10 to prevent slow reads on deeply-chained objects.
Chunking
Large files are split into chunks for efficient deduplication and parallel transfer. MediaGit uses different chunkers per file type:
| File size / type | Chunker | Typical chunk count |
|---|---|---|
| < 10 MB | FastCDC (small) | 2–10 |
| 10–100 MB | FastCDC (medium) | 10–100 |
| > 100 MB | StreamCDC | 100–2000 |
| MP4 / MKV / WebM | Video container-aware | 1 per GOP |
| WAV | Audio-aware | Fixed-size segments |
| PSD | Layer-aware | 1 per layer group |
Deduplication: Identical chunks across files or versions are stored only once. For a 6 GB CSV dataset, this yielded 83% storage savings in testing.
Storage Backend Performance
Cloud backend upload speeds depend on network, not MediaGit:
| Backend | Upload | Download | Notes |
|---|---|---|---|
| Local filesystem | 200–500 MB/s | 200–500 MB/s | Limited by disk I/O |
| MinIO (local) | 100–300 MB/s | 200–500 MB/s | Validated: 108 MB/s upload |
| Amazon S3 | 50–200 MB/s | 100–400 MB/s | Depends on region + instance |
| Azure Blob | 50–150 MB/s | 100–300 MB/s | |
| Google Cloud Storage | 50–200 MB/s | 100–400 MB/s |
S3 Transfer Optimization
[performance]
max_concurrency = 32 # More parallel uploads
[performance.connection_pool]
max_connections = 32
[performance.timeouts]
request = 300 # 5 min for very large files
write = 120
Memory Usage
Cache settings control how much object data MediaGit keeps in memory:
[performance.cache]
enabled = true
max_size = 1073741824 # 1 GB (for large repos)
ttl = 7200 # 2 hours
For workstations with < 8 GB RAM, reduce to 256 MB:
max_size = 268435456 # 256 MB
Repository Maintenance
Garbage Collection
Run after many branch deletions or partial operations:
mediagit gc
GC removes unreferenced objects and repacks data. Safe to run any time.
Verify Integrity
# Quick check (metadata only)
mediagit fsck
# Full cryptographic verification
mediagit verify
Statistics
mediagit stats
Shows compression ratio, deduplication rate, object count, and chunk distribution by file category.
Profiling
For investigating performance bottlenecks in development:
# Enable trace-level logging
RUST_LOG=mediagit_versioning=trace mediagit add large-file.psd
# Benchmark specific operations
cargo bench --workspace -p mediagit-compression
CI/CD Performance Tips
- Cache the binary: Download once, cache with
actions/cache, skip re-download on subsequent runs - Parallel jobs: Match
--jobsto the CI runner’s CPU count (nprocon Linux) - Avoid re-verifying in CI:
mediagit fsckis fast;mediagit verifydoes full SHA-256 re-reads and is slower - Use regional buckets: Place S3 buckets in the same region as your CI runners
See Also
Troubleshooting
Common issues and solutions for MediaGit.
Repository Corruption
mediagit fsck reports errors
Run a full verification to identify the issue:
mediagit fsck
If corruption is found, attempt repair:
mediagit fsck --repair
If objects are missing, check if they exist in the remote and fetch them:
mediagit fetch
mediagit fsck
Repository is inaccessible after system crash
# Verify integrity first
mediagit fsck
# If OK, run GC to clean up any partial writes
mediagit gc
# If corrupt, attempt repair
mediagit fsck --repair
“Not a mediagit repository” in a valid repo
This usually means the current directory is not inside a MediaGit repository, or the .mediagit/ directory was deleted.
# Check where MediaGit expects the repo root
ls .mediagit/
# Use -C to point to the repo explicitly
mediagit -C /path/to/repo status
The MEDIAGIT_REPO environment variable can also override the repo path:
export MEDIAGIT_REPO=/path/to/repo
mediagit status
Network Errors
Push / pull fails with connection error
# Verify the remote URL is correct
mediagit remote -v
# Test connectivity
curl -v http://media-server.example.com/healthz
Check the remote URL in .mediagit/config.toml:
[remotes.origin]
url = "http://media-server.example.com/my-project"
S3 upload fails with “Access Denied”
Verify your credentials are set (prefer environment variables over config file):
export AWS_ACCESS_KEY_ID=your-key
export AWS_SECRET_ACCESS_KEY=your-secret
export AWS_REGION=us-east-1
mediagit push
For MinIO or other S3-compatible services, set the endpoint:
export AWS_ENDPOINT_URL=http://localhost:9000
Azure Blob upload fails
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net"
mediagit push
Push times out on large files
Large files can take time to upload. Increase timeouts in .mediagit/config.toml:
[performance.timeouts]
request = 300 # 5 minutes
write = 120
Performance Issues
mediagit add is slow
By default, mediagit add uses all CPU cores. If your system is under memory pressure:
# Limit parallelism
mediagit add --jobs 4 assets/
# Disable parallelism (for debugging)
mediagit add --no-parallel assets/
Check if files are being re-compressed unnecessarily. Pre-compressed formats (JPEG, MP4, ZIP, PDF, AI) should be stored without re-compression — verify with:
RUST_LOG=mediagit_compression=debug mediagit add file.jpg
mediagit log is slow in large repos
Run garbage collection to build the commit graph:
mediagit gc
Clone or pull is slow
If the remote is on S3, increase upload concurrency:
[performance]
max_concurrency = 32
[performance.connection_pool]
max_connections = 32
Common Command Issues
mediagit status crashes on empty repo
This was fixed in the current release. If you see a crash, ensure you are running the latest binary:
mediagit --version
An empty repo correctly shows:
On branch: main (no commits yet)
mediagit add --all says “no files”
--all collects all files recursively from the repo root. Ensure you are inside a MediaGit repository:
mediagit -C /path/to/repo add --all
mediagit log -3 not recognized
Use the -n flag directly, or upgrade to the latest binary which preprocesses -N shorthand:
mediagit log -n 3 # always works
mediagit log -3 # works in current release
mediagit commit uses wrong author name
The priority chain for author identity is:
--author "Name <email>"CLI flagMEDIAGIT_AUTHOR_NAME/MEDIAGIT_AUTHOR_EMAILenv vars[author]section in.mediagit/config.toml$USERenvironment variable
Set your identity in config:
[author]
name = "Alice Smith"
email = "alice@example.com"
Or via environment:
export MEDIAGIT_AUTHOR_NAME="Alice Smith"
export MEDIAGIT_AUTHOR_EMAIL="alice@example.com"
File Format Issues
WAV file produces too many chunks
This was a known bug (WAV was routed to the AVI/RIFF chunker) and is fixed in the current release. Verify:
mediagit --version
STL / USDZ / PLY detected as “Unknown”
These 3D formats are now detected correctly in the current release. If you see “Unknown” for a supported format, check your binary version.
Supported 3D extensions: stl, obj, fbx, glb, gltf, ply, dae, abc, 3ds, usd, usda, usdc, usdz.
AI / InDesign files inflate in size after add
AI and InDesign (.indd) files are PDF containers with embedded compressed streams. MediaGit stores them as-is (no re-compression) because re-compressing compressed data increases size. This is correct behavior.
Storage Backend Issues
MinIO: “bucket does not exist”
Create the bucket first:
mc mb myminio/media-bucket
Or set create_dirs = true in config for the filesystem backend.
GCS: authentication fails
Set the credentials path:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
For local testing with the fake-gcs-server emulator:
export GCS_EMULATOR_HOST=http://localhost:4443
Debug Logging
Enable detailed logs to investigate any issue:
# All MediaGit logs
RUST_LOG=mediagit=debug mediagit add file.psd
# Specific crate
RUST_LOG=mediagit_versioning=trace mediagit add file.psd
# Human-readable format (instead of JSON)
RUST_LOG_FORMAT=text RUST_LOG=mediagit=debug mediagit status
See Also
- mediagit fsck — full repository verification
- mediagit gc — garbage collection and repair
- mediagit verify — verify specific objects
- Configuration Reference
- Environment Variables
Custom Merge Strategies
Implementing custom merge strategies for specific file types.
Backup and Recovery
Strategies for backing up MediaGit repositories and recovering from failures.
What to Back Up
A MediaGit repository consists of:
.mediagit/
├── objects/ # Content-addressable object database (chunks, trees, commits)
├── manifests/ # Chunk manifests (postcard format) — index of all chunks per file
├── refs/ # Branch and tag references
├── HEAD # Current branch pointer
├── config.toml # Repository configuration
└── stats/ # Operation statistics (non-critical)
The objects/ directory is the most important — it contains all file content. manifests/ and refs/ are smaller but required for correct operation.
Backup Strategies
1. Full Repository Archive (Local)
The simplest backup: archive the entire .mediagit/ directory.
# Create timestamped backup
tar czf mediagit-backup-$(date +%Y%m%d-%H%M%S).tar.gz .mediagit/
# Verify backup integrity
tar tzf mediagit-backup-*.tar.gz | head -20
Schedule daily backups with cron:
# /etc/cron.d/mediagit-backup
0 2 * * * /usr/bin/tar czf /backups/mediagit-$(date +%Y%m%d).tar.gz /path/to/repo/.mediagit/
2. Push to a Remote (Recommended)
The safest backup is a live remote that always has the latest state:
# Configure a backup remote (different server or cloud account)
# In .mediagit/config.toml:
[remotes.origin]
url = "http://primary-server.example.com/my-project"
[remotes.backup]
url = "http://backup-server.example.com/my-project"
# Push to both
mediagit push origin main
mediagit push backup main
For cloud storage backends, the provider handles redundancy. S3 and Azure Blob have 99.999999999% (11 nines) durability by default.
3. Sync to Cloud Storage
If you use a local filesystem backend and want to also back up to cloud storage, sync the .mediagit/objects/ directory:
# Sync to S3
aws s3 sync .mediagit/objects/ s3://my-backup-bucket/mediagit-objects/
# Sync to Google Cloud Storage
gsutil -m rsync -r .mediagit/objects/ gs://my-backup-bucket/mediagit-objects/
4. Incremental Backup
Because MediaGit uses content-addressable storage, objects are immutable once written. Incremental backup is straightforward — only new files need to be copied:
# rsync is efficient: only copies new objects
rsync -av --checksum .mediagit/objects/ backup-host:/backup/mediagit-objects/
Before Critical Operations
Always verify repository integrity and create a backup before major operations:
# Verify integrity
mediagit fsck
# Create safety snapshot
tar czf .mediagit-backup-$(date +%Y%m%d-%H%M%S).tar.gz .mediagit/
# Proceed with operation
mediagit rebase main
Recovery Procedures
Restore from Archive
# Remove damaged repository
rm -rf .mediagit/
# Restore from backup
tar xzf mediagit-backup-20260101-020000.tar.gz
# Verify restored repo
mediagit fsck
mediagit log --oneline -5
Restore from Remote
If your local repository is damaged but the remote is intact:
# Re-clone from remote
mediagit clone http://media-server.example.com/my-project my-project-restored
cd my-project-restored
mediagit fsck
Repair Corrupt Objects
MediaGit’s fsck can attempt automatic repair:
# Check what's damaged
mediagit fsck
# Attempt repair
mediagit fsck --repair
# If objects are missing, fetch from remote
mediagit fetch
mediagit fsck
If the remote has the correct objects, a fetch followed by fsck will usually restore a damaged local repository.
Recover Deleted Branch
Deleted branches may still be reachable via the reflog:
# Show recent ref history
mediagit reflog
# The deleted branch's last commit will appear
# Recreate the branch
mediagit branch create recovered-branch <commit-hash>
Lost-Found Recovery
If objects become dangling (unreferenced) after a failed operation:
# Find dangling objects
mediagit fsck --dangling
# Save them to lost-found
mediagit fsck --lost-found
# Inspect what was saved
ls .mediagit/lost-found/
Disaster Recovery Plan
For production environments managing large media repositories:
- Regular pushes to a remote on a different server or cloud provider
- Daily archives of
.mediagit/directory stored offsite - Weekly
mediagit fsckto detect corruption early - Monthly restore test — actually restore from backup to confirm it works
- Document recovery procedures for your team
Estimating Backup Size
The backup size equals the repository’s stored object size. Check with:
du -sh .mediagit/objects/
du -sh .mediagit/manifests/
du -sh .mediagit/ # total
For cloud backends, the objects are already stored remotely — only the .mediagit/refs/, .mediagit/HEAD, and .mediagit/config.toml need local backup (these are typically a few KB).
See Also
- mediagit fsck — repository integrity verification
- mediagit verify — verify specific objects
- mediagit gc — garbage collection before backup
- Storage Backend Configuration
Repository Migration
Migrating from other version control systems to MediaGit.
From Git-LFS
If you currently use Git-LFS to store large media files, you can migrate your assets to MediaGit while keeping source code in Git.
Step 1: Pull all LFS content locally
git lfs pull
This downloads all LFS-tracked files to your working tree.
Step 2: Initialize a MediaGit repository
mediagit init
Step 3: Add all media files
# For parallel ingestion (recommended)
mediagit add --jobs $(nproc) --all
This processes all files in the current directory. For large collections (hundreds of GB), expect several minutes to several hours depending on file count, file types, and hardware.
Step 4: Commit
mediagit commit -m "Initial import from Git-LFS"
Step 5: Configure a remote and push
# In .mediagit/config.toml
[remotes.origin]
url = "http://media-server.example.com/my-project"
mediagit push origin main
Ongoing workflow
After migration, continue tracking code with Git and assets with MediaGit:
project/
├── .git/ ← Git repository for code
├── .mediagit/ ← MediaGit repository for assets
├── src/ ← tracked by Git
└── assets/ ← tracked by MediaGit
Remove large files from Git-LFS tracking in .gitattributes and stop using git lfs track.
From Plain Git (Large Files in History)
If your Git repository has large binary files committed directly:
Step 1: Export the current state of large files
# Identify large files in Git history
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ && $3 > 10485760 {print $4, $3}' | sort -k2 -rn
Step 2: Copy large files to a separate directory
mkdir ../media-export
# Copy each identified large file:
cp assets/video.mp4 ../media-export/
cp assets/textures/ ../media-export/ -r
Step 3: Import into MediaGit
mkdir ../my-media-repo
cd ../my-media-repo
mediagit init
mediagit add --jobs $(nproc) ../media-export/
mediagit commit -m "Initial import from Git"
Step 4: Remove large files from Git history (optional)
Use git filter-repo to remove large files from Git history and reduce repository size:
pip install git-filter-repo
git filter-repo --strip-blobs-bigger-than 10M
From File System (No VCS)
If your media assets are on a file system with no version control:
mediagit init
mediagit add --jobs $(nproc) /path/to/media/
mediagit commit -m "Initial import"
For very large collections (TB-scale), run add in batches by directory:
for dir in /media/project/*/; do
mediagit add --jobs 16 "$dir"
mediagit commit -m "Import $(basename "$dir")"
done
Verifying the Migration
After migration, verify all files were ingested correctly:
# Check object integrity
mediagit fsck
# Review statistics
mediagit stats
# Spot-check specific files
mediagit verify --path assets/hero-video.mp4
Storage Efficiency After Migration
MediaGit’s deduplication and delta encoding provide significant storage savings for versioned media collections:
| Content type | Typical savings vs raw files |
|---|---|
| Design iterations (PSD, AI) | 40–80% via delta encoding |
| Video master + proxy pairs | 15–30% via deduplication of shared frames |
| Photo series | 10–40% via chunk deduplication |
| Pre-compressed media (JPEG, MP4) | Minimal (stored as-is) |
Run mediagit stats after committing multiple versions to see actual compression and deduplication ratios.
See Also
CI/CD Integration
Using MediaGit in continuous integration and deployment pipelines.
Overview
MediaGit’s CI/CD integration enables automated testing, verification, and deployment of media asset repositories. The mediagit-server binary provides the HTTP API for remote operations, while standard CLI commands work in headless CI environments.
GitHub Actions
Basic CI Workflow
name: MediaGit CI
on: [push, pull_request]
jobs:
verify-assets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install MediaGit
run: |
curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/latest/download/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz \
| tar xz -C /usr/local/bin/
- name: Verify repository integrity
run: mediagit fsck
- name: Check repository stats
run: mediagit stats
Full Pipeline with S3 Backend
name: Media Asset Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
AWS_REGION: us-east-1
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install MediaGit
run: |
VERSION="0.2.6-beta.1"
curl -fsSL "https://github.com/winnyboy5/mediagit-core/releases/download/v${VERSION}/mediagit-${VERSION}-x86_64-linux.tar.gz" \
| tar xz -C /usr/local/bin/
- name: Configure author identity
run: |
cat >> .mediagit/config.toml << 'EOF'
[author]
name = "CI Bot"
email = "ci@yourorg.com"
EOF
- name: Configure S3 backend
run: |
cat >> .mediagit/config.toml << 'EOF'
[storage]
backend = "s3"
bucket = "${{ vars.MEDIAGIT_S3_BUCKET }}"
region = "us-east-1"
EOF
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Verify assets
run: mediagit verify
- name: Run fsck
run: mediagit fsck
- name: Show stats
run: mediagit stats
Environment Variables
All CI systems can configure MediaGit through environment variables without modifying config.toml:
| Variable | Purpose |
|---|---|
MEDIAGIT_REPO | Override repository path (used by -C flag) |
MEDIAGIT_AUTHOR_NAME | Commit author name |
MEDIAGIT_AUTHOR_EMAIL | Commit author email |
AWS_ACCESS_KEY_ID | S3 access key |
AWS_SECRET_ACCESS_KEY | S3 secret key |
AWS_REGION | S3 region |
AWS_ENDPOINT_URL | Custom S3 endpoint (MinIO, etc.) |
AZURE_STORAGE_CONNECTION_STRING | Azure Blob connection string |
GCS_EMULATOR_HOST | GCS emulator URL (for testing) |
See Environment Variables Reference for the full list.
Non-Interactive Operation
MediaGit CLI commands exit cleanly in non-interactive environments. Key flags:
# Specify repository explicitly (no directory navigation needed)
mediagit -C /path/to/repo status
# Commit with author from environment (no config needed)
MEDIAGIT_AUTHOR_NAME="CI Bot" \
MEDIAGIT_AUTHOR_EMAIL="ci@example.com" \
mediagit commit -m "Automated update"
# Add all changed files
mediagit add --all
# Parallel add with explicit job count
mediagit add --jobs 8 assets/
Integration with Storage Emulators
For running integration tests locally or in CI without cloud credentials, use the bundled Docker Compose setup:
# Start emulators (MinIO, Azurite, fake-gcs-server)
docker compose -f docker-compose.test.yml up -d
# Configure MediaGit to use MinIO
export AWS_ACCESS_KEY_ID=minioadmin
export AWS_SECRET_ACCESS_KEY=minioadmin
export AWS_ENDPOINT_URL=http://localhost:9000
export AWS_REGION=us-east-1
# Run your pipeline
mediagit init test-repo
cd test-repo
mediagit add assets/
mediagit commit -m "Test commit"
mediagit push origin main
# Cleanup
docker compose -f docker-compose.test.yml down -v
GitLab CI
stages:
- validate
validate-assets:
stage: validate
image: ubuntu:22.04
before_script:
- apt-get update -qq && apt-get install -y -qq curl
- curl -fsSL https://github.com/winnyboy5/mediagit-core/releases/latest/download/mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
| tar xz -C /usr/local/bin/
script:
- mediagit fsck
- mediagit verify
- mediagit stats
variables:
MEDIAGIT_AUTHOR_NAME: "GitLab CI"
MEDIAGIT_AUTHOR_EMAIL: "ci@gitlab.com"
Performance in CI
MediaGit is designed for CI performance:
- Parallel add: Use
-j Nto match your runner’s CPU count - Cache: The
.mediagit/directory can be cached between CI runs for faster operations - Shallow operations:
mediagit log -1for recent commit checks is instantaneous
Caching the MediaGit binary (GitHub Actions)
- name: Cache MediaGit binary
uses: actions/cache@v4
with:
path: /usr/local/bin/mediagit
key: mediagit-${{ runner.os }}-0.2.6-beta.1
Troubleshooting CI Issues
mediagit: command not found
Ensure /usr/local/bin is in your PATH, or specify the full path to the binary.
Authentication failures with S3
- Verify
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYsecrets are set - Check that the IAM role/user has
s3:GetObject,s3:PutObject,s3:ListBucketpermissions
Slow uploads in CI
- Use parallel add:
mediagit add --jobs $(nproc) assets/ - Consider using a regional S3 bucket close to your CI runners
Repository not found
- Use
-C /path/to/repoto specify the repository root explicitly - Or set
MEDIAGIT_REPOenvironment variable
Large File Optimization
Strategies for handling very large files — video masters, high-resolution image sequences, 3D scene files, and game assets.
How MediaGit Handles Large Files
MediaGit automatically adapts its behavior based on file size:
| File size | Chunker | Typical chunks | Strategy |
|---|---|---|---|
| < 10 MB | FastCDC (small params) | 2–10 | Single-threaded |
| 10–100 MB | FastCDC (medium params) | 10–100 | Single-threaded |
| > 100 MB | StreamCDC | 100–2000 | Parallel workers |
| MP4 / MKV / WebM | Video container-aware | 1 per GOP | Per-format |
| PSD | Layer-aware | 1 per layer group | Per-format |
| WAV | FastCDC | Adaptive by size | Per-format |
No configuration is required. MediaGit detects file size and type automatically.
Parallel Ingestion
The single most effective optimization for large files is parallelism. MediaGit uses all CPU cores by default:
# Default: uses all cores
mediagit add assets/
# Explicit job count (match to your I/O bandwidth, not just CPU count)
mediagit add --jobs 8 assets/
# Disable for debugging or resource-constrained systems
mediagit add --no-parallel assets/
Expected throughput (validated benchmarks):
| File type | Sequential | Parallel (16 cores) |
|---|---|---|
| PSD (71 MB) | ~2 MB/s | ~35 MB/s |
| MP4 (500 MB) | ~3 MB/s | ~20 MB/s |
| Pre-compressed (JPEG) | ~80 MB/s | ~200 MB/s |
For very large files (10–100 GB), I/O tends to be the bottleneck rather than CPU. Use SSDs and tune --jobs to match your disk’s sequential read throughput divided by average chunk size.
Adding a 1 TB Media Collection
A 1 TB media collection with 16 CPU cores and an SSD:
# Time estimate: 33–105 minutes depending on content
mediagit add --jobs 16 /media/collection/
Progress is shown per-file and per-chunk. The parallel pipeline:
- File-level: multiple files processed concurrently (bounded semaphore)
- Chunk-level: each file’s chunks compressed and stored in parallel (async-channel producer-consumer)
Memory Usage for Large Files
Each worker holds one uncompressed chunk in memory. Chunk sizes are approximately:
- FastCDC medium: 4–32 MB per chunk
- StreamCDC (>100 MB files): 1–8 MB per chunk (adaptive by file size)
With --jobs 16 and 32 MB average chunk size, expect ~512 MB peak memory during add.
Tune the object cache separately from worker memory:
[performance.cache]
max_size = 1073741824 # 1 GB — for repositories with many reads
Reduce if your system has less than 8 GB RAM:
[performance.cache]
max_size = 268435456 # 256 MB
Cloud Backend Tips for Large Files
S3 / MinIO
Increase connection pool and concurrency for large parallel uploads:
[performance]
max_concurrency = 32
[performance.connection_pool]
max_connections = 32
[performance.timeouts]
request = 300 # 5 minutes for very large chunks
write = 120
Use a bucket in the same region as your workstation or CI runner.
Azure Blob
The Azure backend uses block upload for large objects. Increase timeout if uploads fail:
[performance.timeouts]
write = 120
Local Filesystem
For local storage of very large repos, sync = true ensures data safety on crash at the cost of ~30% write throughput:
[storage]
backend = "filesystem"
base_path = "./data"
sync = false # set true for critical data
Delta Encoding for Large Files
MediaGit applies delta encoding when a new version of a file has chunks similar to the stored version. For large files, delta encoding can reduce storage from GB to MB per revision:
v1.psd: 500 MB (base)
v2.psd: 15 MB (delta — only changed layers stored)
v3.psd: 8 MB (delta — minor touch-up)
Total: 523 MB (vs 1,500 MB without delta)
Delta chains are capped at depth 10 to prevent slow reads. After 10 revisions, the next version is stored as a new base.
Run mediagit gc periodically to optimize chain depth:
mediagit gc
Garbage Collection
After deleting branches or files containing large objects, run GC to reclaim storage:
mediagit gc
For maximum reclamation (slower):
mediagit gc --aggressive
Integrity Verification
After adding very large files, verify chunk integrity:
# Quick checksum check
mediagit fsck
# Full chunk-level verification (slower)
mediagit verify --path /path/to/large-file.mov
File Format Recommendations
| File type | Notes |
|---|---|
| MP4 / MOV / MKV | Already compressed; stored as-is. Deduplication works at GOP level. |
| JPEG / PNG / WebP | Already compressed; stored as-is. No re-compression overhead. |
| PSD / PSB | Layer-aware chunking + Zstd compression. Excellent delta savings per revision. |
| TIFF (uncompressed) | Zstd compresses well. Large but effective delta encoding. |
| EXR | Typically compressed. Stored as-is. |
| WAV / AIFF | Audio-aware chunking. Zstd compresses ~40–60% on uncompressed audio. |
| PDF / AI / InDesign | PDF containers with internal compression; stored as-is. |
| ZIP / DOCX / XLSX | ZIP containers; stored as-is. |
| 3D (OBJ, FBX, GLB, STL) | Binary 3D data; Zstd Best compression applied. |
See Also
- Performance Optimization
- Delta Compression Guide
- Storage Backend Configuration
- mediagit add
- mediagit gc
Configuration Reference
Complete reference for .mediagit/config.toml. All sections are optional — MediaGit uses sensible defaults for any missing values.
File Location
<repo-root>/.mediagit/config.toml
Minimal Configuration
[author]
name = "Alice Smith"
email = "alice@example.com"
Full Example
[author]
name = "Alice Smith"
email = "alice@example.com"
[storage]
backend = "s3"
bucket = "my-media-bucket"
region = "us-east-1"
prefix = "repos/my-project"
encryption = true
[compression]
enabled = true
algorithm = "zstd"
level = 3
min_size = 1024
[performance]
max_concurrency = 8
buffer_size = 65536
[performance.cache]
enabled = true
cache_type = "memory"
max_size = 536870912 # 512 MB
ttl = 3600
[performance.timeouts]
request = 60
read = 30
write = 30
connection = 30
[observability]
log_level = "info"
log_format = "json"
[remotes.origin]
url = "http://media-server.example.com/my-project"
[protected_branches.main]
prevent_force_push = true
prevent_deletion = true
require_reviews = true
min_approvals = 1
[author] — Author Identity
Used when creating commits. Override with MEDIAGIT_AUTHOR_NAME / MEDIAGIT_AUTHOR_EMAIL env vars or --author CLI flag.
| Key | Type | Default | Description |
|---|---|---|---|
name | string | $USER | Display name on commits |
email | string | "" | Email address on commits |
[storage] — Storage Backend
The storage backend is selected with the backend key. All backend-specific fields are placed directly in [storage] alongside backend — there are no nested [storage.s3] or [storage.filesystem] subsections.
Local Filesystem (default)
[storage]
backend = "filesystem"
base_path = "./data"
create_dirs = true
sync = false
file_permissions = "0644"
| Key | Type | Default | Description |
|---|---|---|---|
backend | string | "filesystem" | Must be "filesystem" |
base_path | string | "./data" | Storage root directory |
create_dirs | bool | true | Auto-create directories |
sync | bool | false | Sync writes to disk (slower, safer) |
file_permissions | string | "0644" | Octal file permission string |
Amazon S3
[storage]
backend = "s3"
bucket = "my-bucket"
region = "us-east-1"
prefix = ""
encryption = false
encryption_algorithm = "AES256"
# access_key_id and secret_access_key from env vars or IAM role
| Key | Type | Default | Description |
|---|---|---|---|
backend | string | — | Must be "s3" |
bucket | string | — | Required. S3 bucket name |
region | string | — | Required. AWS region |
access_key_id | string | env | AWS access key (prefer env var) |
secret_access_key | string | env | AWS secret key (prefer env var) |
endpoint | string | — | Custom endpoint for S3-compatible services |
prefix | string | "" | Object key prefix |
encryption | bool | false | Enable server-side encryption |
encryption_algorithm | string | "AES256" | SSE algorithm: AES256 or aws:kms |
Azure Blob Storage
[storage]
backend = "azure"
account_name = "mystorageaccount"
container = "media-container"
prefix = ""
# account_key from env AZURE_STORAGE_KEY or use connection_string
| Key | Type | Default | Description |
|---|---|---|---|
backend | string | — | Must be "azure" |
account_name | string | — | Required. Storage account name |
container | string | — | Required. Blob container name |
account_key | string | env | Storage account key (prefer env var) |
connection_string | string | env | Full connection string (alternative to account_name/key) |
prefix | string | "" | Blob path prefix |
Google Cloud Storage
[storage]
backend = "gcs"
bucket = "my-gcs-bucket"
project_id = "my-gcp-project"
prefix = ""
# credentials_path from GOOGLE_APPLICATION_CREDENTIALS env var
| Key | Type | Default | Description |
|---|---|---|---|
backend | string | — | Must be "gcs" |
bucket | string | — | Required. GCS bucket name |
project_id | string | — | Required. GCP project ID |
credentials_path | string | env | Path to service account JSON key |
prefix | string | "" | Object prefix |
[compression] — Compression Settings (Informational)
Note: MediaGit uses
SmartCompressorwhich automatically selects the optimal algorithm and level per file type. The values in this section are written toconfig.tomlbymediagit initfor reference but are not read at runtime — compression behavior is determined entirely by file type, not these settings.
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | (Informational) SmartCompressor is always active |
algorithm | string | "zstd" | (Informational) Actual algorithm selected per file type |
level | integer | 3 | (Informational) Actual level selected per file type |
min_size | integer | 1024 | (Informational) Not currently enforced |
Automatic algorithm selection by file type (always active, cannot be overridden via config):
- Already-compressed formats (JPEG, MP4, ZIP, docx, AI, PDF): stored as-is (
none) - PSD, raw formats, 3D models:
zstdatBestlevel (level 22) - Text, JSON, TOML:
zstdatDefaultlevel (level 3) - ML checkpoints:
zstdatFastlevel (level 1)
[performance] — Performance Tuning
| Key | Type | Default | Description |
|---|---|---|---|
max_concurrency | integer | CPU count (min 4) | Max parallel operations |
buffer_size | integer | 65536 | I/O buffer size in bytes (64 KB) |
[performance.cache]
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable in-memory object cache |
cache_type | string | "memory" | Cache type ("memory") |
max_size | integer | 536870912 | Max cache size in bytes (512 MB) |
ttl | integer | 3600 | Cache entry TTL in seconds |
compression | bool | false | Compress cached objects |
[performance.connection_pool]
| Key | Type | Default | Description |
|---|---|---|---|
min_connections | integer | 1 | Minimum pool connections |
max_connections | integer | 10 | Maximum pool connections |
timeout | integer | 30 | Connection timeout in seconds |
idle_timeout | integer | 600 | Idle connection timeout in seconds |
[performance.timeouts]
| Key | Type | Default | Description |
|---|---|---|---|
request | integer | 60 | Total request timeout in seconds |
read | integer | 30 | Read timeout in seconds |
write | integer | 30 | Write timeout in seconds |
connection | integer | 30 | Connection timeout in seconds |
[observability] — Logging and Tracing
| Key | Type | Default | Description |
|---|---|---|---|
log_level | string | "info" | Log level: "error", "warn", "info", "debug", "trace" |
log_format | string | "json" | Log format: "json" or "text" |
tracing_enabled | bool | true | Enable distributed tracing |
sample_rate | float | 0.1 | Trace sampling rate (0.0–1.0) |
Override log_level with the RUST_LOG environment variable.
[observability.metrics]
| Key | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable Prometheus metrics |
port | integer | 9090 | Metrics HTTP server port |
endpoint | string | "/metrics" | Metrics endpoint path |
interval | integer | 60 | Collection interval in seconds |
[remotes.<name>] — Remote Repositories
[remotes.origin]
url = "http://media-server.example.com/my-project"
[remotes.backup]
url = "http://backup-server.example.com/my-project"
| Key | Type | Default | Description |
|---|---|---|---|
url | string | — | Required. Remote server URL |
fetch | string | url | Fetch URL if different from url |
push | string | url | Push URL if different from url |
[branches.<name>] — Branch Tracking
[branches.main]
remote = "origin"
merge = "refs/heads/main"
Set automatically by mediagit push -u origin main. Rarely edited manually.
[protected_branches.<name>] — Branch Protection
[protected_branches.main]
prevent_force_push = true
prevent_deletion = true
require_reviews = false
min_approvals = 1
| Key | Type | Default | Description |
|---|---|---|---|
prevent_force_push | bool | true | Block force pushes |
prevent_deletion | bool | true | Block branch deletion |
require_reviews | bool | false | Require PR review before merge |
min_approvals | integer | 1 | Minimum approvals required |
See Also
- Environment Variables — env var overrides
- Storage Backend Configuration — detailed backend setup
- Security — encryption and authentication details
Environment Variables
All environment variables recognized by MediaGit. Environment variables take precedence over config.toml values where both are supported.
Core Variables
| Variable | Description | Default |
|---|---|---|
MEDIAGIT_REPO | Override repository root path. Used internally by -C <path>. | — |
Author Identity
These override the [author] section of .mediagit/config.toml. Priority (highest first): --author CLI flag → MEDIAGIT_AUTHOR_NAME/MEDIAGIT_AUTHOR_EMAIL → config.toml [author] → $USER.
| Variable | Description |
|---|---|
MEDIAGIT_AUTHOR_NAME | Commit author name (e.g., "Alice Smith") |
MEDIAGIT_AUTHOR_EMAIL | Commit author email (e.g., "alice@example.com") |
AWS / S3 / S3-Compatible Storage
Standard AWS SDK environment variables. Used when storage.backend = "s3".
| Variable | Description |
|---|---|
AWS_ACCESS_KEY_ID | AWS access key ID |
AWS_SECRET_ACCESS_KEY | AWS secret access key |
AWS_SESSION_TOKEN | AWS session token (for temporary credentials) |
AWS_REGION | AWS region (e.g., us-east-1) |
AWS_ENDPOINT_URL | Custom S3 endpoint URL (for MinIO, DigitalOcean Spaces, Backblaze B2, etc.) |
AWS_PROFILE | AWS named profile from ~/.aws/credentials |
Azure Blob Storage
Used when storage.backend = "azure".
| Variable | Description |
|---|---|
AZURE_STORAGE_CONNECTION_STRING | Full connection string (alternative to account_name + account_key) |
AZURE_STORAGE_ACCOUNT | Storage account name |
AZURE_STORAGE_KEY | Storage account key |
Google Cloud Storage
Used when storage.backend = "gcs".
| Variable | Description |
|---|---|
GOOGLE_APPLICATION_CREDENTIALS | Path to service account JSON key file |
GCS_EMULATOR_HOST | GCS emulator URL for testing (e.g., http://localhost:4443) |
Observability
| Variable | Description | Default |
|---|---|---|
RUST_LOG | Log filter directive (e.g., mediagit=debug, info) | info |
RUST_LOG_FORMAT | Log output format: json or text | json |
Log Filter Examples
# Show all debug logs
export RUST_LOG=debug
# Show debug for mediagit only, info for everything else
export RUST_LOG=mediagit=debug,info
# Show trace for a specific crate
export RUST_LOG=mediagit_versioning=trace
# Human-readable logs (development)
export RUST_LOG_FORMAT=text mediagit add file.psd
Cargo / Build (Development)
| Variable | Description |
|---|---|
CARGO_TERM_COLOR | Force color output: always, never, auto |
RUST_BACKTRACE | Enable Rust backtraces: 1 or full |
Integration Test Variables
Used by the CI integration test job and local integration testing:
| Variable | Value for local testing |
|---|---|
AWS_ACCESS_KEY_ID | minioadmin |
AWS_SECRET_ACCESS_KEY | minioadmin |
AWS_ENDPOINT_URL | http://localhost:9000 |
AWS_REGION | us-east-1 |
AZURE_STORAGE_CONNECTION_STRING | DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1; |
GCS_EMULATOR_HOST | http://localhost:4443 |
See Development Setup for running integration tests locally.
Precedence Summary
For each setting, MediaGit resolves values in this order (first match wins):
- CLI flag (e.g.,
--author "Name <email>") - Environment variable (e.g.,
MEDIAGIT_AUTHOR_NAME) - Repository config (
.mediagit/config.toml) - Built-in default
See Also
- Configuration Reference —
config.tomlfile format - Storage Backend Configuration — backend-specific setup
File Formats
Internal file format reference for MediaGit’s on-disk data structures.
Repository Layout
<repo-root>/
└── .mediagit/
├── HEAD # Current branch or commit pointer
├── config.toml # Repository configuration (TOML)
├── objects/ # Content-addressable object database
│ ├── <xx>/ # Two-character prefix directories
│ │ └── <hash> # Object files (remaining 62 hex chars of SHA-256)
│ └── pack/ # Pack files (future)
├── refs/ # Reference storage
│ └── heads/ # Branch refs
│ └── main # Branch pointer files
├── manifests/ # Chunk manifests per committed file
│ └── <hash>.bin # Bincode-serialized ChunkManifest
└── stats/ # Operation statistics (non-critical)
└── <timestamp>.json
Object Format
All objects are stored content-addressably. The object’s SHA-256 hash (over the uncompressed content) is used as the key. The key is split into a 2-character directory prefix and 62-character filename:
objects/ab/cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890cd
Object Types
| Type | Description |
|---|---|
blob | File content (full or delta) |
tree | Directory listing: maps filenames to object hashes |
commit | Commit metadata: tree hash, parent hashes, author, message |
chunk | A content chunk from a chunked large file |
Object Storage
Objects are stored compressed (Zstd) or uncompressed (Store), depending on the file type. The compression strategy is selected automatically per file extension:
| Format class | Strategy |
|---|---|
| JPEG, PNG, WebP, MP4, MOV, ZIP, docx, PDF, AI | Store (no compression) |
| PSD, 3D models (OBJ, FBX, GLB, STL, PLY) | Zstd Best |
| WAV, FLAC | Zstd Default |
| Text, JSON, TOML, CSV | Zstd Default |
Delta objects reference a base object and store only the difference.
Chunk Manifests
Large files are split into content-addressable chunks. The mapping of file → ordered list of chunks is stored as a ChunkManifest serialized with postcard (compact binary format):
.mediagit/manifests/<content-hash>.bin
The manifest contains:
- File path
- Total file size
- Ordered list of chunks, each with:
- Chunk hash (SHA-256 of chunk content)
- Chunk offset in the original file
- Chunk size (uncompressed)
- Whether the chunk is stored as full or delta
Reference Format
Refs are plain text files containing a 64-character hex SHA-256 hash followed by a newline:
.mediagit/refs/heads/main
a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
HEAD
HEAD contains either:
- A symbolic ref (pointing to a branch):
ref: refs/heads/main - A detached commit hash:
a3c8f9d2e1b4f6a8c5d7e9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1
Configuration Format
.mediagit/config.toml is a standard TOML file. See Configuration Reference for all supported keys.
[author]
name = "Alice Smith"
email = "alice@example.com"
[storage]
backend = "filesystem"
base_path = "./data"
[compression]
enabled = true
algorithm = "zstd"
level = 3
Commit Object Format
Commits are stored as Bincode-serialized structs containing:
| Field | Type | Description |
|---|---|---|
tree | [u8; 32] | SHA-256 hash of the root tree object |
parents | Vec<[u8; 32]> | Parent commit hashes (0 for initial, 1+ for merges) |
author | string | Author name |
email | string | Author email |
timestamp | i64 | Unix timestamp (seconds) |
message | string | Commit message |
Tree Object Format
Trees are stored as Bincode-serialized ordered lists of entries:
| Field | Type | Description |
|---|---|---|
name | string | Filename (not full path) |
hash | [u8; 32] | SHA-256 hash of the blob or subtree |
is_tree | bool | true for subdirectory, false for file |
size | u64 | Uncompressed size in bytes |
Statistics Format
Operation statistics are written as JSON to .mediagit/stats/:
{
"operation": "add",
"timestamp": "2026-02-20T10:30:00Z",
"files_processed": 42,
"bytes_input": 1073741824,
"bytes_stored": 157286400,
"chunks_created": 512,
"chunks_deduplicated": 87,
"duration_ms": 4320
}
These files are informational only and can be deleted without affecting repository integrity.
Hashing
MediaGit uses SHA-256 for all content hashing:
- Object identity: SHA-256 of the uncompressed object content
- Chunk identity: SHA-256 of the uncompressed chunk content
- Commit hash: SHA-256 of the serialized commit object
See Also
- Architecture — Object Database
- Architecture — Content-Addressable Storage
- Architecture — Compression Strategy
- Configuration Reference
API Documentation
Rust API documentation.
See docs.rs/mediagit for complete API reference.
MediaGit vs Git-LFS
Detailed comparison of MediaGit and Git Large File Storage (Git-LFS).
Overview
Git-LFS is a Git extension developed by GitHub that replaces large files in a Git repository with text pointers. The actual file content is stored on an LFS server. It requires Git to be installed and a Git host with LFS support (GitHub, GitLab, Bitbucket).
MediaGit is an independent version control system designed specifically for large media files. It does not depend on Git and uses its own object database, chunking engine, delta encoder, and wire protocol.
Feature Comparison
| Feature | MediaGit | Git-LFS |
|---|---|---|
| Git dependency | None — standalone | Required |
| Server requirement | MediaGit server or cloud backend | Git host with LFS support |
| Content-aware chunking | Yes (FastCDC, StreamCDC, per-format) | No |
| Cross-file deduplication | Yes — shared chunk pool | No |
| Delta encoding | Yes — chunk-level deltas | No |
| Parallel ingestion | Yes — multi-core (--jobs) | No |
| Cloud backends | S3, Azure, GCS, MinIO, B2, DO Spaces | LFS server (varies by host) |
| No file size limit | Practical limit: disk/network | Host-specific (e.g., 2 GB on GitHub free) |
| Format-aware compression | Yes — JPEG/MP4 stored as-is | No — always uploads raw bytes |
| Offline history | Full history locally | Pointer only; content fetched on demand |
| Git compatibility | Not compatible | Full Git compatibility |
| Windows ARM64 | Build from source | Part of Git for Windows |
Storage Efficiency
Deduplication
Git-LFS stores each version of a file as a complete copy on the LFS server. If you have 100 versions of a 500 MB video, Git-LFS stores 50 GB.
MediaGit splits files into content-addressable chunks. Chunks shared across versions or files are stored only once. For a video with 80% unchanged content between versions, MediaGit stores approximately:
500 MB base + (19 × 100 MB deltas) = 2.4 GB vs Git-LFS: 50 GB
Delta Encoding
Git-LFS has no delta encoding. MediaGit stores only the diff between similar chunk versions, which is especially effective for:
- PSD files with layer changes (5–20% of file size per edit)
- 3D model files with incremental geometry changes
- Audio stems with minor edits
Performance
Ingestion
| File | Git-LFS | MediaGit (16 cores) |
|---|---|---|
| PSD 71 MB | ~2 MB/s | ~35 MB/s |
| MP4 500 MB | ~3 MB/s | ~20 MB/s |
| Pre-compressed (JPEG) | ~80 MB/s | ~200 MB/s |
MediaGit’s parallel chunking pipeline (--jobs N) saturates multi-core machines.
Transfer
Git-LFS uploads each file as a single HTTP request. Interrupted transfers must restart from the beginning. MediaGit transfers individual chunks, so an interrupted upload can resume from the last successful chunk.
Workflow Comparison
Git-LFS
# Setup (once per repo)
git lfs install
git lfs track "*.psd" "*.mp4"
git add .gitattributes
# Normal workflow
git add scene.psd
git commit -m "Update scene"
git push origin main
MediaGit
# Setup (once per repo)
mediagit init
mediagit remote add origin http://server/my-project
# Normal workflow
mediagit add scene.psd
mediagit commit -m "Update scene"
mediagit push origin main
Advantages of MediaGit
- No Git required — deploy MediaGit independently of your code repository
- Content-aware chunking — PSD layers, video frames, and audio segments are split at format boundaries for better deduplication
- Cross-file deduplication — identical frames in different videos share storage
- Delta encoding — only differences are stored for similar versions
- Parallel ingestion — 10–20× faster than sequential on multi-core hardware
- Format-aware compression — pre-compressed formats (JPEG, MP4) are not re-compressed, saving CPU cycles
- No host file size limits — no GitHub-imposed 2 GB limit
- Self-hosted options — MinIO, local filesystem, or any S3-compatible service
Advantages of Git-LFS
- Git compatible — works with GitHub, GitLab, Bitbucket, and any Git host
- Familiar workflow — same
git add / commit / pushcommands - Mature ecosystem — LFS support is built into all major Git hosting platforms
- Selective fetching — pull only specific files with
git lfs pull --include
Trade-offs
MediaGit is optimized for media-heavy workflows where storage efficiency and ingestion speed matter more than Git compatibility. If your team is already using GitHub and needs code and assets in one repository, Git-LFS integrates with less friction.
| Situation | Recommendation |
|---|---|
| Code + small assets (<100 MB total) | Git-LFS or plain Git |
| Media-first pipeline (game art, VFX, video) | MediaGit |
| Existing GitHub workflow, want LFS | Git-LFS |
| Self-hosted, storage cost matters | MediaGit |
| 1TB+ media repositories | MediaGit |
| Need Git compatibility | Git-LFS |
Migration Guide
From Git-LFS to MediaGit
# 1. Pull all LFS content locally
git lfs pull
# 2. Initialize a MediaGit repository
mediagit init
# 3. Add all LFS files to MediaGit
mediagit add --jobs $(nproc) --all
# 4. Create initial commit
mediagit commit -m "Migrate from Git-LFS"
# 5. Configure remote and push
mediagit remote add origin http://media-server.example.com/my-project
mediagit push origin main
Running Both Side-by-Side
Many teams use Git for source code and MediaGit for assets:
project/
├── .git/ # Git repo for code
├── .mediagit/ # MediaGit repo for assets
├── src/ # Tracked by Git
└── assets/ # Tracked by MediaGit
# Code workflow
git add src/feature.py && git commit -m "Add feature"
# Asset workflow
mediagit add assets/scene.psd && mediagit commit -m "Update scene"
See Also
Frequently Asked Questions
How is MediaGit different from Git-LFS?
Git-LFS is an extension to Git that replaces large files with text pointers and stores the actual content on a separate LFS server. It requires a Git repository and a Git-LFS-compatible server.
MediaGit is a standalone version control system purpose-built for large media files. Key differences:
| MediaGit | Git-LFS | |
|---|---|---|
| Git required | No — fully standalone | Yes — wraps Git |
| Chunking | Content-aware chunking (FastCDC, StreamCDC) | No chunking |
| Delta encoding | Yes — chunk-level deltas | No |
| Deduplication | Cross-file chunk deduplication | No deduplication |
| Parallel ingestion | Yes — multi-core | No |
| Cloud backends | S3, Azure, GCS, MinIO, B2 | Server-specific |
| File size limit | No practical limit | Depends on server |
For a detailed comparison, see MediaGit vs Git-LFS.
What file sizes are supported?
MediaGit has no hard file size limit. In practice:
- Files under 10 MB: stored as single objects with FastCDC chunking
- Files 10–100 MB: split into 10–100 chunks with content-aware FastCDC
- Files over 100 MB: split with StreamCDC into 100–2000 chunks
- Files over 10 GB: supported; tested with 100 GB+ video files
Performance for large files benefits from the --jobs flag:
mediagit add --jobs 16 huge-video.mp4
Which cloud storage is best?
All supported backends (local, S3, Azure Blob, GCS) are functionally equivalent. Choose based on your infrastructure:
| Backend | Best for |
|---|---|
| Local filesystem | Development, single-machine use |
| Amazon S3 | AWS-hosted projects, widest ecosystem |
| MinIO | Self-hosted S3-compatible, on-premise |
| Azure Blob | Azure-hosted projects |
| Google Cloud Storage | GCP-hosted projects |
For CI/CD environments, use the same region as your runners to minimize latency and transfer costs.
How does delta encoding work?
When you add a new version of a file that already exists in the repository, MediaGit computes a similarity score between the new file’s chunks and the stored chunks. If the chunks are sufficiently similar, it stores only the difference (delta) rather than a full copy.
Similarity thresholds vary by file type:
- AI/PDF files: 15% similarity required
- Office documents (docx, xlsx): 20% similarity required
- General files: 80% similarity required
Delta chains are capped at depth 10 to prevent slow reads.
Does MediaGit work with Git?
No. MediaGit is an independent version control system, not a Git extension or plugin. It uses its own object database, ref format, and wire protocol. You cannot push a MediaGit repository to GitHub/GitLab.
Use MediaGit alongside Git: keep source code in Git, keep large media assets in MediaGit.
How do I migrate from Git-LFS?
The migration process:
- Export your Git-LFS files:
git lfs pull - Initialize a MediaGit repository:
mediagit init - Add the exported files:
mediagit add --all - Commit:
mediagit commit -m "Initial import from Git-LFS"
For large repositories, use the parallel add flag to speed up ingestion:
mediagit add --jobs $(nproc) --all
How do I undo a commit?
MediaGit provides two commands for undoing commits:
Revert — creates a new commit that undoes a previous commit (preserves history):
mediagit revert <commit-hash> # undo a specific commit
Reset — moves the current branch pointer backward (rewrites history):
mediagit reset --soft HEAD~1 # undo commit but keep changes staged
mediagit reset --mixed HEAD~1 # undo commit and unstage changes (default)
mediagit reset --hard HEAD~1 # undo commit and discard changes
For recovering specific files from an earlier commit, use mediagit show:
mediagit log --oneline # find the target commit hash
mediagit show <hash>:<path> # inspect a file from that commit
Can multiple people work on the same repository?
Yes. Push your changes to a shared remote:
mediagit push origin main
Others pull updates:
mediagit pull origin main
Concurrent writes to the same branch follow a push/pull model similar to Git.
What compression algorithm does MediaGit use?
Zstd (level 3 by default) for compressible formats, and Store (no compression) for already-compressed formats like JPEG, MP4, ZIP, PDF, and AI files. The algorithm is selected automatically per file type.
You can tune the global level in .mediagit/config.toml:
[compression]
algorithm = "zstd"
level = 3 # 1 (fast) to 22 (best)
How do I configure author information for commits?
Priority (highest to lowest):
--author "Name <email>"CLI flagMEDIAGIT_AUTHOR_NAME/MEDIAGIT_AUTHOR_EMAILenvironment variables[author]section in.mediagit/config.toml$USERenvironment variable (name only)
[author]
name = "Alice Smith"
email = "alice@example.com"
Is Windows ARM64 supported?
Windows ARM64 pre-built binaries are not included in official releases because the cross-compilation tool (cross-rs) does not support Windows targets. Windows ARM64 users must build from source. Alternatively, the x64 binary runs via Windows ARM64 emulation.
See Also
Contributing to MediaGit
See CONTRIBUTING.md in repository root for complete contribution guidelines.
Quick Start
- Fork the repository
- Create feature branch
- Make changes
- Submit pull request
Code of Conduct
See Code of Conduct.
Development Setup
A complete guide for setting up MediaGit for development and contribution.
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Rust | 1.92.0+ | Language toolchain (MSRV) |
| Docker | 20.10+ | Integration test emulators |
| Git | 2.x | Source code management |
Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://rustup.rs | sh
source ~/.cargo/env
# Install the exact MSRV toolchain
rustup toolchain install 1.92.0
rustup component add rustfmt clippy
Clone and Build
git clone https://github.com/winnyboy5/mediagit-core.git
cd mediagit-core
# Build (debug)
cargo build
# Build release binaries
cargo build --release --bin mediagit --bin mediagit-server
# Install locally
cargo install --path crates/mediagit-cli
Project Structure
mediagit-core/
├── crates/
│ ├── mediagit-cli/ # CLI binary (clap commands)
│ ├── mediagit-versioning/ # ODB, refs, commits, trees, pack files, chunking
│ ├── mediagit-storage/ # LocalBackend + cloud StorageBackend trait
│ ├── mediagit-compression/ # zstd/brotli, smart compression, ObjectType
│ ├── mediagit-media/ # PSD/video/audio/3D format parsers
│ ├── mediagit-config/ # TOML config schema, branch protection
│ ├── mediagit-protocol/ # HTTP push/pull/clone protocol
│ ├── mediagit-server/ # mediagit-server binary
│ ├── mediagit-security/ # AES-GCM encryption, argon2 key derivation
│ ├── mediagit-observability/ # tracing, structured logging
│ ├── mediagit-metrics/ # Prometheus metrics
│ ├── mediagit-migration/ # Repository migration utilities
│ ├── mediagit-git/ # Git interop (smudge/clean filters)
│ └── mediagit-test-utils/ # Shared test helpers (publish = false)
├── book/ # mdBook documentation source
├── docker/ # Dockerfiles
├── docker-compose.test.yml # Storage emulators for integration tests
├── Cargo.lock # Committed lockfile (binary workspace)
└── Cargo.toml # Workspace root with [workspace.lints]
Running Tests
Unit Tests
# All workspace crates
cargo test --workspace --all-features
# Single crate
cargo test -p mediagit-versioning
# With output (for debugging)
cargo test --workspace -- --nocapture
Integration Tests (requires Docker)
Integration tests are marked #[ignore] and need real storage emulators:
# Start emulators
docker compose -f docker-compose.test.yml up -d
# Run integration tests
export AWS_ACCESS_KEY_ID=minioadmin
export AWS_SECRET_ACCESS_KEY=minioadmin
export AWS_ENDPOINT_URL=http://localhost:9000
export AWS_REGION=us-east-1
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;"
export GCS_EMULATOR_HOST=http://localhost:4443
cargo test --ignored -p mediagit-storage -p mediagit-server --verbose
# Cleanup
docker compose -f docker-compose.test.yml down -v
MSRV Check
cargo +1.92.0 check --workspace --all-features
Git Hooks (husky-rs)
Git hooks are managed by husky-rs and installed automatically when you cargo build:
| Hook | What it enforces |
|---|---|
pre-commit | cargo fmt --check, cargo clippy --workspace, AGPL license headers, 5MB file size limit, conflict markers |
pre-push | cargo test --workspace — all tests must pass |
commit-msg | Conventional Commits format, max 72 chars |
To bypass hooks for a WIP: git commit --no-verify
To skip in CI: set NO_HUSKY_HOOKS=1 before building.
Code Quality
Formatting
cargo fmt --all
Linting
cargo clippy --workspace --all-targets --all-features -- -D warnings
Workspace lint policy is in Cargo.toml under [workspace.lints]. Three crates
(config, security, compression) already inherit these. When adding [lints] workspace = true
to other crates, fix any new clippy::all warnings first.
Unused Dependencies
cargo install cargo-machete --locked
cargo machete
License Headers
All .rs files must include an AGPL-3.0 header. Check with:
while IFS= read -r file; do
grep -q "GNU Affero General Public License" "$file" || echo "MISSING: $file"
done < <(git ls-files 'crates/**/*.rs')
Security Audit
cargo install cargo-audit --locked
cargo audit
Key Coding Patterns
Repository Discovery
#![allow(unused)]
fn main() {
use mediagit_cli::repo::find_repo_root;
let root = find_repo_root().await?;
// Respects MEDIAGIT_REPO env var and -C flag
}
ObjectDatabase Construction
#![allow(unused)]
fn main() {
// Always prefer with_smart_compression()
let odb = ObjectDatabase::with_smart_compression(root).await?;
}
Config Loading
#![allow(unused)]
fn main() {
use mediagit_config::schema::Config;
let config = Config::load(&repo_root).await?;
// Author priority: --author CLI > MEDIAGIT_AUTHOR_NAME env > config.toml [author] > $USER
}
Cross-Platform Paths
#![allow(unused)]
fn main() {
use dunce::canonicalize;
// NOT: std::fs::canonicalize (adds \\?\ prefix on Windows)
let path = dunce::canonicalize(&path)?;
}
Progress Bars
#![allow(unused)]
fn main() {
// Use ProgressTracker from src/progress.rs, not raw indicatif
use mediagit_cli::progress::ProgressTracker;
}
Adding a New CLI Command
- Create
crates/mediagit-cli/src/commands/mycommand.rs - Derive
clap::Parseron your args struct - Add
pub mod mycommand;tocommands/mod.rs - Add a variant to the
Commandsenum inmain.rs - Wire up execution in
main.rsmatch arm
Adding a New Storage Backend
- Implement the
Backendtrait inmediagit-storage - Add a variant to
StorageConfigenum inmediagit-config/src/schema.rs - Wire up construction in the storage factory
- Add integration tests with
#[ignore]and an emulator - Document in
book/src/architecture/backend-*.md
Benchmarks
cargo bench --workspace
Benchmarks use criterion. Results are stored in target/criterion/.
Documentation
# Install mdbook
cargo install mdbook
# Install mdbook-mermaid (pre-built binary, much faster)
MERMAID_VERSION="0.14.0"
curl -fsSL "https://github.com/badboy/mdbook-mermaid/releases/download/v${MERMAID_VERSION}/mdbook-mermaid-v${MERMAID_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \
| tar xz -C ~/.cargo/bin/
# Serve docs locally with live reload
cd book
mdbook serve
# Open http://localhost:3000
WSL2 Notes
When developing on Windows via WSL2 with the repository on an NTFS mount:
- Cargo’s fingerprinting may not detect file changes reliably on NTFS mounts
- Prefer cloning to a WSL2-native path (e.g.
~/projects/mediagit-core) for reliable incremental builds - The Linux ELF binary at
target/release/mediagitworks from WSL2 - The Windows PE binary (
mediagit.exe) requires building from Windowscmdor PowerShell
Troubleshooting
Git hooks not executing
git commit (or git push) fails with:
fatal: cannot exec '.husky/pre-commit': No such file or directory
This can happen on any platform — Windows, Linux, macOS, or CI — when either of two conditions are present:
Cause 1 — CRLF line endings
git config core.autocrlf true (the Windows git default) converts \n → \r\n in
text files on checkout. The hook shebang becomes #!/bin/sh\r, and the kernel cannot
find an interpreter named sh followed by a carriage return.
Diagnose: file .husky/pre-commit — reports “with CRLF line terminators” if affected.
Fix:
sed -i 's/\r//' .husky/pre-commit .husky/pre-push .husky/commit-msg
Cause 2 — Missing execute bit
Filesystems that do not track Unix permissions (NTFS, FAT32, SMB shares, CI artifact
zip extracts) may drop the +x bit on checkout.
Diagnose: ls -la .husky/ — hook files should be -rwxr-xr-x, not -rw-r--r--.
Fix:
chmod +x .husky/pre-commit .husky/pre-push .husky/commit-msg
git update-index --chmod=+x .husky/pre-commit .husky/pre-push .husky/commit-msg
git update-index --chmod=+x records mode 100755 in the git index so the bit is
preserved for future checkouts on the same machine.
Combined fix (safe to run on any platform after a fresh clone):
sed -i 's/\r//' .husky/pre-commit .husky/pre-push .husky/commit-msg
chmod +x .husky/pre-commit .husky/pre-push .husky/commit-msg
git update-index --chmod=+x .husky/pre-commit .husky/pre-push .husky/commit-msg
The .gitattributes file at the repo root enforces eol=lf for .husky/*, which
prevents the CRLF issue from recurring on subsequent checkouts.
Getting Help
- Check existing issues: GitHub Issues
- Review CONTRIBUTING.md
- Read the Architecture Overview
Code of Conduct
See CODE_OF_CONDUCT.md in repository root.
Release Process
The MediaGit release process for maintainers. Releases are driven by GitHub Actions.
Version Numbering
Semantic versioning: MAJOR.MINOR.PATCH[-prerelease]
v0.2.6-beta.1— stable releasev0.3.0-alpha.1— pre-release (alpha/beta/rc in version →is-prerelease: true)
Pre-Release Checklist
Before creating a release tag:
# 1. Ensure all CI jobs are green on main
# 2. Update CHANGELOG.md with the new version entry
# 3. Bump version in workspace Cargo.toml [workspace.package]
# (all crates inherit version.workspace = true)
sed -i 's/^version = ".*"/version = "0.2.6-beta.1"/' Cargo.toml
# 4. Update Cargo.lock
cargo generate-lockfile
# 5. Verify the build
cargo build --release --bin mediagit --bin mediagit-server
# 6. Run full test suite
cargo test --workspace --all-features
# 7. Check MSRV still passes
cargo +1.92.0 check --workspace --all-features
# 8. Commit and push
git add Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "chore: release v0.2.6-beta.1"
git push origin main
Creating the Release Tag
# Stable release
git tag -a v0.2.6-beta.1 -m "Release v0.2.6-beta.1"
git push origin v0.2.6-beta.1
# Pre-release (alpha/beta/rc)
git tag -a v0.2.6-beta.1-alpha.1 -m "Pre-release v0.2.6-beta.1-alpha.1"
git push origin v0.2.6-beta.1-alpha.1
Pushing the tag automatically triggers the release.yml workflow.
Release Workflow Steps
The release.yml workflow runs these jobs in sequence:
1. plan
Determines the version from the tag, sets is-prerelease flag.
2. build (parallel, 5 targets)
| Target | Platform | Tool |
|---|---|---|
x86_64-unknown-linux-gnu | Linux x64 | cargo |
aarch64-unknown-linux-gnu | Linux ARM64 | cross |
x86_64-apple-darwin | macOS Intel | cargo |
aarch64-apple-darwin | macOS Apple Silicon | cargo |
x86_64-pc-windows-msvc | Windows x64 | cargo |
Both mediagit and mediagit-server binaries are built and archived.
Note: Windows ARM64 (
aarch64-pc-windows-msvc) is not released —cross-rsdoes not support Windows targets. Windows ARM64 users should build from source.
3. installers
Generates install.sh (Unix) and install.ps1 (Windows) scripts.
4. release
Creates the GitHub Release with all archives, checksums, and installer scripts.
Only runs on tag push (not workflow_dispatch).
5. publish-crates
Publishes all 13 crates to crates.io in dependency order. Only runs for stable releases (is-prerelease == false).
Publish order (respects internal dependency tiers):
- Tier 0:
mediagit-config,mediagit-security,mediagit-observability,mediagit-compression,mediagit-storage,mediagit-media,mediagit-git - Tier 1:
mediagit-versioning,mediagit-metrics,mediagit-migration - Tier 2:
mediagit-protocol - Tier 3:
mediagit-server,mediagit-cli
The publish step uses retry logic (3 attempts, 60s between) and 30s delays between crates for crates.io index propagation.
6. docker
Builds and pushes multi-arch Docker images to GHCR (ghcr.io/winnyboy5/mediagit-core).
Tags: latest (stable only), semver X.Y.Z, X.Y, X.
Required Secrets
| Secret | Value |
|---|---|
CARGO_REGISTRY_TOKEN | crates.io API token with publish scope |
GITHUB_TOKEN | Auto-provided by GitHub Actions |
Dry Run
Test the release workflow without publishing:
- Go to Actions → Release → Run workflow
- Check Dry run checkbox
- Click Run workflow
The dry run builds all binaries and creates a pre-release with tag dry-run. No crates are published and no Docker images are pushed.
Post-Release
After a successful release:
- Verify GitHub Releases has all assets
- Verify crates on crates.io
- Verify Docker image:
docker pull ghcr.io/winnyboy5/mediagit-core:latest - Update the documentation site if needed
- Announce on Discord/community channels
Hotfix Releases
For critical bug fixes on a stable release:
# Create hotfix branch from the tag
git checkout -b hotfix/v0.2.2 v0.2.6-beta.1
# Apply the fix, test, commit
# ...
# Tag and push
git tag -a v0.2.2 -m "Hotfix v0.2.2: fix critical bug"
git push origin v0.2.2
# Merge fix back to main
git checkout main
git merge hotfix/v0.2.2
git push origin main