A lightweight, functional implementation of the Git source control system developed in Go. This project serves as a deep dive into the internal mechanics of version control, focusing on object storage, indexing, and the Merkle tree architecture.
The project implements the fundamental pillars of Git:
Everything in ugit is an object. Data is stored in the .ugit/objects directory, indexed by the SHA-1 hash of its content.
- Blobs: Store file data with a zlib-compressed header.
- Trees: Represent directory structures, linking filenames to blob or tree hashes.
- Commits: Store snapshots of the root tree along with author metadata and parent history.
The index file acts as the single source of truth between the working directory and the repository. It tracks file paths, SHA-1 hashes, and metadata to determine what has changed.
During a commit, ugit performs a post-order traversal to build a hierarchy of trees. This ensures that a single root hash represents the entire state of the project at that specific moment.
- Initialization:
ugit initsets up the internal directory structure (objects,refs,heads). - Object Hashing:
ugit hash-objectgenerates unique identifiers for content with optional write support. - Staging:
ugit addupdates the index and prepares snapshots. - Status Tracking:
ugit statuscompares the working directory, index, and latest commit to identify untracked, modified, or deleted files. - Snapshotting:
ugit commit -m "message"creates a permanent record of the staged changes. - Difference Engine:
ugit diffimplements the Myers diff algorithm to visualize line-by-line changes between the index and the working directory.
- Go 1.21 or higher installed on your system.
-
Clone the repository:
git clone https://github.com/esalama01/ugit.git ugit cd ugit -
Build the executable:
go build -o ugit
-
(Optional) Move the binary to your path:
sudo mv ugit /usr/local/bin/
Initialize a new repository:
./ugit initCheck the status:
./ugit statusStage a file:
./ugit add <filename>Create a commit:
./ugit commit -m "Your commit message"View differences:
./ugit diffCalculate the hash of a file:
./ugit hash-object <filename>
# Use -w to write the object to the database
./ugit hash-object -w <filename>.ugit/
├── HEAD # Points to the current active branch
├── index # Binary-like file representing the staging area
├── objects/ # Content-addressable database (sharded by first 2 chars of SHA-1)
└── refs/
└── heads/ # Branch pointers (e.g., main)
- Language: Go 1.21+
- Compression: Standard zlib for object storage.
- Hashing: crypto/sha1 for generating 40-character hexadecimal identifiers.
- Diff Logic: Utilizes the Myers algorithm for efficient Longest Common Subsequence (LCS) detection.
Due to the significant time and effort spent mastering the core local architecture, network-related features like ugit push and ugit clone have not been implemented in this version. However, expanding the tool to support the Git Transfer Protocol and Smart HTTP handshake remains a primary goal for future updates.