The Git Version Control system must support:
- Initializing a repository (
init) - Adding files to a staging area (
add) - Committing staged files with metadata (
commit) - Viewing the commit history (
log)
Below is a clean, multi-language codebase blueprint showcasing our design patterns and thread-safety strategies in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.*;
// 1. Core Git Objects (Composite Pattern)
abstract class GitObject {
protected String hash;
public String getHash() { return hash; }
public abstract String type();
public abstract String serialize();
protected void computeHash() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] hashBytes = digest.digest(serialize().getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : hashBytes) {
sb.append(String.format("%02x", b));
}
this.hash = sb.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
class Blob extends GitObject {
private final String content;
public Blob(String content) {
this.content = content;
computeHash();
}
@Override public String type() { return "blob"; }
@Override public String serialize() { return "blob " + content.length() + "\0" + content; }
public String getContent() { return content; }
}
class TreeEntry {
public final String mode;
public final String name;
public final String hash;
public TreeEntry(String mode, String name, String hash) {
this.mode = mode; this.name = name; this.hash = hash;
}
}
class Tree extends GitObject {
private final List<TreeEntry> entries = new ArrayList<>();
public Tree(List<TreeEntry> entries) {
this.entries.addAll(entries);
this.entries.sort(Comparator.comparing(e -> e.name)); // Canonical sort
computeHash();
}
@Override public String type() { return "tree"; }
@Override public String serialize() {
StringBuilder sb = new StringBuilder();
for (TreeEntry e : entries) sb.append(e.mode).append(" ").append(e.name).append("\0").append(e.hash);
return "tree " + sb.length() + "\0" + sb.toString();
}
}
class Commit extends GitObject {
private final String treeHash;
private final String parentHash;
private final String author;
private final String message;
private final long timestamp;
public Commit(String treeHash, String parentHash, String author, String message) {
this.treeHash = treeHash;
this.parentHash = parentHash;
this.author = author;
this.message = message;
this.timestamp = System.currentTimeMillis();
computeHash();
}
@Override public String type() { return "commit"; }
@Override public String serialize() {
String content = "tree " + treeHash + "\n" +
(parentHash != null ? "parent " + parentHash + "\n" : "") +
"author " + author + " " + timestamp + "\n\n" +
message + "\n";
return "commit " + content.length() + "\0" + content;
}
public String getParentHash() { return parentHash; }
}
// 2. Object Database
class ObjectDatabase {
private final Map<String, GitObject> store = new ConcurrentHashMap<>();
public void store(GitObject obj) { store.put(obj.getHash(), obj); }
public GitObject get(String hash) { return store.get(hash); }
}
// 3. The Repository Facade
class Repository {
private final ObjectDatabase odb = new ObjectDatabase();
private final Map<String, String> index = new ConcurrentHashMap<>(); // path -> blob hash
private final Map<String, String> branches = new ConcurrentHashMap<>(); // branch -> commit hash
private volatile String head = "main"; // current branch
public Repository() {
branches.put("main", null);
}
public synchronized void add(String path, String content) {
Blob blob = new Blob(content);
odb.store(blob);
index.put(path, blob.getHash());
}
public synchronized String commit(String author, String message) {
List<TreeEntry> entries = new ArrayList<>();
for (Map.Entry<String, String> entry : index.entrySet()) {
entries.add(new TreeEntry("100644", entry.getKey(), entry.getValue()));
}
Tree tree = new Tree(entries);
odb.store(tree);
String parentCommitHash = branches.get(head);
Commit commit = new Commit(tree.getHash(), parentCommitHash, author, message);
odb.store(commit);
branches.put(head, commit.getHash());
return commit.getHash();
}
public void log() {
String curr = branches.get(head);
while (curr != null) {
Commit c = (Commit) odb.get(curr);
System.out.println("commit " + c.getHash());
System.out.println("Author: " + c.serialize().split("\n")[2]);
System.out.println("\n " + c.serialize().split("\n\n")[1]);
curr = c.getParentHash();
}
}
}
// 4. Main Driver Class
public class GitRunner {
public static void main(String[] args) {
Repository repo = new Repository();
System.out.println("--- Adding and Committing First File ---");
repo.add("hello.txt", "Hello World!");
repo.commit("Alice <alice@example.com>", "Initial commit: added hello.txt");
System.out.println("\n--- Adding and Committing Second File ---");
repo.add("main.java", "public class Main {}");
repo.commit("Bob <bob@example.com>", "Added main.java class");
System.out.println("\n--- Git Log ---");
repo.log();
}
}