What is a Pull Request (and why should you care?)
Opening your first pull request (PR) can feel intimidating. You are taking code you wrote on your private laptop and submitting it for review to another project—sometimes a project run by complete strangers on the other side of the world.
A pull request is simply a formal proposal. You tell the project maintainer: “I took a copy of your project, made a specific improvement or bug fix on my own branch, and now I’d like you to pull these changes into your project.”
PRs are the universal currency of open-source collaboration and modern software engineering teams. They give teams a shared space to:
- Review code line-by-line before it breaks production.
- Run automated tests (CI/CD pipelines) to verify your changes.
- Discuss architectural choices and maintain code quality.
This tutorial is written for beginners who know basic Git commands (git add, git commit) but have never submitted changes to someone else’s GitHub repository. Let’s break down the whole process from fork to merge.
Part 1: The Core Mental Model
Before running commands, it helps to visualize where your code lives at each stage. Many beginners get confused between forking, cloning, and branching.
Here is how the four key concepts fit together:
| Concept | Where it lives | What it actually does |
|---|---|---|
| Fork | Remote (Your GitHub account) | Creates a server-side copy of someone else’s repository under your account. |
| Clone | Local (Your computer) | Downloads a repository from GitHub to your hard drive so you can edit files. |
| Branch | Local & Remote | An isolated workspace inside a repo where you make changes without touching main. |
| Pull Request | Remote (Original GitHub repo) | A request asking the original project owners to merge your branch into theirs. |
The Flow of Code
[Original Repo: upstream]
│ (Fork via GitHub UI)
▼
[Your Fork: origin]
│ (git clone)
▼
[Your Computer: local workspace]
│ (git checkout -b my-feature)
│ (make edits + git commit)
│ (git push origin my-feature)
▼
[Your Fork: origin/my-feature]
│ (Open Pull Request)
▼
[Original Repo: merged into main!]
Part 2: Open-Source Etiquette
Writing the code is only half the job. How you present your PR determines whether maintainers merge it with a smile or ignore it for months.
1. Check for Existing Issues
Before writing code, search the repository’s Issues tab. Has someone already reported this bug? Has someone already submitted a fix? If you are planning a large change, open an issue first to ask maintainers if they are open to your approach.
2. Keep Your PR Small and Atomic
Do not fix three bugs, refactor the database layer, and fix five typos in a single PR. A PR should do one thing. Small PRs get reviewed and merged quickly; massive 50-file PRs sit in review queues forever.
3. Write Meaningful Commit Messages
Avoid commit messages like:
fixed stuffupdateasdfghjk
Instead, write concise, imperative messages describing the intent:
fix: correct typo in installation instructionsfeat: add email validation to signup form
Hands-on Example: Your First Pull Request
Let’s walk through an end-to-end example. For this walk-through, assume you want to contribute to an open toy repository named community-board owned by an organization called octo-org.
Step 1: Fork the Repository
- Navigate to the project page on GitHub:
https://github.com/octo-org/community-board. - In the top-right corner, click the Fork button.
- Select your personal account as the destination. GitHub will create a copy at
https://github.com/YOUR-USERNAME/community-board.
Step 2: Clone Your Fork to Your Local Machine
Open your terminal and clone your fork (replace YOUR-USERNAME with your actual GitHub username):
git clone https://github.com/YOUR-USERNAME/community-board.git
cd community-board
Step 3: Link the Original Repository (upstream)
When you clone your fork, Git automatically sets your fork as a remote named origin. You also want a reference to the original project (conventionally called upstream) so you can pull future updates.
Check your current remotes:
git remote -v
Output:
origin https://github.com/YOUR-USERNAME/community-board.git (fetch)
origin https://github.com/YOUR-USERNAME/community-board.git (push)
Now, add the original repository as upstream:
git remote add upstream https://github.com/octo-org/community-board.git
Run git remote -v again to verify:
origin https://github.com/YOUR-USERNAME/community-board.git (fetch)
origin https://github.com/YOUR-USERNAME/community-board.git (push)
upstream https://github.com/octo-org/community-board.git (fetch)
upstream https://github.com/octo-org/community-board.git (push)
Step 4: Create a Dedicated Feature Branch
Never make your changes directly on main. Always create a new branch with a descriptive name:
git checkout -b add-tyika-profile
The -b flag creates the branch and switches you to it immediately.
Step 5: Make Your Change and Test It
Open the repository in your code editor. Suppose the project has a file named members.md. Add your entry to the list:
# Community Members
- Ada Lovelace (@ada) - London, UK
- Alan Turing (@alan) - Wilmslow, UK
- Asahluma Tyika (@asahluma) - Cape Town, South Africa
Save the file. Check your changes with git status and git diff:
git status
Output:
On branch add-tyika-profile
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: members.md
Step 6: Stage, Commit, and Push
Stage the modified file and write a descriptive commit message:
git add members.md
git commit -m "docs: add Asahluma Tyika to community roster"
Push your new branch up to your fork (origin):
git push -u origin add-tyika-profile
The -u flag sets upstream tracking so that future pushes on this branch only require git push.
Step 7: Open the Pull Request on GitHub
- Open your browser and go to your fork:
https://github.com/YOUR-USERNAME/community-board. - GitHub will automatically detect the recently pushed branch and display a yellow banner: “add-tyika-profile had recent pushes… Compare & pull request”. Click that button.
- Verify the branch targets:
-
base repository: octo-org/community-boardbase: main -
head repository: YOUR-USERNAME/community-boardcompare: add-tyika-profile
-
- Fill out the title and description:
### Summary of Changes
Adds my profile entry to the `members.md` roster.
### Related Issue
Closes #14
### Verification
- [x] Alphabetical order maintained
- [x] Markdown renders correctly
- Click Create pull request.
Step 8: Navigating the Code Review
Once your PR is submitted, maintainers or automated bots might leave feedback.
If a maintainer asks: “Could you format your city name to include the country code?”, you don’t need to close the PR and start over. You simply:
- Make the change in your local file (
members.md). - Commit the change locally:
git add members.md git commit -m "style: standardize country format" - Push to the same branch:
git push origin add-tyika-profile
GitHub automatically updates your existing Pull Request with your new commit. Once the maintainer approves, they will merge your PR, and your code becomes an official part of the project!
Common Mistakes and Troubleshooting
- Mistake 1: Committing directly to your local
mainbranch.- Symptom: You open a PR from
YOUR-USERNAME:maintoupstream:main. When you want to start another PR later, yourmainis polluted with unmerged changes. - Fix: Always branch off before editing:
git checkout -b branch-name. If you already committed tomain, rungit branch new-feature-name, thengit reset --hard upstream/mainto restore your localmain.
- Symptom: You open a PR from
- Mistake 2: Your fork is out of date with the original repo.
- Symptom: GitHub warns that your branch has conflicts that must be resolved.
- Fix: Fetch the newest changes from the original project and rebase your branch:
git checkout main git fetch upstream git merge upstream/main git checkout your-feature-branch git rebase main
- Mistake 3: Pushing with
git push upstreaminstead ofgit push origin.- Symptom: Git throws
remote: Permission to octo-org/community-board.git denied to YOUR-USERNAME. - Fix: You don’t have write access to the upstream repo. You must always push your branches to your own fork (
origin):git push origin your-feature-branch.
- Symptom: Git throws
- Mistake 4: Committing unintended files (e.g.,
.DS_Store,node_modules,.env).- Symptom: Your PR diff includes system files or secrets.
- Fix: Add those patterns to a
.gitignorefile immediately. To untrack an accidentally staged file without deleting it:git rm --cached <filename>, then commit.
Try It Yourself
Put these steps into practice without bothering a real maintainer:
- Create a dummy test repository on your GitHub account called
pr-practice. - Invite a friend or use a second test GitHub account to fork it.
- On that second account, clone the fork, create a branch named
test-contribution, add a file calledhello.txt, and push it. - Submit a pull request back to
pr-practice. - Switch back to your primary account, review the diff, request a change, make that change from the secondary branch, and merge it!
What’s Next
Congratulations—you now know the standard development workflow used by software teams around the globe.
To take your Git skills to the professional tier, keep an eye out for our upcoming guides:
- Resolving Git Merge Conflicts without Panic: How to read conflict markers (
<<<<<<<,=======,>>>>>>>) and resolve overlapping changes cleanly. - Git Rebase vs. Git Merge: When to rebase to keep a linear history and when a merge commit is better.
- Writing Effective GitHub PR Templates: Standardizing PR descriptions for your own repositories using
.github/PULL_REQUEST_TEMPLATE.md.
Bookmark this guide so you have a quick command reference ready for your next open-source contribution!