Git ships ~150 commands split into two layers:
Porcelain — the high-level commands you use daily: git commit, git push, git merge, git status. Designed for humans, output is human-readable, behaviour optimized for common workflows.
Plumbing — low-level primitives the porcelain is built on top of: git hash-object, git update-ref, git write-tree, git cat-file, git rev-list, git ls-tree. Designed for scripts, output is stable + machine-readable.
When to reach for plumbing:
- Scripts that need stable output across Git versions.
- Custom workflows (e.g., creating commits without changing the working directory).
- Performance-critical operations on huge repos.
Example: create a commit manually with plumbing:
blob=$(echo "hi" | git hash-object -w --stdin)
tree=$(git mktree <<< "100644 blob $blob hello.txt")
commit=$(echo "test" | git commit-tree $tree)
git update-ref refs/heads/main $commit
Pure-Git filesystem manipulation. Most developers never need this — but knowing it exists makes Git stop feeling magical.