Git commands are divided into two categories:
- Porcelain: User-friendly commands you use every day (
add,commit,push,pull). - Plumbing: Low-level commands designed for scripts and automation (
hash-object,update-index,write-tree).
Think of it like a car: Porcelain is the steering wheel and pedals. Plumbing is the engine valves and fuel injection. You usually drive with the wheel, but to fix the engine, you need to understand the valves.
Building a Commit Manually
We are going to create a commit without using git add or git commit. We will use plumbing commands to manipulate the object database directly.
The Steps
hash-object: Create a Blob from file content.update-index: Add the file to the Index (Staging Area).write-tree: Create a Tree object from the Index.commit-tree: Create a Commit object pointing to the Tree.update-ref: Move the branch pointer (HEAD) to the new Commit.
Working Dir
Index
Repository (Objects)
Command Breakdown
1. git hash-object -w
Takes content, computes the SHA-1, creates the blob header, and stores the compressed object in .git/objects.
-w: Write the object to the database (don’t just calculate hash).--stdin: Read content from standard input.
2. git update-index
Modifies the binary index file directly.
--add: Add file if not present.--cacheinfo <mode> <hash> <filename>: Manually register a file in the index using its hash, without needing it to be in the working directory.
3. git write-tree
Scans the current index and creates a tree object representing that directory state. Returns the SHA-1 of the new tree.
4. git commit-tree <tree-hash>
Creates a commit object.
- Takes the tree hash as an argument.
- Takes the commit message from stdin.
- Returns the new commit SHA-1.
- (Note: To add a parent, you would use
-p <parent-hash>).
5. git update-ref
Updates a reference (like a branch pointer) to a new hash. This is safer than echo <hash> > .git/refs/heads/master because it follows symlinks and handles locking.
Summary
You just performed the exact steps git commit does for you!
- Hashes files (Blobs).
- Updates the Staging Area (Index).
- Creates a snapshot of the directory (Tree).
- Creates a history node (Commit).
- Moves the branch pointer (Ref).
Understanding this flow allows you to repair broken repos, script custom workflows, and truly master Git.