|
1 | | -[](https://app.codecrafters.io/users/codecrafters-bot?r=2qF) |
| 1 | +# mygit - A C++ Implementation of Core Git Commands |
2 | 2 |
|
3 | | -This is a starting point for C++ solutions to the |
4 | | -["Build Your Own Git" Challenge](https://codecrafters.io/challenges/git). |
| 3 | +**mygit** is a from-scratch implementation of several core Git commands in modern C++23. It was created as a portfolio project to gain a fundamental understanding of Git's internal object model, packfile protocol, and data structures. This project is inspired by the "Build Your Own X" initiative. |
5 | 4 |
|
6 | | -In this challenge, you'll build a small Git implementation that's capable of |
7 | | -initializing a repository, creating commits and cloning a public repository. |
8 | | -Along the way we'll learn about the `.git` directory, Git objects (blobs, |
9 | | -commits, trees etc.), Git's transfer protocols and more. |
| 5 | +## Core Workflow Demo |
10 | 6 |
|
11 | | -**Note**: If you're viewing this repo on GitHub, head over to |
12 | | -[codecrafters.io](https://codecrafters.io) to try the challenge. |
| 7 | +This demo shows how to build `mygit` and then use its plumbing commands to create a Git commit from scratch, demonstrating the core object model in action. |
13 | 8 |
|
14 | | -# Passing the first stage |
| 9 | +#### Step 1: Build the `mygit` Executable |
15 | 10 |
|
16 | | -The entry point for your Git implementation is in `src/main.cpp`. Study and |
17 | | -uncomment the relevant code, and push your changes to pass the first stage: |
| 11 | +First, clone this repository and run the build script. |
18 | 12 |
|
19 | | -```sh |
20 | | -git commit -am "pass 1st stage" # any msg |
21 | | -git push origin master |
| 13 | +```bash |
| 14 | +# Clone the repository (replace with your actual repo URL) |
| 15 | +$ git clone https://github.com/Mathis-L/recreate-git.git mygit |
| 16 | +$ cd mygit |
| 17 | + |
| 18 | +# Run the build script |
| 19 | +$ chmod +x build.sh |
| 20 | +$ ./build.sh |
| 21 | +--- Starting mygit build process --- |
| 22 | +Step 1: Configuring with CMake... |
| 23 | +-- The CXX compiler identification is GNU 11.4.0 |
| 24 | +... |
| 25 | +Step 2: Building the executable... |
| 26 | +[ 50%] Built target mygit |
| 27 | +... |
| 28 | +[100%] Built target mygit |
| 29 | + |
| 30 | +✅ Build complete! |
| 31 | + The executable is located at: ./build/mygit |
| 32 | + |
| 33 | +$ export PATH=$PWD/build:$PATH |
| 34 | +$ cd .. |
| 35 | +``` |
| 36 | + |
| 37 | +#### Step 2: Create a Commit from Scratch |
| 38 | + |
| 39 | +Now that `mygit` is built, let's use it to create a new project. |
| 40 | + |
| 41 | +```bash |
| 42 | +# Create a new project directory and navigate into it |
| 43 | +$ mkdir my-test-project && cd my-test-project |
| 44 | + |
| 45 | +# Use the 'mygit' we just built to initialize a repository |
| 46 | +$ mygit init |
| 47 | +Initialized empty Git repository in /path/to/my-test-project/.git/ |
| 48 | + |
| 49 | +# Create a file and add it to the object database as a "blob" |
| 50 | +$ echo "hello git" > hello.txt |
| 51 | +$ mygit hash-object -w hello.txt |
| 52 | +d90f1b40cf83b5d4313c4155abdaac3265b53026 |
| 53 | + |
| 54 | +# Create a "tree" object that captures the state of the directory |
| 55 | +$ mygit write-tree |
| 56 | +7c7394336c9966133c945b63cf476902d28f0b9f |
| 57 | + |
| 58 | +# Create a "commit" object, linking the tree with a message |
| 59 | +$ mygit commit-tree 7c7394336c9966133c945b63cf476902d28f0b9f -m "Initial commit" |
| 60 | +1b2e67a423e8b0ed5d46924d567027582b12367d |
| 61 | + |
| 62 | +# Inspect the final commit object we just created |
| 63 | +$ /mygit cat-file -p 1b2e67a423e8b0ed5d46924d567027582b12367d |
| 64 | +tree 7c7394336c9966133c945b63cf476902d28f0b9f |
| 65 | +author Mathis-L <mathislafon@gmail.com> 1721245200 +0000 |
| 66 | +committer Mathis-L <mathislafon@gmail.com> 1721245200 +0000 |
| 67 | + |
| 68 | +Initial commit |
22 | 69 | ``` |
23 | 70 |
|
24 | | -That's all! |
| 71 | +## Features & Implemented Commands |
| 72 | + |
| 73 | +This project implements the plumbing and porcelain commands necessary to support a basic `clone` and `inspect` workflow. |
| 74 | + |
| 75 | +* `init`: Initializes an empty `.git` directory structure. |
| 76 | +* `cat-file`: Inspects a Git object from the database (`-p` pretty-print option is supported). |
| 77 | +* `hash-object`: Computes an object ID and optionally creates a blob from a file (`-w` write option is supported). |
| 78 | +* `ls-tree`: Lists the contents of a tree object (`--name-only` is supported). |
| 79 | +* `write-tree`: Creates a tree object from the current directory state. |
| 80 | +* `commit-tree`: Creates a new commit object from a tree, parent, and message. |
| 81 | +* `clone`: Fetches a complete repository from a remote server over the Smart HTTP protocol. |
| 82 | + |
| 83 | +## Project Foundations: Understanding Git's Internals |
| 84 | + |
| 85 | +To understand how `mygit` works, it is essential to first understand Git's elegant and powerful design. The following document provides a detailed overview of the core concepts that this project implements, from the `.git` directory structure to the fundamental object model. |
| 86 | + |
| 87 | +* **[📄 Deep Dive: Git's Internal Structure and Object Model](./docs/git_internals.md)** |
25 | 88 |
|
26 | | -# Stage 2 & beyond |
| 89 | +## Technical Deep Dive: The Clone Process |
27 | 90 |
|
28 | | -Note: This section is for stages 2 and beyond. |
| 91 | +The most complex command implemented is `clone`, which involves a multi-stage conversation with a remote server using Git's Smart HTTP Protocol. |
29 | 92 |
|
30 | | -1. Ensure you have `cmake` installed locally |
31 | | -1. Run `./your_program.sh` to run your Git implementation, which is implemented |
32 | | - in `src/main.cpp`. |
33 | | -1. Commit your changes and run `git push origin master` to submit your solution |
34 | | - to CodeCrafters. Test output will be streamed to your terminal. |
| 93 | +For a detailed, step-by-step breakdown of how `mygit` handles reference discovery, packfile negotiation, and delta resolution, please see the **[Git Clone Deep Dive Document](./docs/CLONE_DEEP_DIVE.md)**. |
35 | 94 |
|
36 | | -# Testing locally |
37 | 95 |
|
38 | | -The `your_program.sh` script is expected to operate on the `.git` folder inside |
39 | | -the current working directory. If you're running this inside the root of this |
40 | | -repository, you might end up accidentally damaging your repository's `.git` |
41 | | -folder. |
| 96 | +## Current Limitations |
42 | 97 |
|
43 | | -We suggest executing `your_program.sh` in a different folder when testing |
44 | | -locally. For example: |
| 98 | +As a learning project, this implementation focuses on the "happy path" and has several limitations compared to the real Git: |
| 99 | +* `clone` only supports the HTTP/HTTPS protocols. SSH is not supported. |
| 100 | +* `clone` performs a full, shallow clone and does not support complex history negotiation (i.e., it has no `have` lines). |
| 101 | +* Plumbing commands like `commit-tree` use hardcoded author information. |
| 102 | +* There is no concept of an index/staging area (`git add`). `write-tree` works directly from the file system. |
45 | 103 |
|
46 | | -```sh |
47 | | -mkdir -p /tmp/testing && cd /tmp/testing |
48 | | -/path/to/your/repo/your_program.sh init |
| 104 | + |
| 105 | +## Getting Started |
| 106 | + |
| 107 | +### Prerequisites |
| 108 | + |
| 109 | +You will need a C++23 compatible compiler and the following dependencies: |
| 110 | +* `build-essential` (for `g++`, `make`, etc.) |
| 111 | +* `cmake` (version 3.13+) |
| 112 | +* `libssl-dev` (for SHA-1 hashing) |
| 113 | +* `zlib1g-dev` (for object compression) |
| 114 | +* `cpr` (for HTTP requests, installed by the build workflow) |
| 115 | + |
| 116 | +On Debian/Ubuntu, you can install them with: |
| 117 | +```bash |
| 118 | +sudo apt-get update |
| 119 | +sudo apt-get install -y build-essential cmake libssl-dev zlib1g-dev |
| 120 | +``` |
| 121 | + |
| 122 | +And for cpr you will have to do : |
| 123 | +```bash |
| 124 | +# 1. Clone the cpr repository |
| 125 | +git clone https://github.com/libcpr/cpr.git |
| 126 | +cd cpr |
| 127 | + |
| 128 | +# 2. Configure, build, and install the library system-wide |
| 129 | +mkdir build && cd build |
| 130 | +cmake .. -DCPR_USE_SYSTEM_CURL=ON |
| 131 | +cmake --build . |
| 132 | +sudo cmake --install . |
| 133 | + |
| 134 | +# 3. Go back to your original directory |
| 135 | +cd ../.. |
| 136 | +``` |
| 137 | + |
| 138 | +### Building the Project |
| 139 | + |
| 140 | +A convenience script is provided to build the project. |
| 141 | + |
| 142 | +```bash |
| 143 | +# Make the build script executable |
| 144 | +chmod +x build.sh |
| 145 | + |
| 146 | +# Run the script to configure and build |
| 147 | +./build.sh |
49 | 148 | ``` |
50 | 149 |
|
51 | | -To make this easier to type out, you could add a |
52 | | -[shell alias](https://shapeshed.com/unix-alias/): |
| 150 | +The final executable will be located at `./build/mygit`. |
| 151 | + |
| 152 | +### Running Tests |
53 | 153 |
|
54 | | -```sh |
55 | | -alias mygit=/path/to/your/repo/your_program.sh |
| 154 | +The project includes a suite of integration tests written as shell scripts. To run them: |
| 155 | +```bash |
| 156 | +# Navigate to the tests directory |
| 157 | +cd tests |
56 | 158 |
|
57 | | -mkdir -p /tmp/testing && cd /tmp/testing |
58 | | -mygit init |
| 159 | +# Make the test scripts executable |
| 160 | +chmod +x *.sh |
| 161 | + |
| 162 | +# Run the main test runner |
| 163 | +./run_all_tests.sh |
59 | 164 | ``` |
| 165 | +A successful run will end with the message: `✅ All tests passed.` |
| 166 | + |
| 167 | +## Future Work |
| 168 | + |
| 169 | +This project provides a solid foundation. Future work could include implementing more of Git's core features: |
| 170 | +* **Index Management:** `add`, `rm` |
| 171 | +* **Status & Diffs:** `status`, `diff` |
| 172 | +* **Branching & Merging:** `branch`, `checkout`, `merge` |
| 173 | +* **Protocol Enhancements:** Support for the v2 protocol, SSH. |
| 174 | + |
0 commit comments