Minigit: A simplified but functional Git implementation in pure Python to understand how Git works behind the scenes.
- Repository initialization (init)
- Staging files (add)
- Creating commits (commit)
- Viewing status (status)
- Showing diffs (diff)
- Commit history with visualization (log)
- GitHub repository creation (create-repo) (NEW)
- Push to remote repositories (push)
- Content-addressable object storage
- Index/staging area
- Tree and blob objects
- Pack file generation for network transfer
- Zero external dependencies (pure Python stdlib)
Minigit demonstrates:
- How Git stores objects (blobs, trees, commits)
- How the staging area works
- How commits form a DAG (directed acyclic graph)
- How push protocol works
- Why Git is so fast and efficient
From Source
git clone https://github.com/Andrew011123/minigit.git
cd minigit
pip install -e .
Using Docker
docker build -t minigit
docker run -it minigit
Quick Start
# Initialize a repository
minigit init my-repo
cd my-repo
# Create a file
echo "Hello, Git!" > README.md
# Stage the file
minigit add README.md
# Check status
minigit status
# Commit
export GIT_AUTHOR_NAME="Your Name"
export GIT_AUTHOR_EMAIL="you@example.com"
minigit commit -m "Initial commit"
# View history
minigit log
# See what changed
echo "More content" >> README.md
minigit diff
# Create a GitHub repository (requires personal access token)
export GITHUB_TOKEN="your_token_here"
minigit create-repo my-new-repo -t $GITHUB_TOKEN
# Push to the new remote repository
minigit push https://github.com/username/my-new-repo.git -u username -p token
Commands
| Command | Description | Example |
|---|---|---|
init |
Initialize a new repository | minigit init my-repo |
add |
Stage files for commit | minigit add file1.txt file2.txt |
status |
Show working tree status | minigit status |
commit |
Record changes to repository | minigit commit -m "Add feature" |
diff |
Show changes between index and working tree | minigit diff |
log |
Show commit history | minigit log -n 10 |
ls-files |
List files in index | minigit ls-files -s |
cat-file |
Display object contents | minigit cat-file pretty abc123 |
hash-object |
Compute object hash | minigit hash-object file.txt -w |
create-repo |
Create a GitHub repository | minigit create-repo my-repo -t token |
push |
Update remote refs | minigit push <url> -u user -p pass |
info |
Show repository information | minigit info |
Architecture
minigit/
├── __init__.py # Package initialization
├── core.py # Object storage (hash, read, write)
├── index.py # Staging area operations
├── tree.py # Tree object handling
├── commit.py # Commit operations
├── diff.py # Diff generation
├── network.py # Push protocol (Git)
├── github_api.py # GitHub REST API client
├── repository.py # Repository management
├── cli.py # Command-line interface
└── exceptions.py # Custom exceptions
Object Storage
Git stores everything as objects identified by SHA-1 hashes:
# Create a blob object
content = b"Hello, World!"
header = b"blob 13\x00"
full_data = header + content
sha1 = hashlib.sha1(full_data).hexdigest()
# Store at .git/objects/af/5626b4a114...
The Index (Staging Area)
Binary file at .git/index containing:
- File metadata (timestamps, permissions, size)
- SHA-1 hash of file contents
- Path name
Commits
tree abc123def456...
parent 789ghi012jkl...
author Name <email> 1234567890 -0800
committer Name <email> 1234567890 -0800
Commit message goes here
Tree Objects
100644 blob 5716ca... README.md
100644 blob 551156... main.py
040000 tree 99a456... src/
Testing
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# With coverage
pytest tests/ --cov=minigit --cov-report=html
# Run specific test
pytest tests/test_minigit.py::TestRepository::test_init_creates_structure
Limitations
This is an educational implementation with some intentional simplifications:
- No subdirectories: Only supports flat file structure (single directory level)
- No merging: Doesn't implement merge algorithm
- No branches: Only master branch supported
- No fetch/pull: Only push is implemented
- No .gitignore: All files are tracked
- No submodules: Not supported
- Basic diff: Unified diff only, no word-diff or other formats
Comparison with Real Git
| Feature | MiniGit | Git |
|---|---|---|
| Object storage | ✅ | ✅ |
| Commits | ✅ | ✅ |
| Trees and blobs | ✅ | ✅ |
| Index/staging | ✅ | ✅ |
| Push | ✅ | ✅ |
| Branches | ❌ | ✅ |
| Merge | ❌ | ✅ |
| Fetch/Pull | ❌ | ✅ |
| Subdirectories | ❌ | ✅ |
| Delta compression | ❌ | ✅ |
| Garbage collection | ❌ | ✅ |
| Performance | Slow | Fast (C) |
Learning Resources
- Code Comments: Every function is documented
- Tests: tests/test_minigit.py shows usage examples
Examining Objects
# Hash a file
minigit hash-object myfile.txt -w
# View object type
minigit cat-file type abc123
# View object size
minigit cat-file size abc123
# Pretty-print object
minigit cat-file pretty abc123
Index Operations
# List files in index
minigit ls-files
# List with details (mode, hash, stage)
minigit ls-files -s
Repository Info
# Show repo information
minigit info
Output:
Repository Information:
Path: /home/user/my-repo
Git directory: /home/user/my-repo/.git
Current branch: refs/heads/master
Objects stored: 42
Creating Repositories
Minigit can create GitHub repositories directly using the GitHub REST API:
# Create a public repository
minigit create-repo my-awesome-project -t YOUR_GITHUB_TOKEN
# The command returns the clone URL:
# https://github.com/yourusername/my-awesome-project.git
# Then you can push to it
minigit push https://github.com/yourusername/my-awesome-project.git -u username -p tokenGetting a GitHub Token
- Go to GitHub Settings → Developer Settings → Personal Access Tokens → Tokens (classic)
- Click "Generate new token"
- Give it a name and select the
reposcope - Copy the token (you won't see it again!)
- Use it with
-tflag:minigit create-repo myrepo -t ghp_yourtoken...
Complete Workflow Example
# 1. Initialize local repository
minigit init my-project
cd my-project
# 2. Create some content
echo "# My Project" > README.md
minigit add README.md
# 3. Set author info and commit
export GIT_AUTHOR_NAME="Your Name"
export GIT_AUTHOR_EMAIL="you@example.com"
minigit commit -m "Initial commit"
# 4. Create GitHub repository
export GITHUB_TOKEN="ghp_your_token_here"
CLONE_URL=$(minigit create-repo my-project -t $GITHUB_TOKEN)
# 5. Push to GitHub
minigit push $CLONE_URL -u your_username -p $GITHUB_TOKENQ: Why Python instead of C like real Git?
A: Python is more readable for educational purposes. Performance isn't the goal.
Q: Does this work with GitHub/GitLab?
A: Yes! The push command works with any Git server supporting HTTP basic auth.
Q: Can real Git read minigit repositories?
A: Yes! minigit creates standard Git objects. You can use real Git commands in a minigit repo.
This project is licensed under the MIT License — see the LICENSE.txt file for details.
This work (made to educate myself on the inner workings of git) was inspired by pygit by Ben Hoyt (MIT Licensed). Significant advancements and extensions have been made beyond the original implementation, including expanded functionality, refactored architecture, and new features.
Author Andrew Johnson