Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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?

FeatureMediaGit-CoreGit-LFSPerforce
ArchitectureStandalone native VCSGit extension + serverCentralized VCS
Branch Switch SpeedInstant (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 Support7 backendsServer-dependentProprietary
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

What’s Next?

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:

PlatformArchive
Linux x86_64mediagit-{VERSION}-x86_64-linux.tar.gz
Linux ARM64mediagit-{VERSION}-aarch64-linux.tar.gz
macOS Intelmediagit-{VERSION}-x86_64-macos.tar.gz
macOS Apple Siliconmediagit-{VERSION}-aarch64-macos.tar.gz
Windows x86_64mediagit-{VERSION}-x86_64-windows.zip

Each archive contains both mediagit (CLI) and mediagit-server binaries, with a corresponding .sha256 checksum file.

Platform-Specific Guides

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+
  • 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:

  1. Follow the Quickstart Guide for a 5-minute tutorial
  2. Read Configuration to customize MediaGit
  3. 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.

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

DistributionVersionStatus
Ubuntu20.04, 22.04, 24.04✅ Tested
Debian10, 11, 12✅ Tested
Fedora38, 39, 40✅ Tested
RHEL8, 9✅ Tested
CentOS7, 8, Stream 9✅ Tested
Arch LinuxRolling✅ Tested
openSUSELeap 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

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

PlatformVersionStatus
Raspberry Pi 48GB✅ Tested
Raspberry Pi 54GB, 8GB✅ Tested
AWS Graviton 2/3All instance types✅ Tested
Oracle Ampere A1All shapes✅ Tested
Azure ARM64 VMsDpsv5, Epsv5 series✅ Tested
Ampere AltraAll 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

macOS Intel Installation

MediaGit-Core provides native binaries optimized for Intel-based Macs.

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

macOS ARM64 (Apple Silicon) Installation

MediaGit-Core is optimized for Apple Silicon (M1, M2, M3, M4) processors with native ARM64 binaries.

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

ChipCoresStatus
M14P+4E✅ Tested
M1 Pro6P+2E, 8P+2E✅ Tested
M1 Max8P+2E✅ Tested
M1 Ultra16P+4E✅ Tested
M24P+4E✅ Tested
M2 Pro6P+4E, 8P+4E✅ Tested
M2 Max8P+4E✅ Tested
M2 Ultra16P+8E✅ Tested
M34P+4E✅ Tested
M3 Pro6P+6E✅ Tested
M3 Max12P+4E✅ Tested
M44P+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

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:

OperationM1M1 MaxM2M3Intel i9
Compression (1GB)2.3s1.8s2.1s1.6s4.2s
Branch Switch45ms38ms42ms35ms120ms
Object Scan (10k)0.8s0.6s0.7s0.5s1.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

Windows x64 Installation

MediaGit-Core provides native Windows binaries for x64 systems (Windows 10/11).

# Open PowerShell as Administrator
choco install mediagit-core

Alternative Installation Methods

Windows Package Manager (winget)

winget install MediaGit.MediaGitCore

Direct Download

  1. Download the latest ZIP from GitHub Releases: mediagit-0.2.6-beta.1-x86_64-windows.zip
  2. Extract the archive
  3. Move mediagit.exe and mediagit-server.exe to 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

  1. Download latest ZIP from GitHub Releases
  2. Extract and replace the binaries in your install directory

Uninstalling

Via Chocolatey

choco uninstall mediagit-core

Via Windows Settings

  1. Open Settings → Apps → Installed apps
  2. Find “MediaGit-Core”
  3. 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

Windows ARM64 Installation

Status: Windows ARM64 pre-built binaries are not currently included in official releases. The cross-rs tool 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

  1. Install Rust — download from rustup.rs

    winget install Rustlang.Rustup
    
  2. Install Visual Studio Build Tools (required for MSVC linker):

    winget install Microsoft.VisualStudio.2022.BuildTools
    # Select "Desktop development with C++"
    
  3. 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-rs does 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

# 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:

PlatformArchive
Linux x86_64mediagit-0.2.6-beta.1-x86_64-linux.tar.gz
Linux ARM64mediagit-0.2.6-beta.1-aarch64-linux.tar.gz
macOS Intelmediagit-0.2.6-beta.1-x86_64-macos.tar.gz
macOS Apple Siliconmediagit-0.2.6-beta.1-aarch64-macos.tar.gz
Windows x86_64mediagit-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

Getting Help

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 override
  • MEDIAGIT_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 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:

  1. Content-addressable storage: Identical content stored once
  2. Compression: Zstd or Brotli compression
  3. Delta encoding: Store differences for similar files
  4. 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 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

  1. Atomic commits: Each commit should represent one logical change
  2. Descriptive messages: Explain why changes were made, not just what changed
  3. Test before committing: Ensure files work as expected
  4. Review staged changes: Use mediagit status and mediagit 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 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 --ignored is 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

  1. Clean: No changes, nothing to commit
  2. Modified: Changes exist but not staged
  3. Staged: Changes ready for commit
  4. Conflicted: Merge conflicts need resolution
  5. Detached: HEAD not on a branch tip

Performance Tips

  • Use --short for faster output in scripts
  • Use --porcelain for machine parsing
  • Use .mediagitignore to permanently exclude build artifacts and temp files from appearing as untracked
  • Use --ignored to 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 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 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 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-patch to skip diff generation
  • Use --stat for 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

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 -D for force deletion
  • Shows warning when deleting unmerged branches

Large Repository Performance

For repositories with many branches:

  • Use pattern matching: --list 'feature/*'
  • Use --no-merged to focus on active work
  • Sort by date: --sort=-committerdate

See Also

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

  1. three-way merge: Standard git-style merge with common ancestor
  2. ours: Keep our version
  3. theirs: Keep their version

For Media Files (MediaGit-Specific)

  1. latest-mtime (default): Choose file with latest modification time

    • Best for: Active editing workflows
    • Assumption: Latest edit is the intended version
  2. largest-size: Choose largest file

    • Best for: Resolution upgrades, lossless workflows
    • Assumption: Larger = higher quality or more content
  3. highest-quality: Analyze metadata to determine quality

    • Best for: Re-encoding workflows
    • Considers: Bitrate, resolution, codec efficiency
  4. highest-resolution: Choose highest resolution (images/video)

    • Best for: Archival, print media
    • Considers: Pixel dimensions only
  5. highest-bitrate: Choose highest bitrate (audio/video)

    • Best for: Audio mastering, video production
    • Considers: Data rate regardless of codec
  6. 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

  1. Before Merging:

    • Ensure working tree is clean
    • Review changes with mediagit log
    • Consider impact with mediagit diff
  2. During Merge:

    • Read conflict messages carefully
    • Test media files after resolution
    • Verify quality hasn’t degraded
  3. 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 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 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

ScenarioRecommended
Bring specific fix to another branchcherry-pick
Integrate all work from a branchmerge
Move a series of commits onto new baserebase
Undo a specific commitrevert

Exit Status

  • 0: Success
  • 1: Conflicts detected, manual resolution required
  • 2: Commit not found or invalid operation

See Also

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 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 files
  • PATHS — 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 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

ModeBranch pointerStaging areaWorking tree
--softMovedUnchangedUnchanged
--mixedMovedResetUnchanged
--hardMovedResetReset (destructive)

Exit Status

  • 0: Success
  • 1: Commit not found or invalid options

See Also

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

SituationCommand
Undo commits that haven’t been pushedreset --hard
Undo pushed commits (preserve history)revert
Keep the change but remove from branchreset --soft
Undo a specific old commit in historyrevert <hash>

Exit Status

  • 0: Success
  • 1: Conflicts detected, manual resolution required
  • 2: Commit not found or invalid operation

See Also

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

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 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

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 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

  1. Review changes:

    $ mediagit log origin/main..HEAD
    $ mediagit diff origin/main..HEAD
    
  2. Ensure tests pass:

    $ mediagit push --dry-run
    
  3. Check remote state:

    $ mediagit fetch
    $ mediagit status
    

When Pushing

  1. Use descriptive branch names
  2. Set upstream tracking (-u on first push)
  3. Avoid force push to shared branches
  4. Use --force-with-lease instead of --force

After Pushing

  1. Verify success:

    $ mediagit log origin/main
    
  2. 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 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

  1. Commit or stash local changes:

    $ mediagit status
    $ mediagit commit -m "Save work in progress"
    # or
    $ mediagit stash
    
  2. Review remote changes:

    $ mediagit fetch
    $ mediagit log ..origin/main
    

When Pulling

  1. Use rebase for clean history (feature branches):

    $ mediagit pull --rebase
    
  2. Use merge for shared branches (main, develop):

    $ mediagit pull --no-ff
    
  3. Enable optimization for large repositories:

    $ mediagit pull --optimize-transfer --parallel=8
    

After Pulling

  1. Verify changes:

    $ mediagit log -3
    $ mediagit status
    
  2. 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

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
# 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 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 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-chunks after downloads
  • Use --deep only when investigating corruption
  • Batch verification with --parallel for efficiency

See Also

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.

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 gc for most accurate stats
  • Statistics cached for performance (5 min TTL)
  • Use --force to 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 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 created
  • reset — Branch pointer moved with reset
  • checkout — Switched branch with branch switch
  • merge — Branches merged
  • rebase — Commits rebased
  • cherry-pick — Commits applied via cherry-pick
  • revert — Revert commit created

Exit Status

  • 0: Success
  • 1: Ref not found or reflog is empty

See Also

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 (Backend trait)
  • 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: Backend trait with 7 implementations
  • Benefit: Easy testing (mock backends), cloud provider flexibility

Performance Characteristics

OperationLocal BackendS3 BackendOptimization
Add 1GB file~2-3 seconds~15-20 secondsDelta encoding for updates
Commit<100ms~200-500msMetadata-only operation
Checkout~3-5 seconds~20-30 secondsParallel object fetch
Merge~1-2 seconds~5-10 secondsMedia-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 verify for 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 verification
  • mediagit verify: Cryptographic object verification
  • mediagit stats: Repository statistics and health metrics

Extension Points

Custom Merge Strategies

  • Implement MergeStrategy trait
  • Register strategy in MergeEngine
  • Example: Custom video frame merging

Storage Backend Development

  • Implement Backend trait
  • Provide get, put, exists, delete, list operations
  • Example: IPFS backend, SFTP backend

Media Format Support

  • Implement format parser (e.g., FBX, Blender, CAD)
  • Register with MediaIntelligence module
  • 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)

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

  1. Automatic Deduplication: Identical files stored only once
  2. Integrity Verification: Hash mismatch = corruption detected
  3. Distributed Sync: Objects identifiable across repositories
  4. 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 branch
    • refs/tags/v1.0 → points to tagged release commit
    • HEAD → 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 gc optimizes long chains

Compression Strategy

MediaGit employs intelligent compression based on file type:

Compression Algorithms

  1. zstd (default): Fastest, good ratio for all file types
  2. brotli: Better ratio for text/code, slower
  3. 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

  1. Mark Phase: Traverse from all refs, mark reachable objects
  2. Sweep Phase: Delete unmarked objects
  3. 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

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 gc optimizes 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 SizeChunking StrategyChunk Count
< 5-10 MB (type-dependent)No chunking (single blob)1
5-100 MBFastCDC (1 MB avg)5-100
100 MB - 10 GBFastCDC (2 MB avg)50-5000
> 10 GBFastCDC (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

  1. Mark: Traverse from all refs
  2. Sweep: Delete unmarked objects
  3. Repack: Optimize delta chains
  4. 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.

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):

  1. Verify content matches
  2. If content differs, abort (catastrophic error)
  3. 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())
}
}

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-versioningDeltaEncoder using 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

  1. Compare new chunk with similar base chunk (via SimilarityDetector)
  2. Use base chunk as a zstd dictionary: zstd::bulk::Compressor::with_dictionary(19, base)
  3. Compress target chunk against the dictionary
  4. 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_DEPTH in odb.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 TypeExampleThresholdRationale
Creative/PDFAI, InDesign, PDF0.15Compressed streams shift bytes; structural similarity remains
OfficeDOCX, XLSX, PPTX0.20ZIP containers with shared structure
VideoMP4, MOV, AVI, MKV0.50Metadata/timeline changes significant
AudioWAV, AIFF, MP3, FLAC0.65Medium threshold
ImagesJPG, PNG, PSD0.70Perceptual similarity
3D ModelsOBJ, FBX, BLEND, glTF, GLB0.70Vertex/animation changes
Text/CodeTXT, PY, RS, JS0.85Small changes matter
ConfigJSON, YAML, TOML, XML0.95Exact matches preferred
DefaultUnknown types0.30Global 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 SizeDetection TimeTypical Savings
10 MB0.1s15–45%
100 MB0.5s20–50%
1 GB2-3s25–65%

Trade-off: Small detection cost for significant storage savings

Delta Generation

Process

  1. Read base version from ODB
  2. Read new version from working directory
  3. Generate delta (zstd dictionary at chunk level)
  4. If delta < 80% of full object, store delta
  5. 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

  1. Identify delta chain: target ← delta3 ← delta2 ← delta1 ← base
  2. Read base object
  3. Apply deltas in sequence
  4. 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-deltas reoptimizes chains

Garbage Collection Integration

Recompression

mediagit gc optimizes delta chains:

  1. Identify long chains (depth >10)
  2. Create new base from most recent version
  3. Regenerate deltas from new base
  4. 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 fsck verified.

FormatDelta EfficiencyOverhead
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

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 TypeSizeAlgorithmSavingsThroughput
PSD-xl (Photoshop)213 MBzstd-1970.9% (3.44x)4.0 MB/s
FBX-ascii (3D)16 MBzstd/brotli81.0% (5.27x)0.27 MB/s
DAE (Collada 3D)8.6 MBzstd/brotli81.4% (5.37x)0.39 MB/s
SVG (Vector)496 KBbrotli80.8% (5.20x)1.90 MB/s
WAV (Uncompressed Audio)54 MBzstd-1954.1% (2.18x)1.04 MB/s
GLB (3D Binary)13 MBzstd50.6% (2.03x)0.77 MB/s
MP4 (Video)4.9 MBStore0% (1.00x)27 MB/s
FLAC (Audio)37 MBStore0% (1.00x)1.28 MB/s
ZIP (Archive)656 MBStore0% (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" }

Storage Backends

MediaGit supports 7 storage backends through a unified trait-based abstraction.

Available Backends

  1. Local - File system storage
  2. S3 - Amazon S3
  3. Azure - Azure Blob Storage
  4. GCS - Google Cloud Storage
  5. B2 - Backblaze B2
  6. MinIO - Self-hosted S3-compatible
  7. 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

BackendBest ForCostPerformance
LocalDevelopment, small teamsFreeFastest
S3Production, global teams$$$Excellent
AzureMicrosoft ecosystem$$$Excellent
GCSGoogle Cloud users$$$Excellent
B2Cost-effective archival$Good
MinIOSelf-hosted, complianceFree*Excellent
SpacesSimple 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

  1. Parse file format structure
  2. Identify layers/tracks/channels
  3. Merge at structural level
  4. 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 verify for 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

  1. Use IAM roles (avoid hardcoded keys)
  2. Enable bucket versioning
  3. Regular mediagit verify checks
  4. Restrict branch protection rules
  5. 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

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:

  1. File size - Must be >10MB
  2. File similarity - Content similarity above threshold
  3. File type - Media-aware thresholds
  4. Savings check - Delta must be <90% of full size

Similarity Thresholds by File Type

File TypeThresholdBehavior
AI/PDF/InDesign0.15Very aggressive (compressed streams, structural similarity)
DOCX/XLSX/PPTX (Office)0.20Aggressive (ZIP containers, shared structure)
MP4/MOV (Video)0.50Moderate (metadata/timeline changes)
WAV/AIF (Audio)0.65Medium (clip edits)
PSD/JPG/PNG (Images)0.70Moderate (perceptual similarity)
FBX/OBJ/BLEND (3D Models)0.70Moderate (geometry changes)
TXT/Code0.85Conservative (small changes matter)
JSON/YAML/TOML (Config)0.95Very conservative (exact matches preferred)
Default0.30Global 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 SizeEncoding TimeThroughput
10 MB0.1s100 MB/s
100 MB0.8s125 MB/s
500 MB4.2s119 MB/s
1 GB8.7s115 MB/s

Reconstruction Speed

Chain DepthFile SizeReconstruction Time
1-5500 MB0.5s (1000 MB/s)
6-10500 MB1.2s (416 MB/s)
11-20500 MB2.8s (178 MB/s)
21-50500 MB6.5s (77 MB/s)
>50500 MB15s+ (33 MB/s)

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 typeThroughputNotes
PSD (72–181 MB)72–119 MB/sZstd Best; layer data compresses well
MP4/MOV (5–398 MB)146–174 MB/sPre-compressed; store-mode, zero CPU overhead
GLB (14–25 MB)3.0–5.2 MB/sGLB parser + CDC chunking + Zstd
WAV (55–57 MB)2.1–3.6 MB/sRIFF parser + chunking (CPU-bound)
Pre-compressed (JPEG, USDZ)25–182 MB/sDirect 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:

FormatStrategyReason
JPEG, PNG, WebPStore (level 0)Already compressed
MP4, MOV, AVIStoreAlready compressed
ZIP, DOCX, XLSXStoreZIP container
PDF, AI, InDesignStoreContains compressed streams
PSDZstd BestRaw layer data compresses well
OBJ, FBX, GLB, STLZstd BestBinary 3D data
WAV, FLACZstd DefaultUncompressed audio
Text, JSON, TOMLZstd DefaultHighly 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 / typeChunkerTypical chunk count
< 10 MBFastCDC (small)2–10
10–100 MBFastCDC (medium)10–100
> 100 MBStreamCDC100–2000
MP4 / MKV / WebMVideo container-aware1 per GOP
WAVAudio-awareFixed-size segments
PSDLayer-aware1 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:

BackendUploadDownloadNotes
Local filesystem200–500 MB/s200–500 MB/sLimited by disk I/O
MinIO (local)100–300 MB/s200–500 MB/sValidated: 108 MB/s upload
Amazon S350–200 MB/s100–400 MB/sDepends on region + instance
Azure Blob50–150 MB/s100–300 MB/s
Google Cloud Storage50–200 MB/s100–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 --jobs to the CI runner’s CPU count (nproc on Linux)
  • Avoid re-verifying in CI: mediagit fsck is fast; mediagit verify does 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:

  1. --author "Name <email>" CLI flag
  2. MEDIAGIT_AUTHOR_NAME / MEDIAGIT_AUTHOR_EMAIL env vars
  3. [author] section in .mediagit/config.toml
  4. $USER environment 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

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/

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:

  1. Regular pushes to a remote on a different server or cloud provider
  2. Daily archives of .mediagit/ directory stored offsite
  3. Weekly mediagit fsck to detect corruption early
  4. Monthly restore test — actually restore from backup to confirm it works
  5. 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

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 typeTypical savings vs raw files
Design iterations (PSD, AI)40–80% via delta encoding
Video master + proxy pairs15–30% via deduplication of shared frames
Photo series10–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:

VariablePurpose
MEDIAGIT_REPOOverride repository path (used by -C flag)
MEDIAGIT_AUTHOR_NAMECommit author name
MEDIAGIT_AUTHOR_EMAILCommit author email
AWS_ACCESS_KEY_IDS3 access key
AWS_SECRET_ACCESS_KEYS3 secret key
AWS_REGIONS3 region
AWS_ENDPOINT_URLCustom S3 endpoint (MinIO, etc.)
AZURE_STORAGE_CONNECTION_STRINGAzure Blob connection string
GCS_EMULATOR_HOSTGCS 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 N to match your runner’s CPU count
  • Cache: The .mediagit/ directory can be cached between CI runs for faster operations
  • Shallow operations: mediagit log -1 for 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_ID and AWS_SECRET_ACCESS_KEY secrets are set
  • Check that the IAM role/user has s3:GetObject, s3:PutObject, s3:ListBucket permissions

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/repo to specify the repository root explicitly
  • Or set MEDIAGIT_REPO environment 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 sizeChunkerTypical chunksStrategy
< 10 MBFastCDC (small params)2–10Single-threaded
10–100 MBFastCDC (medium params)10–100Single-threaded
> 100 MBStreamCDC100–2000Parallel workers
MP4 / MKV / WebMVideo container-aware1 per GOPPer-format
PSDLayer-aware1 per layer groupPer-format
WAVFastCDCAdaptive by sizePer-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 typeSequentialParallel (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:

  1. File-level: multiple files processed concurrently (bounded semaphore)
  2. 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 typeNotes
MP4 / MOV / MKVAlready compressed; stored as-is. Deduplication works at GOP level.
JPEG / PNG / WebPAlready compressed; stored as-is. No re-compression overhead.
PSD / PSBLayer-aware chunking + Zstd compression. Excellent delta savings per revision.
TIFF (uncompressed)Zstd compresses well. Large but effective delta encoding.
EXRTypically compressed. Stored as-is.
WAV / AIFFAudio-aware chunking. Zstd compresses ~40–60% on uncompressed audio.
PDF / AI / InDesignPDF containers with internal compression; stored as-is.
ZIP / DOCX / XLSXZIP containers; stored as-is.
3D (OBJ, FBX, GLB, STL)Binary 3D data; Zstd Best compression applied.

See Also

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.

KeyTypeDefaultDescription
namestring$USERDisplay name on commits
emailstring""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"
KeyTypeDefaultDescription
backendstring"filesystem"Must be "filesystem"
base_pathstring"./data"Storage root directory
create_dirsbooltrueAuto-create directories
syncboolfalseSync writes to disk (slower, safer)
file_permissionsstring"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
KeyTypeDefaultDescription
backendstringMust be "s3"
bucketstringRequired. S3 bucket name
regionstringRequired. AWS region
access_key_idstringenvAWS access key (prefer env var)
secret_access_keystringenvAWS secret key (prefer env var)
endpointstringCustom endpoint for S3-compatible services
prefixstring""Object key prefix
encryptionboolfalseEnable server-side encryption
encryption_algorithmstring"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
KeyTypeDefaultDescription
backendstringMust be "azure"
account_namestringRequired. Storage account name
containerstringRequired. Blob container name
account_keystringenvStorage account key (prefer env var)
connection_stringstringenvFull connection string (alternative to account_name/key)
prefixstring""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
KeyTypeDefaultDescription
backendstringMust be "gcs"
bucketstringRequired. GCS bucket name
project_idstringRequired. GCP project ID
credentials_pathstringenvPath to service account JSON key
prefixstring""Object prefix

[compression] — Compression Settings (Informational)

Note: MediaGit uses SmartCompressor which automatically selects the optimal algorithm and level per file type. The values in this section are written to config.toml by mediagit init for reference but are not read at runtime — compression behavior is determined entirely by file type, not these settings.

KeyTypeDefaultDescription
enabledbooltrue(Informational) SmartCompressor is always active
algorithmstring"zstd"(Informational) Actual algorithm selected per file type
levelinteger3(Informational) Actual level selected per file type
min_sizeinteger1024(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: zstd at Best level (level 22)
  • Text, JSON, TOML: zstd at Default level (level 3)
  • ML checkpoints: zstd at Fast level (level 1)

[performance] — Performance Tuning

KeyTypeDefaultDescription
max_concurrencyintegerCPU count (min 4)Max parallel operations
buffer_sizeinteger65536I/O buffer size in bytes (64 KB)

[performance.cache]

KeyTypeDefaultDescription
enabledbooltrueEnable in-memory object cache
cache_typestring"memory"Cache type ("memory")
max_sizeinteger536870912Max cache size in bytes (512 MB)
ttlinteger3600Cache entry TTL in seconds
compressionboolfalseCompress cached objects

[performance.connection_pool]

KeyTypeDefaultDescription
min_connectionsinteger1Minimum pool connections
max_connectionsinteger10Maximum pool connections
timeoutinteger30Connection timeout in seconds
idle_timeoutinteger600Idle connection timeout in seconds

[performance.timeouts]

KeyTypeDefaultDescription
requestinteger60Total request timeout in seconds
readinteger30Read timeout in seconds
writeinteger30Write timeout in seconds
connectioninteger30Connection timeout in seconds

[observability] — Logging and Tracing

KeyTypeDefaultDescription
log_levelstring"info"Log level: "error", "warn", "info", "debug", "trace"
log_formatstring"json"Log format: "json" or "text"
tracing_enabledbooltrueEnable distributed tracing
sample_ratefloat0.1Trace sampling rate (0.0–1.0)

Override log_level with the RUST_LOG environment variable.

[observability.metrics]

KeyTypeDefaultDescription
enabledbooltrueEnable Prometheus metrics
portinteger9090Metrics HTTP server port
endpointstring"/metrics"Metrics endpoint path
intervalinteger60Collection 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"
KeyTypeDefaultDescription
urlstringRequired. Remote server URL
fetchstringurlFetch URL if different from url
pushstringurlPush 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
KeyTypeDefaultDescription
prevent_force_pushbooltrueBlock force pushes
prevent_deletionbooltrueBlock branch deletion
require_reviewsboolfalseRequire PR review before merge
min_approvalsinteger1Minimum approvals required

See Also

Environment Variables

All environment variables recognized by MediaGit. Environment variables take precedence over config.toml values where both are supported.

Core Variables

VariableDescriptionDefault
MEDIAGIT_REPOOverride 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_EMAILconfig.toml [author]$USER.

VariableDescription
MEDIAGIT_AUTHOR_NAMECommit author name (e.g., "Alice Smith")
MEDIAGIT_AUTHOR_EMAILCommit author email (e.g., "alice@example.com")

AWS / S3 / S3-Compatible Storage

Standard AWS SDK environment variables. Used when storage.backend = "s3".

VariableDescription
AWS_ACCESS_KEY_IDAWS access key ID
AWS_SECRET_ACCESS_KEYAWS secret access key
AWS_SESSION_TOKENAWS session token (for temporary credentials)
AWS_REGIONAWS region (e.g., us-east-1)
AWS_ENDPOINT_URLCustom S3 endpoint URL (for MinIO, DigitalOcean Spaces, Backblaze B2, etc.)
AWS_PROFILEAWS named profile from ~/.aws/credentials

Azure Blob Storage

Used when storage.backend = "azure".

VariableDescription
AZURE_STORAGE_CONNECTION_STRINGFull connection string (alternative to account_name + account_key)
AZURE_STORAGE_ACCOUNTStorage account name
AZURE_STORAGE_KEYStorage account key

Google Cloud Storage

Used when storage.backend = "gcs".

VariableDescription
GOOGLE_APPLICATION_CREDENTIALSPath to service account JSON key file
GCS_EMULATOR_HOSTGCS emulator URL for testing (e.g., http://localhost:4443)

Observability

VariableDescriptionDefault
RUST_LOGLog filter directive (e.g., mediagit=debug, info)info
RUST_LOG_FORMATLog output format: json or textjson

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)

VariableDescription
CARGO_TERM_COLORForce color output: always, never, auto
RUST_BACKTRACEEnable Rust backtraces: 1 or full

Integration Test Variables

Used by the CI integration test job and local integration testing:

VariableValue for local testing
AWS_ACCESS_KEY_IDminioadmin
AWS_SECRET_ACCESS_KEYminioadmin
AWS_ENDPOINT_URLhttp://localhost:9000
AWS_REGIONus-east-1
AZURE_STORAGE_CONNECTION_STRINGDefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;
GCS_EMULATOR_HOSThttp://localhost:4443

See Development Setup for running integration tests locally.

Precedence Summary

For each setting, MediaGit resolves values in this order (first match wins):

  1. CLI flag (e.g., --author "Name <email>")
  2. Environment variable (e.g., MEDIAGIT_AUTHOR_NAME)
  3. Repository config (.mediagit/config.toml)
  4. Built-in default

See Also

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

TypeDescription
blobFile content (full or delta)
treeDirectory listing: maps filenames to object hashes
commitCommit metadata: tree hash, parent hashes, author, message
chunkA 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 classStrategy
JPEG, PNG, WebP, MP4, MOV, ZIP, docx, PDF, AIStore (no compression)
PSD, 3D models (OBJ, FBX, GLB, STL, PLY)Zstd Best
WAV, FLACZstd Default
Text, JSON, TOML, CSVZstd 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 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:

FieldTypeDescription
tree[u8; 32]SHA-256 hash of the root tree object
parentsVec<[u8; 32]>Parent commit hashes (0 for initial, 1+ for merges)
authorstringAuthor name
emailstringAuthor email
timestampi64Unix timestamp (seconds)
messagestringCommit message

Tree Object Format

Trees are stored as Bincode-serialized ordered lists of entries:

FieldTypeDescription
namestringFilename (not full path)
hash[u8; 32]SHA-256 hash of the blob or subtree
is_treebooltrue for subdirectory, false for file
sizeu64Uncompressed 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

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

FeatureMediaGitGit-LFS
Git dependencyNone — standaloneRequired
Server requirementMediaGit server or cloud backendGit host with LFS support
Content-aware chunkingYes (FastCDC, StreamCDC, per-format)No
Cross-file deduplicationYes — shared chunk poolNo
Delta encodingYes — chunk-level deltasNo
Parallel ingestionYes — multi-core (--jobs)No
Cloud backendsS3, Azure, GCS, MinIO, B2, DO SpacesLFS server (varies by host)
No file size limitPractical limit: disk/networkHost-specific (e.g., 2 GB on GitHub free)
Format-aware compressionYes — JPEG/MP4 stored as-isNo — always uploads raw bytes
Offline historyFull history locallyPointer only; content fetched on demand
Git compatibilityNot compatibleFull Git compatibility
Windows ARM64Build from sourcePart 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

FileGit-LFSMediaGit (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

  1. No Git required — deploy MediaGit independently of your code repository
  2. Content-aware chunking — PSD layers, video frames, and audio segments are split at format boundaries for better deduplication
  3. Cross-file deduplication — identical frames in different videos share storage
  4. Delta encoding — only differences are stored for similar versions
  5. Parallel ingestion — 10–20× faster than sequential on multi-core hardware
  6. Format-aware compression — pre-compressed formats (JPEG, MP4) are not re-compressed, saving CPU cycles
  7. No host file size limits — no GitHub-imposed 2 GB limit
  8. Self-hosted options — MinIO, local filesystem, or any S3-compatible service

Advantages of Git-LFS

  1. Git compatible — works with GitHub, GitLab, Bitbucket, and any Git host
  2. Familiar workflow — same git add / commit / push commands
  3. Mature ecosystem — LFS support is built into all major Git hosting platforms
  4. 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.

SituationRecommendation
Code + small assets (<100 MB total)Git-LFS or plain Git
Media-first pipeline (game art, VFX, video)MediaGit
Existing GitHub workflow, want LFSGit-LFS
Self-hosted, storage cost mattersMediaGit
1TB+ media repositoriesMediaGit
Need Git compatibilityGit-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:

MediaGitGit-LFS
Git requiredNo — fully standaloneYes — wraps Git
ChunkingContent-aware chunking (FastCDC, StreamCDC)No chunking
Delta encodingYes — chunk-level deltasNo
DeduplicationCross-file chunk deduplicationNo deduplication
Parallel ingestionYes — multi-coreNo
Cloud backendsS3, Azure, GCS, MinIO, B2Server-specific
File size limitNo practical limitDepends 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:

BackendBest for
Local filesystemDevelopment, single-machine use
Amazon S3AWS-hosted projects, widest ecosystem
MinIOSelf-hosted S3-compatible, on-premise
Azure BlobAzure-hosted projects
Google Cloud StorageGCP-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:

  1. Export your Git-LFS files: git lfs pull
  2. Initialize a MediaGit repository: mediagit init
  3. Add the exported files: mediagit add --all
  4. 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):

  1. --author "Name <email>" CLI flag
  2. MEDIAGIT_AUTHOR_NAME / MEDIAGIT_AUTHOR_EMAIL environment variables
  3. [author] section in .mediagit/config.toml
  4. $USER environment 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

  1. Fork the repository
  2. Create feature branch
  3. Make changes
  4. Submit pull request

Code of Conduct

See Code of Conduct.

Development Setup

A complete guide for setting up MediaGit for development and contribution.

Prerequisites

ToolVersionPurpose
Rust1.92.0+Language toolchain (MSRV)
Docker20.10+Integration test emulators
Git2.xSource 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:

HookWhat it enforces
pre-commitcargo fmt --check, cargo clippy --workspace, AGPL license headers, 5MB file size limit, conflict markers
pre-pushcargo test --workspace — all tests must pass
commit-msgConventional 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

  1. Create crates/mediagit-cli/src/commands/mycommand.rs
  2. Derive clap::Parser on your args struct
  3. Add pub mod mycommand; to commands/mod.rs
  4. Add a variant to the Commands enum in main.rs
  5. Wire up execution in main.rs match arm

Adding a New Storage Backend

  1. Implement the Backend trait in mediagit-storage
  2. Add a variant to StorageConfig enum in mediagit-config/src/schema.rs
  3. Wire up construction in the storage factory
  4. Add integration tests with #[ignore] and an emulator
  5. 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/mediagit works from WSL2
  • The Windows PE binary (mediagit.exe) requires building from Windows cmd or 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

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 release
  • v0.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)

TargetPlatformTool
x86_64-unknown-linux-gnuLinux x64cargo
aarch64-unknown-linux-gnuLinux ARM64cross
x86_64-apple-darwinmacOS Intelcargo
aarch64-apple-darwinmacOS Apple Siliconcargo
x86_64-pc-windows-msvcWindows x64cargo

Both mediagit and mediagit-server binaries are built and archived.

Note: Windows ARM64 (aarch64-pc-windows-msvc) is not released — cross-rs does 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):

  1. Tier 0: mediagit-config, mediagit-security, mediagit-observability, mediagit-compression, mediagit-storage, mediagit-media, mediagit-git
  2. Tier 1: mediagit-versioning, mediagit-metrics, mediagit-migration
  3. Tier 2: mediagit-protocol
  4. 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

SecretValue
CARGO_REGISTRY_TOKENcrates.io API token with publish scope
GITHUB_TOKENAuto-provided by GitHub Actions

Dry Run

Test the release workflow without publishing:

  1. Go to Actions → Release → Run workflow
  2. Check Dry run checkbox
  3. 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:

  1. Verify GitHub Releases has all assets
  2. Verify crates on crates.io
  3. Verify Docker image: docker pull ghcr.io/winnyboy5/mediagit-core:latest
  4. Update the documentation site if needed
  5. 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