Owner:@DanisLol
Module: 3 - Commits & branching
File you own:minigit/commits.py
Week: 2 of 10 - Real Bytes on Disk
Fix first - from the Week 1 review
minigit commit -m x crashes: AttributeError: 'CommitManager' object has no attribute 'store'.
__init__ only sets self.store when store is passed. Uncomment the fallbacks:
self.store=storeorObjectStore(repo_path)
self.tree=treeorWorkingTree(repo_path)
Also raise RefNotFoundError -> raise RefNotFoundError(name) so the CLI prints something.
What changes this week
- Week 1 refs lived in
self._refs and vanished when the process exited - Week 2 a ref is a real file:
.minigit/refs/heads/<branch>, content = one commit hash + \n - HEAD is a real file:
ref: refs/heads/main\n
Steps
- Branch
week2/m3-real-refs (branch off main after M1 merges) - Delete
self._refs and self._head. Helpers instead:
_ref_path(name) -> self.root / ".minigit" / "refs" / "heads" / nameread_head() -> str | None - ref: refs/heads/x -> "x"; raw hash -> detached, return the hashwrite_head(name) -> write ref: refs/heads/<name>\nread_ref(name) -> str | None - file missing = branch has no commits yetwrite_ref(name, commit_hash) -> mkdir(parents=True, exist_ok=True), write hash + \n
create_commit(tree_hash, parents, author, message):
_format_commit stays byte-for-byte identical to Week 1- write the commit object, then advance the current branch ref to the new hash
- a commit that doesn't move a ref is unreachable garbage - moving the ref is the point
create_branch(name, commit_hash) -> write_ref; name already exists -> MiniGitErrorlist_branches -> sorted(p.name for p in refs_dir.iterdir()), * marks read_head()switch_branch(name) -> unknown ref = RefNotFoundError(name), else write_head(name)# Week 4 - also resolve ref -> commit -> tree and call self.tree.checkout(tree_hash)
minigit commit -m "<msg>" for real:
tree_hash = self.tree.build_tree_from_index() (still a stub hash this week - fine)- parents =
[read_ref(current_branch)], or [] when the branch file doesn't exist yet (root commit) - author from
.minigit/config if present, else "minigit <minigit@local>" - print the short hash:
[main a1b2c3d] <msg>
- New command
minigit log:
- walk from
read_ref(current) back through parents, print <hash> <message first line> per commit - no commits yet -> print
no commits yet, return 0 - parse the commit body back out of
store.read_object(hash) - the format is yours, so is the parser
merge stays return None# Week 4 fast-forward / Week 5 three-way- Tests
tests/test_commits.py - real ObjectStore(tmp_path), drop FakeObjectStore:
- commit on an empty repo -> zero parent lines, ref file created
- second commit -> one parent line, points at the first
- the ref file actually moved
create_branch twice -> raisesswitch_branch("nope") -> RefNotFoundError- branch, commit, switch back -> the two branches point at different hashes
log output has one line per commit, newest first
- quality-check green -> commit, push, PR
Notes
- run
minigit init (@mahis1067's, landing this week) before touching refs in a test - branching copies a 40-char string and zero object data - that is why it's instant
Done when
Owner:@DanisLol
Module: 3 - Commits & branching
File you own:
minigit/commits.pyWeek: 2 of 10 - Real Bytes on Disk
Fix first - from the Week 1 review
minigit commit -m xcrashes:AttributeError: 'CommitManager' object has no attribute 'store'.__init__only setsself.storewhenstoreis passed. Uncomment the fallbacks:Also
raise RefNotFoundError->raise RefNotFoundError(name)so the CLI prints something.What changes this week
self._refsand vanished when the process exited.minigit/refs/heads/<branch>, content = one commit hash +\nref: refs/heads/main\nSteps
week2/m3-real-refs(branch offmainafter M1 merges)self._refsandself._head. Helpers instead:_ref_path(name) -> self.root / ".minigit" / "refs" / "heads" / nameread_head() -> str | None-ref: refs/heads/x->"x"; raw hash -> detached, return the hashwrite_head(name)-> writeref: refs/heads/<name>\nread_ref(name) -> str | None- file missing = branch has no commits yetwrite_ref(name, commit_hash)->mkdir(parents=True, exist_ok=True), write hash +\ncreate_commit(tree_hash, parents, author, message):_format_commitstays byte-for-byte identical to Week 1create_branch(name, commit_hash)->write_ref; name already exists ->MiniGitErrorlist_branches->sorted(p.name for p in refs_dir.iterdir()),*marksread_head()switch_branch(name)-> unknown ref =RefNotFoundError(name), elsewrite_head(name)# Week 4 - also resolve ref -> commit -> tree and call self.tree.checkout(tree_hash)minigit commit -m "<msg>"for real:tree_hash = self.tree.build_tree_from_index()(still a stub hash this week - fine)[read_ref(current_branch)], or[]when the branch file doesn't exist yet (root commit).minigit/configif present, else"minigit <minigit@local>"[main a1b2c3d] <msg>minigit log:read_ref(current)back through parents, print<hash> <message first line>per commitno commits yet, return 0store.read_object(hash)- the format is yours, so is the parsermergestaysreturn None# Week 4 fast-forward / Week 5 three-waytests/test_commits.py- realObjectStore(tmp_path), dropFakeObjectStore:create_branchtwice -> raisesswitch_branch("nope")->RefNotFoundErrorlogoutput has one line per commit, newest firstNotes
minigit init(@mahis1067's, landing this week) before touching refs in a testDone when
storecrash fixedcreate_commitmoves the current branch refminigit commit/branch/checkout/logall work across separate CLI calls