What You'll Learn
- How to find beginner-friendly issues on GitHub
- The fork + clone + upstream workflow
- Reading CONTRIBUTING.md and setting up the project
- Writing a focused, well-structured contribution
- Opening a high-quality pull request
- Responding to review comments professionally
- Keeping your fork up to date after the merge
A typo fix in the README, a clarified code comment, a missing example in the docs — these are exactly as valuable as bug fixes for users who encounter them. Documentation PRs are also easier to get merged (no risk of breaking functionality), making them the perfect first contribution. Don't underestimate the "docs" commit type.
Step 1 – Finding a Beginner-Friendly Issue
The "good first issue" label is your best friend. Projects add this label specifically for new contributors:
| GitHub search query | What it finds |
|---|---|
label:"good first issue" language:JavaScript | JS projects with beginner issues |
label:"good first issue" label:"help wanted" | Actively seeking contributors |
label:"documentation" is:open | Documentation improvements needed |
Other resources: goodfirstissue.dev, up-for-grabs.net, and firstcontributions.github.io.
Before claiming an issue:
- Read the issue fully — understand what's being requested
- Check if someone is already working on it (look for recent comments)
- Leave a comment: "I'd like to work on this. I'll have a PR ready by [date]."
- Wait for a maintainer to assign it to you before starting
Step 2 – Fork and Clone
# On GitHub: click the "Fork" button (top right of the repo page)
# This creates a copy under YOUR account: github.com/YOUR-USERNAME/repo-name
# Clone YOUR fork (not the original)
git clone git@github.com:YOUR-USERNAME/awesome-project.git
cd awesome-project
# Add the original repository as "upstream"
# This lets you pull in future changes from the original
git remote add upstream git@github.com:ORIGINAL-OWNER/awesome-project.git
# Verify you have both remotes
git remote -v
# origin git@github.com:YOUR-USERNAME/awesome-project.git (fetch)
# origin git@github.com:YOUR-USERNAME/awesome-project.git (push)
# upstream git@github.com:ORIGINAL-OWNER/awesome-project.git (fetch)
# upstream git@github.com:ORIGINAL-OWNER/awesome-project.git (push)
Step 3 – Read CONTRIBUTING.md and Set Up
Before writing a single line of code, read the project's contribution guide:
# Look for contribution documentation
ls
# CONTRIBUTING.md CODE_OF_CONDUCT.md README.md ...
cat CONTRIBUTING.md
# Read carefully for:
# - How to set up the development environment
# - How to run tests
# - Code style requirements (linting, formatting)
# - Commit message conventions
# - PR template and requirements
# Set up the project per CONTRIBUTING.md instructions
# (example for a Node.js project)
npm install
npm test # Make sure all tests pass before you change anything!
If tests are already failing before your change, you need to know that — otherwise you might think you broke something that was already broken. Run the full test suite immediately after cloning. If tests fail, check the issue tracker to see if it's a known problem. If it seems unrelated to your issue, document it when opening your PR.
Step 4 – Create Fix Branch and Make the Change
# Make sure you're on an up-to-date main
git switch main
git fetch upstream
git rebase upstream/main
git push origin main # Keep your fork's main in sync too
# Create a focused branch for your fix
# Name it descriptively — include the issue number if possible
git switch -c fix/issue-42-typo-in-readme
# OR for a feature: git switch -c feat/issue-87-add-dark-mode
# Make your change
# (For a docs fix: edit README.md or the relevant .md file)
# (For a code fix: make the smallest change that fixes the issue)
# Verify the change looks right
git diff
# Run tests again to make sure nothing broke
npm test
# Stage your change
git add README.md
# Write a good conventional commit message
git commit -m "docs: fix typo 'recieve' → 'receive' in installation guide
The word 'receive' was misspelled as 'recieve' in the installation
instructions section, which could cause confusion for new users
following the guide.
Closes #42"
# The "Closes #42" will automatically close the issue when the PR is merged
Step 5 – Push to Your Fork and Open a PR
# Push your branch to YOUR fork
git push -u origin fix/issue-42-typo-in-readme
# To git@github.com:YOUR-USERNAME/awesome-project.git
# * [new branch] fix/issue-42-typo-in-readme -> fix/issue-42-typo-in-readme
GitHub will show a banner: "fix/issue-42-typo-in-readme had recent pushes — Compare & pull request". Click it. Fill in the PR template:
## Summary
Fixes a typo in the installation guide: "recieve" → "receive".
## Related Issue
Closes #42
## Changes Made
- Fixed spelling of "receive" in `README.md` line 47
## Testing
- No code changes — documentation fix only
- Verified the surrounding text still makes sense in context
## Screenshots
(Not applicable for this text-only change)
Good PR habits:
- Title: imperative mood, concise — "Fix typo in installation guide" (not "Fixed" or "Fixing")
- Link to the issue: "Closes #42" auto-closes the issue on merge
- Keep scope small — one fix per PR
- Don't mix unrelated changes in the same PR
- Be patient — maintainers are volunteers and may take days or weeks to review
Step 6 – Responding to Review Comments
A reviewer might request changes. This is normal — even experienced contributors get review feedback. The review process makes the contribution better.
# Address the reviewer's feedback on your local branch
git switch fix/issue-42-typo-in-readme
# Make the requested changes
# Then commit them
git add README.md
git commit -m "docs: address review feedback — also fix related typo"
# Push to update the PR (the same branch, so the PR updates automatically)
git push
# On GitHub: reply to the reviewer's comment to let them know you've addressed it
# "Done — I also noticed and fixed the same typo on line 53 per your suggestion."
# Then click "Re-request review"
Code review is about the code, not about you. When a maintainer requests changes, they're investing time to make your contribution better. Respond professionally, thank them for their feedback, ask for clarification if something is unclear. Maintainers remember contributors who are pleasant to work with — they'll review your future PRs faster.
Step 7 – After Merge: Sync Your Fork
# Congratulations! Your PR was merged!
# Update your local main from upstream
git switch main
git fetch upstream
git rebase upstream/main
# Update your fork's main on GitHub
git push origin main
# Delete the local feature branch (it's been merged, no longer needed)
git branch -d fix/issue-42-typo-in-readme
# Delete the remote branch on your fork
git push origin --delete fix/issue-42-typo-in-readme
# Your fork is now clean and ready for your next contribution!
Good Contribution Practices
| Practice | Why |
|---|---|
| One logical change per PR | Easier to review, easier to revert if needed |
| Always branch from an up-to-date main | Minimize merge conflicts |
| Read CONTRIBUTING.md before coding | Avoid wasted effort on PRs that won't be accepted |
| Write tests for code changes | Maintainers expect it; prevents regressions |
| Check the PR template | Missing info = delayed review |
| Respond to reviews within 48 hours | Shows you're engaged; PRs go stale quickly |
| Start with docs/typos | Get familiar with the process before tackling code |
📋 Summary
- Find beginner issues: search "good first issue" or "help wanted" labels. Comment before starting.
- Fork → Clone → Add upstream remote:
git remote add upstream <original-url> - Read CONTRIBUTING.md and run tests before writing any code.
- Create a focused branch: branch from an up-to-date main, one fix per branch.
- Write a good conventional commit message with "Closes #N" to auto-close the issue.
- Open a clear PR: imperative title, description of what and why, test plan, link to issue.
- Respond to reviews professionally and promptly.
- After merge: sync your fork's main from upstream, delete the branch, start fresh for the next contribution.
- Documentation fixes are real contributions — start there and build confidence for code contributions.
FAQ
It's appropriate to politely "ping" the PR after 1–2 weeks with a brief comment like: "Friendly reminder — is there anything I can improve on this PR to help it get reviewed?" Keep it short and non-demanding. Maintainers are often volunteers with limited time. If a project consistently takes months to review PRs, check if there's a more active fork or alternative project. It's also worth checking if the project is still actively maintained — look at recent merged PRs and commit activity.
This happens to everyone — even experienced contributors. Common reasons: the change doesn't fit the project's direction, the issue was already fixed differently, or the scope was too large. When a PR is closed, read the maintainer's explanation carefully. Thank them for their time and feedback. Use what you learned on your next contribution. Rejection doesn't mean your work was bad — open source projects have specific visions and constraints that aren't always visible to outside contributors. The experience is still valuable learning.
For any repository you don't have write access to, you must fork. Forking is the standard open-source contribution model. The fork+PR workflow is also used within organizations — internal contributors may be required to use PRs even if they technically have push access, to ensure code review happens. You only push directly (without a PR) when: you own/maintain the repository, or you're a trusted collaborator and the team explicitly allows direct pushes to feature branches (never to main in a protected-branch setup).
Sync your fork's main from upstream: git fetch upstream && git rebase upstream/main. Then rebase your feature branch on the updated main: git switch your-branch && git rebase main. If there are conflicts, resolve them. Then force-push the rebased branch (it's safe since only you work on your fork's feature branch): git push --force-with-lease origin your-branch. Using --force-with-lease (instead of plain --force) is safer — it aborts if someone else has pushed to the branch since your last fetch.