Lesson 5 - Guided Project: Contribute a Feature via PR

Welcome to the Guided Project

You have read about forks, opened pull requests, learned how review works, and seen how to keep a fork in sync. Now you’ll do all of it at once, on a real project. In this guided project you’ll contribute an actual feature to datatweets/git-collaboration-practice — a small, public, list-based task-manager app written in Python and built for exactly this kind of practice. It contains a task_manager.py program plus a README.md, a CONTRIBUTORS.md, and an EXERCISES.md of suggested improvements.

This is not a simulation. The repo is live, it accepts pull requests, and you are warmly invited to send a real one. We’ll fork it, add an optional priority to tasks, push the change to your fork, open a pull request describing it clearly, and then walk through responding to review — the exact loop that contributing to any open-source project looks like.

By the end of this project, you will be able to:

  • Fork and clone a public repository and confirm your origin and upstream remotes
  • Build a small, focused feature on a branch and commit it with a clear message
  • Open a well-described pull request from your fork to the original
  • Respond to review by pushing more commits, then sync your fork afterward

Everything below uses real commands and real output. Your account name, branch, and commit hashes will differ from the examples — that’s expected. Let’s contribute.


Stage 1: Fork and Clone the Practice Repo

First, get your own writable copy. You can click the Fork button on https://github.com/datatweets/git-collaboration-practice, or — much faster — do it from the terminal with the GitHub CLI. The --clone flag forks the repo and clones your new fork and wires up the upstream remote for you in one step:

$ gh repo fork datatweets/git-collaboration-practice --clone
$ cd git-collaboration-practice

Confirm your remotes. You should see two of them — origin pointing at your fork, and upstream pointing at the original:

$ git remote -v
origin    [email protected]:you/git-collaboration-practice.git (fetch)
origin    [email protected]:you/git-collaboration-practice.git (push)
upstream  [email protected]:datatweets/git-collaboration-practice.git (fetch)
upstream  [email protected]:datatweets/git-collaboration-practice.git (push)

Where you appears, you’ll see your own GitHub username. The key thing: origin is your fork (you push here) and upstream is the original (you pull updates from here). Because gh repo fork --clone added upstream automatically, you don’t have to run git remote add yourself.

Take a quick look around so you know what you’re changing:

$ ls
CONTRIBUTORS.md  EXERCISES.md  README.md  task_manager.py

Stage 2: Create a Feature Branch and Make the Change

Never work directly on main. Create a focused branch named for what you’re doing:

$ git switch -c add-priority
Switched to a new branch 'add-priority'

Now open task_manager.py. It’s a small list-based task manager — tasks are dictionaries stored in a list, and there’s a function that adds a new one. Today’s feature: let a task carry an optional priority so it can be marked "normal" or "high", defaulting to "normal" when the caller doesn’t specify.

The “before” function looks roughly like this:

def add_task(tasks, title):
    task = {"title": title, "done": False}
    tasks.append(task)
    return task

Add an optional priority parameter with a sensible default, so existing calls keep working unchanged:

def add_task(tasks, title, priority="normal"):
    task = {"title": title, "done": False, "priority": priority}
    tasks.append(task)
    return task

This is the heart of a good contribution: a small, self-contained change that adds value without breaking anything. Because priority defaults to "normal", every place that already calls add_task(tasks, "Buy milk") behaves exactly as before — you’ve extended the function, not rewritten it.

Stage the file and commit it with a message that says what changed and why:

$ git add task_manager.py
$ git commit -m "Add optional task priority"

A clear, imperative commit message (“Add optional task priority”, not “changes”) is what a reviewer reads first — keep it honest and specific.


Stage 3: Push the Branch to Your Fork

Your commit lives only on your computer until you push it. Send the branch up to origin (your fork) and set it to track, so future git push calls need no arguments:

$ git push -u origin add-priority
 * [new branch]      add-priority -> add-priority
branch 'add-priority' set up to track 'origin/add-priority'.

Before the lines above, Git prints a short burst of object-transfer progress (counting, compressing, and writing objects) as it uploads your commit. The exact counts depend on your change, so don’t be surprised that yours differ — the line that matters is * [new branch] add-priority -> add-priority, confirming the branch now exists on your fork.


Stage 4: Open the Pull Request

Your branch is on your fork; now propose it to the original. Two ways:

In the browser: right after pushing, GitHub usually shows a yellow “Compare & pull request” banner on both your fork and the original repo. Click it, double-check that the base is datatweets/git-collaboration-practice main and the head is you/git-collaboration-practice add-priority, write a title and description, and submit.

From the terminal, with gh, which is faster and keeps you in flow:

$ gh pr create --base main --head add-priority \
    --title "Add optional task priority" \
    --body "Adds an optional priority field so tasks can be marked normal/high."

On success, gh pr create prints the URL of your brand-new pull request — something like https://github.com/datatweets/git-collaboration-practice/pull/<number>. Open that link to see your PR live, with your commit, the diff, and a place for discussion. (Your PR’s number and URL are assigned by GitHub when you submit, so they’ll be unique to you.)

A good description does a reviewer a favor. State what the change does and why it’s useful, and keep it short:

Add optional task priority

Adds an optional priority field to tasks so they can be marked normal or high. Defaults to normal, so existing calls to add_task are unaffected. This is a small step toward sorting or filtering tasks by importance later.


Stage 5: Respond to Review, Then Sync Your Fork

A maintainer reviews your PR and leaves a comment — say, “Could you reject any value that isn’t normal or high?” You don’t open a new pull request to answer. You just push more commits to the same branch, and the PR updates automatically.

Make the requested change in task_manager.py, then commit and push again:

$ git add task_manager.py
$ git commit -m "Validate priority is normal or high"
$ git push

Note the plain git push — no -u origin add-priority needed this time, because Stage 3 set the branch to track origin/add-priority. Refresh the PR page and your new commit appears in the conversation and the diff. It’s polite to leave a brief reply (“Done — added validation, thanks!”) so the reviewer knows you’ve addressed the feedback. This back-and-forth is normal and expected; review makes the change better, it isn’t a rejection.

Once your PR is merged (congratulations!), bring that work — and anyone else’s that landed while you were busy — back into your fork. Fetch from upstream, update your local main, and push it to origin:

$ git switch main
$ git fetch upstream
$ git merge upstream/main
$ git push origin main

Now your fork’s main matches the original, and you’re ready to start your next feature from a clean, up-to-date base. You can also delete the merged branch (git branch -d add-priority) to keep things tidy.

This is a real repo — be a good contributor

datatweets/git-collaboration-practice is public and genuinely accepts pull requests, so do this for real — there’s no substitute for a contribution that actually gets reviewed. Be the kind of contributor maintainers love: keep each PR small and focused (one idea per PR), write a clear title and description, and respond to feedback by pushing more commits rather than arguing. And remember gh repo fork --clone sets up your upstream remote automatically, so syncing later is painless.


Practice Exercises

Extend the project with a few more real contributions. Each one is another full trip through the fork-and-PR loop — exactly the repetition that makes it second nature.

Exercise 1: Add yourself to CONTRIBUTORS.md

Open a second pull request that adds your name (and optionally a one-line note) to CONTRIBUTORS.md. It’s a tiny change, which is the point: practice the whole flow on something low-stakes.

Hint

Start from an up-to-date main, then git switch -c add-myself-to-contributors. Edit CONTRIBUTORS.md, then git add, git commit -m "Add <your-name> to contributors", git push -u origin add-myself-to-contributors, and gh pr create. Keep this PR separate from your priority feature — one idea per pull request.

Exercise 2: Tackle a task from EXERCISES.md

Open EXERCISES.md in the repo and pick one of its suggested improvements (for example, a function to mark a task done, or to filter tasks by priority). Implement it on a fresh branch and open a PR.

Hint

Read EXERCISES.md first and choose the smallest task you understand fully. Branch from an updated main (git fetch upstream && git merge upstream/main first), make the change in task_manager.py, write a commit message that names the feature, and describe in the PR which exercise you implemented and how to use it.

Exercise 3: Review someone else’s pull request

Browse the open pull requests on datatweets/git-collaboration-practice and leave a constructive review comment on one — a question, a suggestion, or a “looks good to me.”

Hint

Open the PR’s Files changed tab to read the diff, then comment on a specific line or use the overall review box. Be specific and kind: point to exact lines, suggest rather than demand, and say what you liked. Reviewing is half of collaboration — practicing it makes you a better contributor too.


Summary

You contributed a real feature to a real, public repository through a pull request. You forked and cloned datatweets/git-collaboration-practice with gh repo fork --clone (which set up upstream automatically), confirmed your origin and upstream remotes, created the add-priority branch, added an optional priority to task_manager.py with a safe default, and committed it with a clear message. You pushed the branch to your fork, opened a pull request with a focused title and a description that explained what and why, responded to review by pushing another commit to the same branch, and finally synced your fork with upstream after the merge. That is the complete contribution loop — the same one used across open source and professional teams.

Key Concepts

  • gh repo fork --clone — forks, clones, and adds upstream in a single command.
  • Focused feature branch — one small, self-contained change per branch and per PR.
  • Backward-compatible change — an optional parameter with a default keeps existing calls working.
  • Responding to review — push more commits to the same branch; the PR updates itself.
  • Sync after mergegit fetch upstream, git merge upstream/main, git push origin main.

Why This Matters

Reading about pull requests teaches the shape; sending a real one builds the instinct. After this project you can walk into any public repository on GitHub, fork it, make a thoughtful change, and propose it the way maintainers expect — small, clearly described, and open to feedback. Every real contribution also leaves a visible, public track record of your work, which is one of the most credible things you can show. The mechanics you practiced here scale directly to the team workflows you’ll meet next.


Next Steps

Continue to Module 6 - Team Workflows

Branching strategies, commit conventions, and releases — how teams organize their work in Git.

Back to Module Overview

Return to the Collaboration with Pull Requests module overview


Continue Building Your Skills

You’ve now made a complete, reviewed contribution from fork to merge — the most valuable collaboration skill in this course, practiced for real. Next, in Module 6, you’ll step up from a single contribution to how whole teams stay organized: branching strategies, commit conventions, and cutting releases. Keep contributing to the practice repo in between; nothing cements these steps like doing them again.