PB158
A content-addressed object graph, and a way to move pointers into it. Branching strategy, review and delivery practice are your team's policy.
Where this starts
Each one is an exact statement about a small data structure. None of them is an opinion.
! [rejected] main -> main (non-fast-forward)
fatal: Need to specify how to reconcile divergent branches.
You are in 'detached HEAD' state.
Eight parts. The model first, team practice second, a decision at each end.
Scope
Covered
Not covered
git worktree
Part I
Part I · The object model
Content addressing: store bytes, get back a name derived from those bytes.
.git
A fresh repository is one line of text, a directory of small files, and an empty object store.
HEAD
index
objects
refs
ref: refs/heads/main
Two low-level commands write one object and read it back.
hash-object -w
Between the files on disk and a commit sits one file that maps every tracked path to a hash.
.git/index
git add
Write an entry into the index, then turn the index into a tree object.
write-tree
100644
100755
120000
One more command wraps the tree. The result is a snapshot with provenance.
Objects are immutable. The only mutable thing in a repository is a pointer.
.git/refs/heads/
Part I · Demonstration
Write your answer down before anything else runs. Answer with equalities, not with hex.
.git/objects
git commit --allow-empty
add
commit
branch
commit-tree
update-ref
git commit
Part I · Storage
Every commit holds the whole project, and the cost tracks only what changed.
Both halves are true. A delta is a recipe for rebuilding one object from another plus the difference.
The model
The storage layer
Content addressing hashes bytes. Line endings are bytes.
eol
Part I · Integrity
Tamper-evidence is structural. Adversary resistance is a property of the hash function.
Part I · The invariant
Two operations. Every command in the tool is one of them, or both.
Adds objects
fetch
merge
Moves refs
reset
checkout
push
Part II
Part II · Refs
Nothing is inside a branch. A branch names one commit, and that commit names its parents.
cd
Part II · The graph
Two words carry every rule in this part. Both are defined by walking parent links.
When one side is an ancestor of the other there is nothing to reconcile.
It is not a mode, a state machine or an error. It is the contents of .git/HEAD.
.git/HEAD
Part II · Merging
A base, and two sides. Two versions are not enough to decide what happened.
The criterion is textual. A merge that succeeds is not a merge that is correct.
Two people resolve the same conflict in opposite directions. Now two commits qualify as the base.
--all
The function is fixed. What changes is which inputs it gets and where its result is written.
git merge claire
git rebase main
git merge --squash claire
--squash
Part II · Demonstration
claire
Three integrations of the same two branches. Write your answers down before anything runs.
main
The content arrived. The ancestry did not.
Part II · Rewriting
A commit hashes its parents as well as its tree. Change the parent and you have a different object.
A rewrite abandons objects. Garbage collection is the later pass that removes them.
Part II · Remotes
Not a connection and not a session. Two lines of configuration that clone writes for you.
clone
+refs/heads/:refs/remotes/origin/
origin/main
A third namespace of refs, stored on your disk, describing somebody else's repository.
Nothing in git status reads the other repository.
git status
git ls-remote
One command. One visible effect, and it is smaller than the name suggests.
pull
Not a silent merge. With nothing configured, current Git stops and asks you to choose.
pull = fetch + merge
pull.rebase
pull.ff
The destination must be an ancestor of the commit you are sending.
One bare repository, two clones, one shared branch. Write down what each command changes.
git fetch
git pull
git push
The remedy is to integrate and send a descendant, not to reach for a flag.
--force-with-lease
Part III
Part III · Before
One repository, on one server, and committing is the same act as publishing.
Part III · The relocation
Every clone is a complete repository. None of them is authoritative by construction.
Part III · The residue
A lock is a claim over a resource, and a claim is only meaningful if one party decides it.
The unit of transfer is a reachable object graph, so there is no point at which a per-path rule applies.
Part III · The limit
"Git has no access control" is too strong. Git ships hooks, and a hook can refuse a push.
Part III · Decision
Part IV
Part IV · The comparison
Content addressing already existed, and a rival project began two weeks after Git.
Part IV · The index
A cache of filesystem information, and a staging buffer the user operates.
Part IV · A system that chose differently
Jujutsu stores its data in a Git repository and discards Git's user model.
Part IV · A different model
cherry-pick
Git derives changes by comparing snapshots. A change has no identity of its own.
Store patches with durable identities, and derive the tree by applying a set of them.
Part IV · Unpaired
The rename is reconstructed at comparison time, from content similarity alone.
Put both in one commit and the trail of the file ends there.
--follow
Part IV · Scale
A commit is a whole-tree snapshot whether the tree holds fifty files or five million.
Part IV · Decision
Part V
Part V · The variable
Git enforces none of this. A branch can sit unmerged for two years and no command refuses.
Part V · The models
develop
Part V · Mechanics
Part V · The model
The definition is stated in merges per day, not in the shape of the graph.
Part V · Preconditions
Part V · Evidence
The largest mining study of merge conflicts, with the effect size that qualifies it.
A conflict is not merely annoying. The code that comes out of one is measurably worse.
Two lines of evidence with different weaknesses. One objection does not remove both.
Part V · The real dispute
The argument that survives is about release branches, and whether your product needs them.
Part V · The substitution
Unfinished work has to be isolated somewhere. A branch isolates it in history, a flag isolates it at run time.
Part V · Decision
Part VI
Part VI · Origins
A pull request was originally a request that somebody else perform a pull.
git request-pull
Part VI · Evidence
One study classified 570 comments from 200 review threads at a large software company.
Counting what reviewers write is not the same as measuring what review prevents.
Part VI · Mechanism
A reviewer does not fail to find a defect through carelessness. Finding one requires understanding the change.
Part VI · Limits
Part VI · Queues
Review latency does not merely delay a change. It grows the change it then fails to review.
Part VI · The Git limitation
A commit records its parents. Nothing records its children.
Part VI · Stacking
git rebase -i
--update-refs
The Part II squash result, applied to a chain.
Part VI · What changes next
The measured output of review assumes a person wrote the change and a person absorbs the comment.
Part VI · Decision
Part VII
Part VII · Separation
Part VII · Integration
It is about how often people merge, not about which server runs the build.
Part VII · The link back
The branching choice in Part V and the integration practice here are one decision.
Part VII · Delivery
The team builds the software so that it can go to production at any time. Production is the running system users depend on, and nobody has to release to it.
Part VII · Deployment
Every change that passes the pipeline goes to production automatically.
Part VII · The precondition question
Two sources disagree about whether flags are required. The disagreement dissolves along the delivery and deployment line.
Part VII · The measurement
Batch size is how much change ships at once. It cannot be counted directly, so the number of releases stands in for it.
Part VII · Decision
Closing
The thesis, stated again now that every part of it has been shown.
git bisect
Take it with you
ondrasek.github.io/talks
me@ondrejkrajicek.com