Pull requests and the GitHub flow
Work on branches, open pull requests that are easy to review, and choose between merge, squash and rebase merges.
- Follow the GitHub flow: branch, commit, open a pull request, review, merge
- Write a pull request that is easy to review, and use drafts and linked issues
- Compare merge commits, squash merges and rebase merges
A pull request (PR) says: “here are some commits on my branch - please review them and pull them into main.” It’s the heart of collaboration on GitHub. Most teams follow the GitHub flow:
mainis always deployable.- Create a branch for each change:
fix/wall-clipping,feature/boss-battles. - Commit and push to the branch.
- Open a pull request early - as a draft if it isn’t ready.
- Automated checks run, and teammates review and discuss.
- Merge into
main, then delete the branch.
1git switch -c fix/wall-clipping # 1. a branch for the change
2# ...edit, test...
3git commit -am "Stop the hero clipping through walls after a dash"
4git push -u origin fix/wall-clipping # 2. publish the branch
5gh pr create --fill --draft # 3. open a draft PR (or use the button on GitHub)
6gh pr ready # 4. mark it ready for review
7gh pr merge --squash --delete-branch # 5. after approval and green checksTry it
The life of a pull request
Follow your first Dungeon Dash pull request from push to merge. Predict what happens at each step before revealing it.
A pull request people want to review
- Keep it small and focused. One change per PR. Reviewers catch far more problems in 100 lines than in 1,000.
- Explain why, not just what: the problem, the approach, anything you’re unsure about, and how you tested it. Screenshots for visual changes.
- Link the issue with a closing keyword.
- Review your own diff first - you’ll catch leftover debug prints.
- Open a draft early to get feedback on direction before you’ve polished the wrong thing.
A .github/pull_request_template.md file pre-fills every new PR description with a checklist.
Three ways to merge
Suppose main has commits A, B, and your branch adds X, Y, Z:
| Method | Resulting main | Good for |
|---|---|---|
| Merge commit | A, B, X, Y, Z, plus a merge commit M joining them | keeping full history and where branches came together |
| Squash and merge | A, B, then one new commit S with X+Y+Z’s changes | a clean, linear history with one commit per PR |
| Rebase and merge | A, B, X′, Y′, Z′ - copies of your commits replayed on top | linear history that keeps each commit |
Squash merging is popular because messy “fix typo” commits disappear. The catch: your branch’s commits are no longer on main (S is a new commit), so delete the branch after merging rather than continuing to build on it. Repository settings control which methods are allowed.
Key takeaways
GitHub flow: branch, commit, push, open a PR, get checks and review, merge, delete the branch.
Small, focused PRs that explain why and link their issue get reviewed faster and better.
Draft PRs invite early feedback; pushing to the branch updates the PR.
Merge commits keep everything, squash gives one commit per PR, rebase keeps commits but linearizes.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: automate GitHub chores with Python
Real GitHub work involves lots of small automation: matching CODEOWNERS, expanding build matrices, bumping versions, reading the API. Write those helpers in Python and run them against sample inputs - locally in your browser, with no GitHub account needed.
Simulate the merge button
The input has two lines: main: followed by main’s commits, and branch: followed by the PR branch’s commits (each word is a commit). Print main’s resulting history for each merge method:
merge commit: A B X Y M
squash: A B S
rebase: A B X' Y'(M is the new merge commit, S the new squash commit, and rebased commits get a ' because they’re new copies.) If the branch has only one commit, squash and rebase both produce that single commit as a new copy: S.
- Three commits
- One commit
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Label PRs by size
Many projects run a bot that labels pull requests by size. The input is a unified diff. Count the added lines (starting with +, but not the +++ file header) and removed lines (starting with -, but not ---), and the files changed (diff --git lines). Print files: 2, +7 -3 and a size label from the total changed lines:
| Total | Label |
|---|---|
| under 10 | size/XS |
| under 50 | size/S |
| under 250 | size/M |
| under 1000 | size/L |
| otherwise | size/XL |
- A small fix
- No changes
Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…