Written for the next cohort as much as this one. Every example here is a real, currently-public repo from this trimester's five teams — not a hypothetical.
Every pull request a team ever opens ends up in exactly one of three states. Understanding why each one happens — and what it costs a team when it happens too often — is one of the more useful things you can take from a group software project, independent of whatever you're actually building.
The work was reviewed (or at least accepted) and folded into main. This is the
goal state. A PR that merges quickly after being opened is usually a sign the work was scoped
well — small enough to review, clear enough to approve without back-and-forth.
The branch exists, the PR was opened, and it's sitting there unresolved. This isn't automatically a problem — a PR that opened yesterday and is still open today is completely normal, review takes time. It becomes a real signal when a PR sits open for weeks with no activity: usually it means one of three things happened — the reviewer never got to it, the author moved on to other work and forgot it existed, or the work genuinely isn't finished and shouldn't have been opened as a PR yet.
The PR was closed, but its changes never made it into main. This is the state
worth paying the most attention to, because it has several very different causes that all look
identical from the outside:
All five teams in this course had access to the same tools, the same deadlines, and the same grading rubric. What they did with pull requests varied enormously — and the differences are instructive.
Some teams pushed every change directly to main, start to finish, and never opened
a single pull request. This isn't automatically wrong for a small team moving fast — but it
means no code review ever happened, and if two people edit the same file at the same time, one of
them silently overwrites the other with no warning. (This is close to the root cause behind a
separate incident this term where a team's automated pipeline output got overwritten by a manual
run — direct-to-main pushes with no branch isolation is exactly the condition that makes
that kind of accident possible.)
One team generated 72 pull requests over the trimester — by far the most of any team — but nearly a quarter of them (17) closed without ever merging. Looking at the real history, a big chunk of that came from one specific week where three near-identical PRs were opened for the same piece of work (a synthesis operator), all but one closed unused, alongside a string of small "renaming" PRs that were opened, abandoned, then redone. High PR volume looks productive on a graph. It isn't the same thing as clean history — a team should ask itself whether repeated near-duplicate PRs mean two people didn't know the other was already working on the same thing.
Another team ran 15 total pull requests across the same period, with 13 merged and only 2 that didn't land. Far fewer PRs overall, but almost all of them counted. This is closer to what "healthy" looks like: PRs opened, reviewed, merged, done — no pile-up, no duplicate confusion.
main with no PRs at all, that's a deliberate tradeoff to make consciously, not a default to fall into by not knowing PRs were an option.