Module 9 — Collaboration Workflows (pull requests, forks, Git Flow)
Updated 8 September 2026
🧠 concept → 🧩 analogy → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (hidden)
Part A — The feature-branch workflow
A1. The shape almost every team shares
Underneath every named methodology sits one shared skeleton: main is sacred, work happens on branches. main must always be releasable — nobody commits to it directly; it moves only by merging reviewed branches. Each unit of work (feature, fix, experiment) gets its own short-lived branch, named descriptively (feature/PAY-231-refund-retry — Module 5's convention capstone), pushed early so it is visible and backed up, merged when reviewed, deleted when merged. The cycle you are about to run is, with a web UI on top, the daily loop of most software teams on earth.
🧪 Exercise 9.1 — a feature's whole life, part one: branch, work, publish
cd ~/git-course/kitchen # on main
git switch -c feature/holiday-menu
echo "stollen: december only" > stollen.txt
git add stollen.txt && git commit -m "Add stollen to holiday menu"
git push -u origin feature/holiday-menu✅ Expected result — click to reveal
Switched to a new branch 'feature/holiday-menu'
[feature/holiday-menu 5eca2dd] Add stollen to holiday menu
1 file changed, 1 insertion(+)
create mode 100644 stollen.txt
To /home/aisha/git-course/bakery.git
* [new branch] feature/holiday-menu -> feature/holiday-menu
branch 'feature/holiday-menu' set up to track 'origin/feature/holiday-menu'.What to read out of it: nothing new mechanically — Module 5's switch -c, Module 2's commit, Module 8's push -u — and that is the point: a "workflow" is sequencing, not new commands. The push matters even before the work is done: a published branch is visible to the team (no surprise duplicated effort), backed up off your laptop (Module 1's trap defused), and ready to become a pull request at any moment. main has not moved and cannot be broken by anything happening here.
A2. Keeping the branch current while main moves
While your branch lives, main receives other people's merges. The longer you drift from it, the bigger the eventual conflict (Module 6's fleet lesson). The standard hygiene: periodically merge main into your feature branch — the same git merge, pointed the other way. Conflicts, if any, get resolved on your branch, at your pace, leaving main pristine — and the final merge back becomes trivial because you already did the hard part. (Rebasing the branch instead is the tidier alternative many teams prefer — Module 10 adds it; the merge version below is always correct.)
🧪 Exercise 9.2 — main moves; you catch up
cd ~/git-course/kitchen # simulate the team: land something on main
git switch main
echo "gingerbread: december only" > gingerbread.txt
git add gingerbread.txt && git commit -q -m "Add gingerbread note" && git push -q
git switch feature/holiday-menu # back on your feature
git merge main --no-edit # bring main's progress IN
git log --oneline -3✅ Expected result — click to reveal
959ac14 Merge branch 'main' into feature/holiday-menu
d41c33a Add gingerbread note
5eca2dd Add stollen to holiday menuWhat to read out of it (your earlier commands also print their usual Switched to branch… and Merge made by the 'ort' strategy. lines, elided here — the log listing is the point; gingerbread sits between the two because log orders by date across both parents): the merge commit's auto-message says the direction plainly — Merge branch 'main' **into** feature/holiday-menu; compare with Module 6's messages, which had no "into" clause because the target was the default. Your branch now contains everything main has, so a merge back can no longer conflict on today's content. On a real team you would do this whenever main moves meaningfully, and always just before opening review — reviewers should see your change against current reality, not last Tuesday's.
🎯 Interview questions — Part A
🎯 "What is the Git Workflow?" — asked verbatim in GeeksforGeeks' 70+ Git Interview Questions, updated Jul 2026
Two legitimate readings, worth handling both. The individual workflow is the edit→stage→commit→push loop from Modules 2 and 8: change files, git add, git commit, git push, with pull/fetch bringing others' work in. The team workflow wraps that loop in process: clone or update, branch from main per unit of work, commit and push the branch, open a pull request, pass review and CI, merge to main, delete the branch. Named models (Git Flow, GitHub Flow, trunk-based) are variations in how many long-lived branches exist and how releases are cut.
The details that separate candidates: an average answer recites edit-add-commit-push. A strong answer notices the question's ambiguity, gives the loop and the team cycle, and states the invariant all team workflows protect: main stays releasable, so integration happens through reviewed branch merges rather than direct commits. Tying each step to its enforcement mechanism — protected branches for "nobody commits to main", required checks for "CI passes before merge" — shows you have worked inside the process, not just read about it.
Part B — Pull requests and review
B1. What a pull request actually is
A pull request (GitLab: merge request) is not a Git object — no PR exists anywhere in .git (Module 1's layer-separation, now concrete). It is a host construct: a proposal saying "merge branch X into branch Y," wrapped in machinery Git itself does not provide — a discussion thread, line-by-line review comments, approval state, CI results, and a merge button with policy attached. The diff a PR shows is one you already own: git diff main...feature — the three-dot, merge-base-to-tip form (Module 6 D2), what this branch contributes, not what main did meanwhile.
The merge button typically offers three strategies, and choosing is a team decision you can now reason about: merge commit (--no-ff, Module 6 — preserves the branch bubble and gives one revertable node), squash (all branch commits collapsed into a single new commit on main — clean history, feature-branch commits discarded), and rebase (branch commits replayed individually onto main, no merge commit — Module 10 teaches the mechanics and the caveats). Protection rules complete the picture: a protected branch refuses direct pushes, force-pushes, and merges that lack required approvals or passing checks — the enforcement layer for everything Part A called "sacred."
A journalist never types straight into tomorrow's front page. They file a draft (the branch), and an editor's desk (the PR) is where it is read, marked up, argued over, fact-checked (CI), and finally approved for print (merge). The paper's masthead rule — nothing prints unedited — is not a suggestion; the print room physically rejects unapproved copy (protected branch).
Where the analogy stops working. An editor rewrites your copy and prints; the byline blurs who wrote what. A PR merge preserves exact authorship and history — every commit keeps its author (Module 3), the reviewer approves but does not silently alter, and requested changes go back to the author to make. Also: newspapers print once; a merged PR's branch can be reverted as a unit (Module 7's -m 1) — the press has an undo, provided the team chose merge commits over fast-forwards.
🧪 Exercise 9.3 — play both roles: reviewer, then merger
cd ~/git-course/kitchen # REVIEWER hat: what does this PR propose?
git switch main
git log --oneline main..feature/holiday-menu # the commits it brings
git diff --stat main...feature/holiday-menu # the PR diff (three-dot!)
git merge --no-ff feature/holiday-menu --no-edit # the "merge button"
git push -q
git push origin --delete feature/holiday-menu # the "delete branch" button
git branch -d feature/holiday-menu
git branch --merged main # cleanup audit: safe to delete✅ Expected result — click to reveal
959ac14 Merge branch 'main' into feature/holiday-menu
5eca2dd Add stollen to holiday menu
stollen.txt | 1 +
1 file changed, 1 insertion(+)
Merge made by the 'ort' strategy.
stollen.txt | 1 +
1 file changed, 1 insertion(+)
To /home/aisha/git-course/bakery.git
- [deleted] feature/holiday-menu
Deleted branch feature/holiday-menu (was 959ac14).
* main
sourdoughWhat to read out of it: the review commands show exactly what a host renders — the commit list (including your catch-up merge from 9.2; squash-merging would collapse such noise, which is much of its appeal) and the three-dot diff: one file — and note that because you caught the branch up in 9.2, even the two-dot form would agree right now; on a stale branch that skipped 9.2, the two-dot form would have dragged gingerbread into view (Module 6's Ticket 3 bug), which is why the three-dot habit is the one to build. The --no-ff merge is the button-press; the two deletions are the post-merge tidy. git branch --merged main is the audit that makes cleanup safe: every branch it lists is fully contained in main — deleting those pointers strands nothing (--no-merged lists the dangerous ones).
🎯 Interview questions — Part B
🎯 "What are the benefits of using a pull request in a project?" — asked verbatim in Interview Coder, Sep 2025 and GeeksforGeeks, updated Jul 2026
A PR centralizes everything that should happen between "code written" and "code shared": human review (line comments, requested changes, approvals), automated verification (CI, linters, scanners as required checks that gate the merge), discussion that becomes a permanent, searchable record of why a change happened, and policy enforcement via protected branches — no direct pushes, no merging without approvals. Net effect: main stays releasable, knowledge spreads (reviewers learn the codebase), and every change has an audit trail linking code, conversation, and checks.
The details that separate candidates: an average answer says "code review before merging." A strong answer covers all four layers (review, automation, record, enforcement) and adds the operational nuances: the PR diff is three-dot (contribution-only) so reviewers see the right thing; merge-strategy choice (merge/squash/rebase) decides what history main accumulates; and small PRs are a reviewability feature — review quality collapses with diff size, so PR sizing is workflow design, not preference. Mentioning that a PR is a host construct, not a Git object, shows precise layering.
🎯 "Why is it considered to be called git 'pull request' as 'push request'?" — asked verbatim in Interview Coder's 90+ Git questions, Sep 2025
Because of who acts. You are not pushing your changes into the target branch — you lack (and should lack) the right to write there. You are requesting that the maintainers pull your branch into theirs: the action, when approved, is performed by the receiving side, integrating from your branch. The name is honest about authority: proposer proposes, owner integrates. It predates the button — in pre-platform kernel-style workflows, git request-pull (Module 1's trivia, now meaningful) generated exactly this message: "please pull from my repository at this address."
The details that separate candidates: an average answer shrugs "GitHub named it that." A strong answer explains the direction-of-action logic, connects it to the permission model (contributors get no write access to main — the whole security posture of open source), and lands the historical anchor (request-pull, mailing-list workflows). This apparently-trivial question is really testing whether you understand who has authority over what in distributed collaboration — answer it that way.
🎯 "What command helps us know the list of branches merged to master?" — asked verbatim in Interview Coder's 90+ Git questions, Sep 2025
git branch --merged master (or main) — lists branches whose tips are reachable from that branch: their work is fully contained, so deleting them loses nothing. Its complement git branch --no-merged master lists branches with unmerged commits — the ones branch -d would refuse (Module 5's seatbelt, same reachability test). Remote-side audit: git branch -r --merged origin/main. Typical cleanup: git branch --merged main | grep -v main | xargs git branch -d — with -d, never -D, so the seatbelt still catches mistakes.
The details that separate candidates: an average answer names the flag. A strong answer explains the underlying test — reachability in the commit graph, the same relation powering -d's safety and fast-forward detection — and the operational caveat that makes seniors pause: a squash-merged branch is not detected as merged (its commits were never merged, only their content re-recorded as a new commit), so squash-heavy teams cannot trust --merged for cleanup and rely on the host's branch-deletion automation instead. That one caveat is worth the whole answer.
Part C — Forks: collaboration without shared write access
C1. A fork is a server-side copy you own
The PR flow in Part B assumes everyone can push branches to the shared repository. Open source cannot assume that — thousands of strangers cannot have push access to anything. The fork solves it: a host-side copy of the repository under your account, where you have full push rights. You clone your fork, work on branches there, push to your fork, and open PRs from your fork's branch to the original's main. The original's maintainers never granted you anything; you never needed them to. Keeping oriented requires exactly the two-remote pattern Module 8 D2 promised: origin = your fork (push there), upstream = the original (fetch from there to stay current).
A fork is not a Git concept — it is git clone performed by the host, onto the host, plus a UI relationship. Which means you can simulate one on your disk with a bare clone, and understand the whole dance offline:
🧪 Exercise 9.4 — the fork dance, simulated end to end
cd ~/git-course
git clone --bare bakery.git bakery-fork.git # "the host copies the repo to your account"
git clone bakery-fork.git kitchen-contributor # you clone YOUR fork
cd kitchen-contributor
git remote add upstream ~/git-course/bakery.git # the original project
git remote -v
git switch -c feature/spice-guide # contribute on a branch
echo "cardamom pairs with cinnamon" > spices.txt
git add spices.txt && git commit -q -m "Add spice pairing guide"
git push -u origin feature/spice-guide # push to YOUR fork only
git fetch upstream # stay current with the original
git branch -r✅ Expected result — click to reveal
Cloning into bare repository 'bakery-fork.git'...
done.
Cloning into 'kitchen-contributor'...
done.
origin /home/aisha/git-course/bakery-fork.git (fetch)
origin /home/aisha/git-course/bakery-fork.git (push)
upstream /home/aisha/git-course/bakery.git (fetch)
upstream /home/aisha/git-course/bakery.git (push)
branch 'feature/spice-guide' set up to track 'origin/feature/spice-guide'.
* [new branch] main -> upstream/main
origin/HEAD -> origin/main
origin/feature/spice-guide
origin/main
upstream/mainWhat to read out of it (routine Switched to… / push-progress lines elided): two remotes, two photo namespaces (origin/* = your fork, upstream/main = the original), and your feature branch pushed only to the fork — the original repository was never written to, which is the entire security model. From here, a real host's "open pull request" offers yourfork:feature/spice-guide → original:main. Staying current is git fetch upstream + git merge upstream/main on your branches (never commit to your fork's main — keep it a clean mirror of upstream's, so every PR starts from truth). Every mechanic here is Module 8; the fork only rearranged who owns which copy.
🎯 Interview questions — Part C
🎯 "What is the Difference Between a Fork and a Clone?" — asked verbatim in GeeksforGeeks' 70+ Git Interview Questions, updated Jul 2026
A clone is a Git operation: a full local copy of a repository on your machine, wired to the source as origin — how anyone gets code to work on. A fork is a host platform operation: a server-side copy of someone else's repository created under your account, giving you a place you may push when you cannot push to the original. They compose rather than compete: the open-source flow is fork (on the host) → clone your fork (locally) → branch, commit, push to the fork → PR from fork to original. The fork also keeps a host-level link to its parent, which is what makes cross-repository PRs and "sync fork" buttons possible.
The details that separate candidates: an average answer says "fork is on GitHub, clone is local." A strong answer states the reason forks exist — write-access economics: maintainers grant nobody push rights, yet accept contributions from anyone — and describes the two-remote working setup (origin = fork, upstream = original, fetch upstream/push origin) that makes fork-based work sane. Precision bonus: a fork is not a Git object or command — plain Git can emulate it with any second copy you can push to, which is also why the same flow works on every host.
Part D — Choosing a branching model
D1. The three named models
Every named model answers one question differently: how does code travel from a keyboard to a release? Git Flow (Driessen, 2010) is the heavyweight: permanent main (production) and develop (integration) branches, plus feature/* off develop, release/* for stabilization, and hotfix/* off main — built for explicitly versioned software where multiple releases live in parallel. GitHub Flow is the lightweight default this module has been teaching: one permanent branch, short feature branches, PR, merge, deploy — built for continuously delivered services. Trunk-based development goes furthest: everyone integrates to main ("trunk") at least daily — branches live hours, not weeks, or vanish entirely in favor of direct small commits — with unfinished work hidden behind feature flags (runtime toggles) instead of long branches; it is the model the DORA research associates with elite delivery performance.
Worth quoting in interviews: Git Flow's own author added a reflection to the original post in 2020 — for continuously delivered web software he now points teams to simpler flows like GitHub Flow, while standing by Git Flow for explicitly versioned, multi-version-supported software. The model wars have a truce line, drawn by release model.
| Model | Permanent branches | Branch lifetime | Built for | Cost |
|---|---|---|---|---|
| Git Flow | main • develop (+ release/hotfix lanes) | Days–weeks | Versioned releases; several supported versions at once | Ceremony; long-lived divergence; slow integration |
| GitHub Flow | main only | Hours–days | Continuous delivery of services; PR-centric teams | Needs real CI and deploy automation on main |
| Trunk-based | main only | Hours (or none) | High-frequency integration; elite CD; monorepos | Demands feature flags, strong tests, mature team discipline |
D2. How to actually choose
Let the release model decide, not fashion. Shipping a service continuously, one production version at a time? GitHub Flow — moving toward trunk-based as CI strength and flag infrastructure grow. Shipping versioned artifacts customers install and you must patch in parallel (a CLI, firmware, an on-prem product)? Git Flow's release and hotfix lanes earn their ceremony. Migrating between models is cheap in Git terms (branches are pointers) and expensive in habit terms — so choose for your delivery reality, write it down, and enforce the invariants with protection rules rather than memos. The one metric that predicts pain regardless of model: integration latency. Whatever you call your workflow, branches that live longer diverge further, conflict harder, and review worse (Modules 6 and 9, unified). Every model is, at heart, a policy for keeping that number small.
🎯 Interview questions — Part D
🎯 "What is a Git workflow model, and can you name a few?" — asked verbatim in WeCreateProblems' 100+ GIT Interview Questions, 2026
A workflow model is a team's agreed pattern for branches and integration — which branches exist permanently, where work happens, how code reaches release. The named ones: Git Flow (main + develop + feature/release/hotfix lanes; for versioned, multi-version software), GitHub Flow (main + short PR'd feature branches; for continuously delivered services), GitLab Flow (GitHub Flow plus environment or release branches as a middle path), trunk-based development (daily-or-faster integration to main, feature flags over long branches), and the forking workflow (contribution without write access — the open-source layer that composes with any of the above).
The details that separate candidates: an average answer names two or three models. A strong answer states the selection criterion — release model: continuous delivery favors light flows, parallel supported versions justify Git Flow — citing the Git Flow author's own 2020 guidance to that effect, and names the shared invariant (releasable main, enforced by protection rules) plus the shared enemy (integration latency: long-lived branches hurt in every model). Mentioning feature flags as the technology that lets trunk-based hide unfinished work signals current, practiced knowledge rather than blog recall.
Part E — Production practice
E1. Symptom → cause → diagnosis → fix
Click the symptom you're seeing.
⚠️ PR shows files/commits the author never touched
What is really happening: The branch is stale — the "changes" are main's movement viewed two-dot, or an outdated base.
Diagnose: git diff --stat main...feature locally — the honest contribution
The fix: Update the branch from main (merge, or rebase — Module 10); the PR diff recalculates.
⚠️ remote: error: GH006: Protected branch update failed (or similar direct-push refusal)
What is really happening: Branch protection is doing its job — direct pushes to main are policy-forbidden.
Diagnose: Read the refusal; check the repo's protection rules
The fix: Branch, push, PR — the intended path; never ask for a protection exception you don't truly need.
⚠️ git branch --merged misses branches everyone agrees were merged
What is really happening: They were squash-merged: content landed as a new commit, and their commits were never merged.
Diagnose: git diff main branch — the endpoint diff is empty once the content landed (three-dot still shows the contribution); git cherry main branch also flags equivalent patches
The fix: Trust the host's merged-state + auto-delete, not graph reachability, on squash-heavy teams.
⚠️ Fork's PRs keep including old, unrelated commits
What is really happening: The fork's main drifted — commits were made on it instead of branches, or it's months behind upstream.
Diagnose: git log --oneline upstream/main..main on the fork clone
The fix: Reset fork main to upstream/main (it should be a pure mirror), branch from there; never commit to fork main.
⚠️ Review turnaround is days; PRs pile up unreviewed
What is really happening: PRs are too large and/or review is not treated as first-class work — process, not Git.
Diagnose: Measure PR size and time-to-first-review over a month
The fix: Slice work smaller (stacked/short PRs), set review SLAs, make review count as delivery.
⚠️ Two teammates unknowingly build the same feature for a week
What is really happening: Branches were unpushed or not named meaningfully — no visibility.
Diagnose: git branch -r — what is the team actually working on?
The fix: Push branches on day one, name by ticket, open draft PRs early as broadcast.
E2. Capstone — four tickets
Worked answer: GitHub Flow with trunk-based ambitions. Concretely: protected main (no direct pushes, no force-push, required CI checks, one approval); feature/<ticket>-<slug> branches capped informally at ~2 days of life; PRs opened as drafts on day one for visibility; squash-merge as the default button (clean main history; the team accepts losing branch-internal commits) or merge-commit if per-feature revertability (revert -m 1, Module 7) matters more — make that choice explicitly and write it down. Deploy from main on merge. As flag infrastructure matures, shrink branch lifetime toward trunk-based rather than "adopting" it by decree. Justify with the module's one metric: every element above is a lever on integration latency.
Worked answer: push back, with the release-model argument. GitHub Flow assumes one production version that continuously advances; you support parallel versions needing independent patches — precisely the case Git Flow's author still endorses his model for (2020 note, citable). You need at minimum: long-lived release/4.x and release/5.x branches, hotfixes branched from and merged back into the affected release lines (and forward-ported to main — state the merge direction explicitly in the runbook), and tags for every shipped build (Module 12). Full Git Flow's develop branch is negotiable — many versioned-product teams run "GitHub Flow + release branches" (GitLab Flow's shape) and skip the ceremony. The interview-grade close: workflow follows release model; HQ's mandate optimizes for a delivery reality you do not have.
Worked answer: fork-based contribution as the security boundary: outside contributors get zero write access — they fork, push to their fork, open cross-repo PRs; maintainers alone merge. Layer the protections: protected main with required maintainer review; CI for fork PRs configured to not expose secrets (host platforms run fork PRs without secret access by default — verify, don't assume, and require approval-to-run-CI for first-time contributors); a CONTRIBUTING.md defining branch naming, commit style (Module 2's conventions), and DCO/CLA sign-off if legal requires attribution chains; CODEOWNERS so sensitive paths demand specific reviewers. Internally nothing changes — employees can keep the shared-repo flow; the two models compose in one repository. The mental model to state: forks turn "who may write?" from a trust decision into an architecture.
Worked answer: the numbers describe an integration-latency problem, not a skills problem — training on conflict resolution treats the symptom (Module 6's fleet lesson, escalated to org level). The causal chain: big work items → big branches → long life → divergence → conflicts and unreviewable PRs → slow review → longer life. Break it at the source: slice work so a branch is mergeable in ≤2 days (vertical slices, stacked PRs for genuinely large features); merge main into open branches daily until then; cap PR size socially (and dashboards make it visible); set a same-day first-review norm — review latency compounds branch age. Keep one training item only: the three-dot diff habit, so reviews at least look at the right changes while sizes shrink. Present it as physics, not blame: every workflow model is a policy for keeping integration latency small, and 16-day branches mean the policy, not the people, failed.
E3. Documentation reference
| Topic | Official source | What it covers |
|---|---|---|
| Branching workflows (concepts) | Git Book §3.4 — Branching Workflows | Long-running vs topic branches |
| Distributed workflows | Git Book §5.1 — Distributed Workflows | Centralized, integration-manager (forks), dictator models |
| Pull requests | About pull requests — GitHub Docs | PR anatomy, review, merge strategies |
| GitHub Flow | GitHub flow — GitHub Docs | The lightweight PR-centric model, step by step |
| Forks | About forks — GitHub Docs | Fork relationships, syncing, cross-repo PRs |
| Git Flow (original) | A successful Git branching model — nvie | The 2010 model, plus the author's 2020 reflection |
| Trunk-based development | trunkbaseddevelopment.com | The model, feature flags, release strategies |
E4. Self-assessment
Try each question aloud, from memory, before opening its answer — the gap between your answer and the hidden one is what to study.
1. State the one invariant every team workflow protects, and the two host features that enforce it.
The invariant: main is sacred and always releasable — nobody commits to it directly; it moves only by merging reviewed branches. It is enforced by protected branches (refusing direct pushes, force-pushes, and unapproved merges) and required status checks (CI, linters, scans that the merge button demands before allowing a merge).
2. Walk a feature's full lifecycle, command by command, from switch -c to the post-merge cleanup.
git switch -c feature/<ticket>-<slug> to start; commit the work; git push -u origin <branch> early for visibility and backup. While main moves, git merge main on the feature to stay current. At review time: git log main..feature for the commits and git diff --stat main...feature for the contribution. Merge with git merge --no-ff feature (the merge button), push, then git push origin --delete <branch> and git branch -d <branch>, auditing safety with git branch --merged main.
3. Which direction do you merge to keep a feature branch current, and why does it make the final merge easier?
You merge main into your feature branch — the same git merge, pointed the other way. Conflicts get resolved on your branch, at your pace, leaving main pristine; your branch then contains everything main has, so the final merge back can no longer conflict on that content and becomes trivial.
4. A PR is "not a Git object" — what does that mean concretely, and which diff form does a PR display?
No PR exists anywhere in .git — it is a host construct: a proposal to merge branch X into branch Y, wrapped in machinery Git does not provide (discussion thread, line comments, approval state, CI results, a merge button with policy). The diff it shows is the three-dot form, git diff main...feature — merge-base to tip, what the branch contributes, not what main did meanwhile.
5. Merge commit vs squash vs rebase on the merge button: what does main's history look like after each?
Merge commit (--no-ff) preserves the branch bubble and adds one revertable merge node. Squash collapses all branch commits into a single new commit on main — clean history, with the feature branch's own commits discarded. Rebase replays the branch commits individually onto main with no merge commit — a linear sequence.
6. Why does git branch --merged lie on squash-heavy teams?
Because --merged tests reachability in the commit graph, and a squash-merged branch's commits were never merged — only their content was re-recorded as a new commit on main. The branch tips remain unreachable from main, so it is not detected as merged; squash-heavy teams rely on the host's merged-state and branch auto-deletion instead.
7. What problem do forks solve that branches cannot? Name the two remotes and the direction of fetch/push for each.
Branches require push access to the shared repository, which open source cannot grant to thousands of strangers. A fork is a host-side copy under your account where you have full push rights, so anyone can contribute with zero access to the original. The setup: origin = your fork (push there), upstream = the original project (fetch from there to stay current).
8. Why should a fork's main never receive direct commits?
It should stay a clean mirror of upstream's main, so every PR starts from truth. If commits land on it, it drifts, and the fork's PRs start including old, unrelated commits; the fix is to reset it to upstream/main and do all work on branches.
9. Give the one-line purpose of Git Flow's develop, release/*, and hotfix/* branches.
develop is the permanent integration branch that feature/* branches come off; release/* branches exist to stabilize a release before it ships; hotfix/* branches come off main to patch production directly.
10. What criterion chooses between Git Flow and GitHub Flow — and what did Git Flow's author say in 2020?
The release model, not fashion: continuously delivered services with one production version fit GitHub Flow; explicitly versioned software with several supported versions in parallel earns Git Flow's release and hotfix lanes. In 2020 the author added a reflection to the original post: for continuously delivered web software he now points teams to simpler flows like GitHub Flow, while standing by Git Flow for versioned, multi-version-supported software.
11. What is trunk-based development's answer to "where does unfinished work live, if not on branches?"
Behind feature flags — runtime toggles that hide unfinished work in code already integrated to main. Everyone integrates to trunk at least daily; branches live hours or vanish entirely, so long-lived branches stop being the hiding place.
12. Define integration latency and explain why it is the unifying metric behind Modules 6 and 9.
Integration latency is how long work lives on a branch before being integrated. Branches that live longer diverge further, conflict harder, and review worse — Module 6's fleet lesson at team scale — and every workflow model is, at heart, a policy for keeping that number small. It is the one metric that predicts pain regardless of the model's name.
E5. Sources
🗒️ Cheat sheet — Module 9
| Command / concept | What it does / means |
|---|---|
| git switch -c feature/<ticket>-<slug> → work → git push -u origin <branch> | Start and publish a unit of work; main untouched |
| git merge main (while on the feature) | Catch the branch up; resolve conflicts on your side, at your pace |
| git log main..feature · git diff --stat main...feature | Review a "PR" locally: its commits · its true contribution (three-dot) |
| git merge --no-ff <feature> → delete remote + local branch | The merge button and its cleanup, by hand |
| git branch --merged main · --no-merged main | Safe-to-delete audit · branches still carrying unmerged work (squash caveat!) |
| git clone <your-fork> • git remote add upstream <original> | The fork working setup: push to origin, fetch from upstream |
| git fetch upstream • git merge upstream/main | Keep fork-based work current with the original project |
| Protected branch · required checks | Host-enforced: no direct/force pushes; CI + approvals gate the merge |
| Merge strategies: merge commit / squash / rebase | Bubble + one-revert unit / one clean commit, branch history discarded / linear replay (Module 10) |
| Git Flow · GitHub Flow · trunk-based | main+develop+lanes for versioned ships · main+PR branches for CD · daily-or-faster integration with feature flags |
Key concepts: main is sacred and always releasable; it moves only by reviewed merges — enforced by protection rules, not memos · a workflow is sequencing of commands you already know · keep branches current by merging main in; review against current reality · a PR = host construct: three-dot diff + review + checks + policy; not in .git · squash breaks --merged detection · forks = write-access architecture: origin (yours, push) + upstream (theirs, fetch); fork main stays a mirror · choose models by release model — continuous delivery → light flows; parallel versions → Git Flow lanes · the universal enemy: integration latency.