Fit is a production-grade distributed version control and backup system inspired by Git's internal architecture, written in C from scratch. It functions as both a version control system and a distributed personal backup solution between Linux machines.
Fit reimplements Git's core concepts:
- Content-addressable storage using SHA-256 hashing
- Object model: blobs (files), trees (directories), commits
- Compression: zlib compression for all objects
- Packfiles: efficient object transfer format
- References: branches and HEAD management
- Garbage collection: removes unreachable objects
- Network protocol: custom TCP-based object transfer
- SHA-256 by default (Git uses SHA-1, transitioning to SHA-256)
- Simplified protocol - custom lightweight TCP protocol with smart negotiation
- Backup-first design - includes
snapshotcommand for quick full-directory backups - Minimal dependencies - only zlib and OpenSSL
- No delta compression yet - stores full objects (stretch goal)
- RSA-signed commits - built-in commit signing with RSA keys
- Shallow clone support - clone with limited history depth
.fit/
├── objects/
│ └── ab/
│ └── cdef123... (compressed object)
├── refs/
│ └── heads/
│ └── main
├── HEAD
├── index
└── config
- Blob: Raw file content
- Tree: Directory listing with modes, names, and hashes
- Commit: Points to tree, parent commit, author, timestamp, message
<type> <size>\0<data>
Compressed with zlib and stored at .fit/objects/<first-2-hex>/<remaining-hex>.
Extensible TCP protocol on port 9418 with version negotiation:
[VERSION:1][COMMAND:1][PACKFILE_DATA]
[VERSION:2][CMD_NEGOTIATE:3]
[CLIENT_MIN_VER:1][CLIENT_MAX_VER:1][CLIENT_CAPS:4]
[SERVER_MIN_VER:1][SERVER_MAX_VER:1][SERVER_CAPS:4]
[COMMAND:1][PACKFILE_DATA]
Commands:
CMD_SEND_OBJECTS (1): Send packfile to serverCMD_REQUEST_OBJECTS (2): Request objects from serverCMD_NEGOTIATE (3): Initiate protocol negotiation
Capabilities:
CAP_MULTI_THREADED: Server supports concurrent connectionsCAP_COMPRESSION: Enhanced compression supportCAP_STREAMING: Optimized streaming transfer
The protocol automatically negotiates the highest common version and capability set between client and server, with automatic fallback to legacy protocol v1 for backward compatibility.
Fit includes built-in commit signing using RSA-2048 keys, providing cryptographic verification of commit authorship without requiring external GPG setup.
- Key Generation:
fit init-signinggenerates a private/public key pair - Signing: Use
--signor-Sflag when committing - Verification:
fit verify-commit <hash>verifies signatures - Keys stored in:
.fit/private_key.pemand.fit/public_key.pem
fit init-signing
fit commit -m "Secure commit" --sign
fit verify-commit abc123Clone repositories with limited history depth, saving bandwidth and disk space for large repositories.
- Shallow Clone:
fit clone <host> <branch> [dir] --depth <N> - History Limit: Only fetches the last N commits
- Boundary Marker:
.fit/shallowfile tracks shallow boundaries - Log Display:
fit logshows "(shallow boundary)" at truncation point
fit clone server.local main ./project --depth 10# Install dependencies
sudo pacman -S gcc make zlib openssl
# Build
make
# Install
sudo make install# Install dependencies
apk add gcc musl-dev make zlib-dev openssl-dev
# Build
make
# Install
make install# Initialize repository
fit init
# Add files
fit add file1.txt file2.txt
# Commit changes
fit commit -m "Initial commit"
# View history
fit log
# Check status
fit status
# Compare commits
fit diff <commit1> <commit2># View differences between two commits
fit diff abc123 def456
# Compare a commit with HEAD
fit diff abc123
# See what changed in recent commits
fit log # Get commit hashes
fit diff <older-hash> <newer-hash># List branches
fit branch
# Create branch
fit branch feature
# Switch branch (restores files)
fit checkout feature
# Merge branch
fit merge feature# List tags
fit tag
# Create tag
fit tag v1.0.0
# Create tag with message
fit tag create v1.0.0 -m "Release version 1.0.0"
# Delete tag
fit tag delete v1.0.0# List remotes
fit remote
# Add remote
fit remote add origin server.local
# Remove remote
fit remote remove origin# Save uncommitted changes
fit stash
# Save with message
fit stash save -m "Work in progress"
# List stashes
fit stash list
# Apply and remove stash
fit stash pop
# Remove specific stash
fit stash drop stash@1234567890# Create snapshot of entire directory
fit snapshot -m "Backup before system upgrade"
# View snapshots
fit log# Start daemon on server
fit daemon --port 9418
# Push from client
fit push server.local main
# Pull from server
fit pull server.local main
# Clone repository
fit clone server.local main ~/myproject
# Shallow clone (only last 5 commits)
fit clone server.local main ~/myproject --depth 5# Generate signing key pair (one-time setup)
fit init-signing
# Create signed commit
fit commit -m "Important change" --sign
# Alternative short flag
fit commit -m "Another change" -S
# Verify commit signature
fit verify-commit abc123def456# Restore files from a specific commit
fit restore <commit-hash>
# Or checkout a branch (restores files automatically)
fit checkout main# Run garbage collection
fit gcRun the Fit daemon 24/7 with Docker:
# Build and start server
docker-compose up -d
# View logs
docker-compose logs -f
# Stop server
docker-compose downAuto-start on boot (systemd):
# Install as system service
chmod +x install_service.sh
./install_service.sh
# Check status
sudo systemctl status fit-server
# View logs
docker-compose logs -fThis will:
- Start Fit daemon on port 9418
- Auto-restart on failure
- Auto-start on system boot
Access:
- Daemon:
fit push localhost main
# Build image
docker build -t fit:latest .
# Run daemon
docker run -d -p 9418:9418 -v fit-data:/data/.fit fit:latest
# Or use docker-compose
docker-compose up -dThe docker-compose.yml includes restart: unless-stopped for automatic startup.
For systemd on bare metal:
# Create /etc/systemd/system/fit-daemon.service
[Unit]
Description=Fit Daemon
After=network.target
[Service]
Type=simple
User=fit
ExecStart=/usr/local/bin/fit daemon --port 9418
Restart=always
[Install]
WantedBy=multi-target.target
# Enable and start
sudo systemctl enable fit-daemon
sudo systemctl start fit-daemon# Install Fit
make && sudo make install
# Initialize repository
mkdir -p ~/backup
cd ~/backup
fit init
# Start daemon
fit daemon --port 9418
# Or with Docker
docker-compose up -d# Install Fit
make && sudo make install
# Initialize repository
cd ~/projects/myproject
fit init
# Create initial snapshot
fit snapshot -m "Initial backup"
# Push to laptop
fit push laptop.local main
# Continue working...
echo "new content" > file.txt
fit add file.txt
fit commit -m "Updated file"
fit push laptop.local main# On new machine or after data loss
fit init
fit pull laptop.local main # (requires implementing pull)
# Or manually:
# 1. Copy .fit directory from backup server
# 2. Checkout desired commit# Run test suite
make test# Test hashing
echo "test" > test.txt
fit init
fit add test.txt
fit commit -m "test"
fit log
# Test network transfer
# Terminal 1:
fit daemon --port 9418
# Terminal 2:
fit push localhost main- Object storage: Each object stored separately until packed
- Compression: zlib level 6 (default) balances speed/size
- Network: Streams packfiles, no chunking yet
- Memory: Loads full objects into memory (optimize for large files later)
- Multi-threading: Daemon now supports concurrent client connections via pthreads
- No delta compression (stores full objects)
- No sparse checkout
No complex merge algorithm (fast-forward only)Three-way merge implemented- No encryption (transport or storage)
- No authentication
Single-threaded daemonMulti-threaded daemon implemented- No index v2 format (simple text format)
- Delta compression for packfiles
- Signed commits (RSA) - ✓ Implemented
- End-to-end encryption
- File chunking for large files
- Multi-threaded daemon - ✓ Implemented
- Smart protocol negotiation - ✓ Implemented
- Shallow clones - ✓ Implemented
- Submodule support
- Three-way merge algorithm - ✓ Implemented
- No authentication: Daemon accepts all connections
- No encryption: Data sent in plaintext (transport layer)
- Commit signing available: Use RSA-2048 signatures to verify commit authorship
For production use, run behind VPN or SSH tunnel:
# SSH tunnel example
ssh -L 9418:localhost:9418 laptop.local
# Then push to localhost
fit push localhost main- Check file exists and is readable
- Ensure
.fitdirectory initialized
- Verify daemon running:
netstat -ln | grep 9418 - Check firewall rules
- Test connectivity:
telnet server.local 9418
- Create initial commit before branching/pushing
src/
├── main.c - CLI interface
├── hash.c - SHA-256 hashing
├── object.c - Object storage
├── tree.c - Tree objects
├── commit.c - Commit objects
├── index.c - Staging area
├── refs.c - Reference management
├── pack.c - Packfile format
├── network.c - Network protocol
├── gc.c - Garbage collection
└── util.c - Utilities
include/
└── fit.h - Public API
tests/
└── run_tests.sh
This is a personal project demonstrating Git internals. Feel free to fork and extend.
MIT License - See LICENSE file
Inspired by:
- Git by Linus Torvalds
- "Git from the Bottom Up" by John Wiegley
- "Building Git" by James Coglan
Built from scratch without copying Git source code.
Fit - Because your filesystem belongs inside your terminal.