Skip to content

BeAyanK/codecrafters-git-typescript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

progress-banner

🔧 Git Implementation in TypeScript

A lightweight implementation of core Git functionality built from scratch in TypeScript/Bun. This project implements Git's internal object model, packfile protocol, and essential commands for version control operations.

📋 Overview

This is a functional Git implementation that handles:

  • Repository initialization
  • Object storage and retrieval (blobs, trees, commits)
  • Hash object creation and manipulation
  • Tree operations and directory traversal
  • Commit creation with parent tracking
  • Repository cloning with packfile parsing
  • Working directory checkout

Built as part of the CodeCrafters "Build Your Own Git" challenge.

✨ Features

🎯 Core Commands

  • init - Initialize a new Git repository
  • cat-file - Display contents of Git objects
  • hash-object - Create blob objects from files
  • ls-tree - List contents of tree objects
  • write-tree - Create tree objects from working directory
  • commit-tree - Create commit objects with metadata
  • clone - Clone remote repositories with full packfile support

🔐 Git Internals

  • Object Storage: Implements Git's content-addressable storage using SHA-1 hashing
  • Compression: Uses zlib deflate/inflate for efficient storage
  • Packfile Protocol: Full support for Git's packfile format including:
    • Pack header parsing
    • Object type identification (blob, tree, commit, tag)
    • Delta compression (ref-delta and ofs-delta)
    • Checksum validation

🌳 Object Model

Supports all core Git object types:

  • Blobs - File content storage
  • Trees - Directory structure
  • Commits - Snapshots with metadata
  • Tags - Named references (parsing support)

🚀 Getting Started

Prerequisites

  • Bun 1.1 or higher (Install Bun)
  • Basic understanding of Git concepts

Installation

  1. Clone the repository

    git clone <repository-url>
    cd git-implementation
  2. Install dependencies

    bun install
  3. Run locally

    ./your_program.sh <command> [args...]

📖 Usage

Initialize a Repository

./your_program.sh init

Creates a new .git directory with the standard structure:

.git/
├── objects/
├── refs/
└── HEAD

Read Object Contents

./your_program.sh cat-file -p <object-hash>

Displays the contents of a Git object (blob, tree, commit, or tag).

Create Object from File

./your_program.sh hash-object -w <file-path>

Creates a blob object from a file and writes it to .git/objects/.

List Tree Contents

./your_program.sh ls-tree --name-only <tree-hash>

Lists all files and directories in a tree object.

Create Tree from Working Directory

./your_program.sh write-tree

Recursively creates tree objects for the current directory structure.

Create a Commit

./your_program.sh commit-tree <tree-hash> -p <parent-hash> -m "Commit message"

Creates a commit object with the specified tree and parent commit.

Clone a Repository

./your_program.sh clone <repository-url> <directory>

Clones a remote repository including:

  • Fetching all objects via packfile
  • Parsing delta-compressed objects
  • Checking out the working directory
  • Setting up HEAD and refs

🏗️ Architecture

Project Structure

.
├── .codecrafters/
│   ├── compile.sh          # Compilation script (no-op for TypeScript)
│   └── run.sh              # Execution script for CodeCrafters
├── app/
│   └── main.ts             # Main implementation file
├── .gitignore
├── codecrafters.yml        # CodeCrafters configuration
├── package.json
├── your_program.sh         # Local execution script
└── README.md

Core Components

Object Hashing

const hashBuffer = (
  buffer: Buffer,
  type: "blob" | "tree" | "commit"
): { hash: string; content: any }

Creates SHA-1 hashes for Git objects with proper headers.

Compression

  • Compression: zlib.deflateSync() for writing objects
  • Decompression: zlib.inflateSync() for reading objects

File Operations

  • readFileSync: Reads and decompresses Git objects
  • writeFileSync: Compresses and writes Git objects
  • writeFileSyncToPath: Creates nested directories as needed

Tree Operations

  • recursiveReadDir: Recursively traverses directories to create tree objects
  • Handles file permissions (regular, executable, symlinks)
  • Sorts entries alphabetically (Git convention)

Packfile Parsing

Complex implementation supporting:

  1. Pack header validation (PACK signature)
  2. Object count parsing (network byte order)
  3. Variable-length encoding for sizes
  4. Delta decompression:
    • Ref-delta (references base object by hash)
    • Ofs-delta (references base object by offset)
  5. Instruction parsing for delta reconstruction
  6. Checksum verification

🔍 Technical Details

Object Storage Format

Git objects are stored in .git/objects/<xx>/<yy...> where <xxyy...> is the SHA-1 hash.

Object Format:

<type> <size>\0<content>

Example Blob:

blob 14\0Hello, World!

Tree Object Format

<mode> <name>\0<20-byte-hash><mode> <name>\0<20-byte-hash>...

Modes:

  • 100644 - Regular file
  • 100755 - Executable file
  • 40000 - Directory (tree)
  • 120000 - Symbolic link

Commit Object Format

tree <tree-hash>
parent <parent-hash>
author <name> <email> <timestamp> <timezone>
committer <name> <email> <timestamp> <timezone>

<commit message>

Packfile Format

Header:

PACK<version><object-count>

Object Entry:

  • Type + Size in variable-length encoding
  • Optional base reference (for deltas)
  • Compressed data (zlib)

Delta Instructions:

  • Copy instruction: 1xxxxxxx - Copy from base object
  • Insert instruction: 0xxxxxxx - Insert new data

🧪 Testing

Run with CodeCrafters test suite:

codecrafters test

Or test locally with manual commands:

# Initialize and create objects
./your_program.sh init
echo "test content" > test.txt
./your_program.sh hash-object -w test.txt

# Create and inspect trees
./your_program.sh write-tree
./your_program.sh ls-tree --name-only <tree-hash>

# Create commits
./your_program.sh commit-tree <tree-hash> -m "Initial commit"

🎓 Learning Resources

Git Internals

Technical Specifications

🛠️ Development

Code Structure

The implementation uses a switch-case pattern for command routing:

switch (command) {
  case Commands.Init:
    // Initialize repository
    break;
  case Commands.CatFile:
    // Read object contents
    break;
  // ... other commands
}

Key Algorithms

SHA-1 Hashing:

const hash = crypto.createHash("sha1").update(content).digest("hex");

Variable-Length Encoding (Packfile):

let MSB = (byte >> 7) & 1;
let size = byte & 15;
while (MSB === 1) {
  idx++;
  size = size + ((byteArray[idx] & 127) << moveOffset);
  MSB = (byteArray[idx] >> 7) & 1;
}

Delta Reconstruction:

if (command === 1) {
  // Copy instruction: extract offset and size
  buffer.concat(baseObject.slice(offset, offset + size));
} else {
  // Insert instruction: read new data
  buffer.concat(deltaData.slice(idx, idx + size));
}

🚧 Limitations

  • No garbage collection
  • No ref packing
  • Limited tag support
  • No merge conflict resolution
  • No branch operations
  • No rebase functionality
  • Single-threaded clone operation

🔮 Future Enhancements

  • Add branch management commands
  • Implement git log functionality
  • Add merge capabilities
  • Support for .gitignore
  • Implement gc (garbage collection)
  • Add diff functionality
  • Support for git config
  • Implement rebase
  • Add stash functionality
  • Support for submodules

🤝 Contributing

This is a learning project, but contributions are welcome! Feel free to:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📝 Notes

  • Author information is hardcoded in commit creation
  • Timezone is set to +0900 (JST)
  • The implementation prioritizes correctness over performance
  • All paths are relative to the repository root

🐛 Known Issues

  • Large repositories may take time to clone
  • Binary file handling needs optimization
  • Some edge cases in delta parsing may not be covered
  • Limited error messages for debugging

📄 License

This project is created for educational purposes as part of the CodeCrafters challenge.

🙏 Acknowledgments

  • CodeCrafters - For the excellent "Build Your Own Git" challenge
  • Git Project - For comprehensive documentation on Git internals
  • Bun Team - For the fast TypeScript runtime

Built with TypeScript + Bun

Understanding Git by rebuilding it from scratch

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors