#!/usr/bin/env python3 # Copyright (C) 2023 Matheus Tavares # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import hashlib, zlib, os, time def write_obj(objtype, content): ''' Writes the loose object to the git object data base and returns its sha1 object. The content must be a byte stream. ''' data = f"{objtype} {len(content)}\0".encode() + content sha1 = hashlib.sha1(data) hex_sha1 = sha1.hexdigest() path = f".git/objects/{hex_sha1[:2]}/{hex_sha1[2:]}" os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "wb") as f: f.write(zlib.compress(data)) return sha1 def write_blob(content): return write_obj("blob", content.encode()) def write_tree(filenames, hashes): mode = 100644 entries = b"" for name, hash in zip(filenames, hashes): entries += f"{mode} {name}\0".encode() + hash return write_obj("tree", entries) def write_commit(tree_sha1, parents, author, committer, msg): content = f"tree {tree_sha1}\n" for parent in parents: content += f"parent {parent}\n" content += f"author {author} {int(time.time())} {time.strftime('%z')}\n" content += f"committer {committer} {int(time.time())} {time.strftime('%z')}\n" content += "\n" content += msg return write_obj("commit", content.encode()) def write_branch(name, hash): with open(f".git/refs/heads/{name}", "w") as f: f.write(hash) # First commit author = "John Doe " blob1_sha1 = write_blob("This is a simple README file\n") tree1_sha1 = write_tree(["README"], [blob1_sha1.digest()]) commit1_sha1 = write_commit(tree1_sha1.hexdigest(), [], author, author, "Add the README file") # Second commit blob2_sha1 = write_blob("This is a simple README file\nWith one extra line\n") tree2_sha1 = write_tree(["README"], [blob2_sha1.digest()]) commit2_sha1 = write_commit(tree2_sha1.hexdigest(), [commit1_sha1.hexdigest()], author, author, "Add another line to README") # Create branch write_branch("my_branch", commit2_sha1.hexdigest()) print("Created 'my_branch'")