MiniGit is a tiny educational content-addressed version control system written in C.
It is not a replacement for Git.
The goal of this project is to learn how a version control system can be built from basic concepts:
- command-line parsing
- file I/O
- directory management
- content hashing
- object storage
- staging area
- commit metadata
- status inspection
- restoring older file versions
- checking out snapshots
- simple line-by-line diff
This version is primarily designed for Linux/POSIX environments.
MiniGit currently supports:
- initializing a local repository
- adding files to an index
- staging file deletions
- saving file contents as objects
- creating commits
- tracking deleted files inside commits
- explicit index and commit entry formats using
TRACKandDELETE - Git-like staged and unstaged change detection
- viewing the commit log
- showing a file from a previous commit
- restoring a single file from a previous commit
- checking out repository snapshots
- checkout cleanup for files tracked by previous snapshots
- simple line-by-line diff inspection
- repository validation before command execution
- prevention of empty commits when no changes are staged
After running:
minigit initMiniGit creates:
.minigit/
├── HEAD
├── index
├── objects/
└── commits/
Stores the latest commit number.
Example:
2
Stores the staged files and staged deletions.
Example:
TRACK main.c 123456789
TRACK README.md 987654321
DELETE old.txt
Stores real file contents.
Example:
.minigit/objects/249889038256978411.obj
Stores commit metadata and snapshot entries.
Example:
.minigit/commits/1.txt
Commit file example:
commit: 1
message: Initial commit
files:
TRACK file.txt 249889038256978411
DELETE old.txt
Compile with GCC:
gcc -Wall -Wextra -pedantic -std=c11 minigit.c -o minigitInstall globally on Linux:
sudo cp minigit /usr/local/bin/After that you can run:
minigitfrom anywhere.
minigit initminigit add file.txtThis command:
- checks if the file exists
- calculates its hash
- stores the file content inside
.minigit/objects/ - stages the file using a
TRACKentry inside the index
minigit rm file.txtThis command:
- removes the file from the working tree
- stages the deletion using a
DELETEentry inside the index - allows the deletion to be committed later
minigit statusPossible output:
Changes staged for commit:
modified: file.txt
deleted: old.txt
Changes not staged for commit:
modified: main.c
Or:
Working tree clean.
minigit commit "Initial commit"If the index already matches the latest commit:
Nothing to commit.
minigit logExample:
commit: 2
message: Second version
commit: 1
message: Initial commit
minigit show 1 file.txtThis prints the version of file.txt stored in commit 1.
minigit restore 1 file.txtThis restores only file.txt from commit 1.
minigit checkout 1This restores all files tracked by commit 1, updates HEAD, and rewrites the index to match that commit.
MiniGit also removes files that were tracked in the current index but are not present in the selected commit.
minigit diff file.txtExample:
Line 2 differs:
INDEX : old line
WORK : new line
If the file is staged for deletion:
File 'file.txt' is staged for deletion.
gcc -Wall -Wextra -pedantic -std=c11 minigit.c -o minigit
minigit init
echo "version 1" > file.txt
minigit add file.txt
minigit commit "First version"
echo "version 2" >> file.txt
minigit status
minigit diff file.txt
minigit add file.txt
minigit commit "Second version"
minigit log
minigit show 1 file.txt
minigit restore 1 file.txtecho "temporary file" > old.txt
minigit add old.txt
minigit commit "Add old file"
minigit rm old.txt
minigit status
minigit commit "Remove old file"MiniGit uses a simplified content-addressed storage model.
When a file is added:
file content -> hash -> object file
For example:
file.txt -> 249889038256978411 -> .minigit/objects/249889038256978411.obj
The index and commit files use explicit entries:
TRACK filename hash
DELETE filename
MiniGit internally manages three states:
Working Tree
Index (staging area)
HEAD (latest commit)
The status command compares these states to detect:
- staged changes
- unstaged changes
- staged deletions
- clean working trees
The checkout command restores a selected commit snapshot and rewrites the index to match it.
MiniGit is intentionally simple.
It does not currently support:
- branches
- merge
- recursive directory tracking
- file names containing spaces
- cryptographic hashing
- remote repositories
- push / pull
- partial staging
- binary diff visualization
- full untracked-file cleanup during checkout
- commit parent chains or DAG history
The hash function used in this project is based on djb2.
It is useful for learning, but it is not secure.
Real Git historically used SHA-1 and also supports SHA-256 in newer repositories.
This project is released for educational purposes.
You can use, modify, and share it freely.