Thousands of projects on GitHub are open source: anyone can read the code, and anyone can suggest improvements. But you can't push to a project you don't own. If you could, any stranger could change it. So how do outsiders contribute?
The answer is a fork: your own copy of someone else's repository, stored under your GitHub account. You can push whatever you like to your fork, and when your change is ready, you open a pull request asking the original project to take it. The maintainers review it and, if they like it, merge it.
In this lesson you'll fork a repository, clone it, connect it to the original project, keep it up to date, and open a pull request from your fork. You'll also learn how to find beginner-friendly issues and what maintainers expect from a first contribution.
Fork, clone and branch
These three words are easy to mix up:
| Where | What it's for | |
|---|---|---|
| Fork | A copy on GitHub, under your account | Contributing to a repository you can't push to |
| Clone | A copy on your computer | Working on any repository locally |
| Branch | A line of work inside a repository | Separating one change from another |
In practice you use all three: fork on GitHub, clone your fork to your computer, then create a branch for your change.
origin and upstream
After cloning your fork, its remote origin points to your copy. To receive new changes from the original project, add a second remote, conventionally called upstream:
git remote add upstream https://github.com/original-owner/project.gitYou then pull from upstream to stay current and push to origin to share your work. You can't push to upstream, and you don't need to: the pull request carries your changes there.
Keeping your fork in sync
The original project keeps moving while you work. To update:
git switch main
git fetch upstream
git merge upstream/main
git push origin mainGitHub also shows a Sync fork button on your fork's page that does the same for the copy on GitHub; afterwards, run git pull locally. Keep your fork's main identical to upstream's, and never commit to it directly: do all work on branches.
Opening a pull request from a fork
Push your branch to your fork, then visit either repository on GitHub. A banner offers Compare & pull request. Check the top of the form: the base repository should be the original project and the head repository your fork.
Leave Allow edits by maintainers ticked, so maintainers can make small fixes directly. Then follow the review process from the code review lesson: respond to feedback by pushing to the same branch.
Bringing a pull request branch up to date
While your pull request waits for review, the original project keeps merging other work. If GitHub reports a conflict, or the maintainers ask you to update your branch, bring in the latest upstream changes and push again:
git fetch upstream
git switch fix-typo
git rebase upstream/main
git push --force-with-lease origin fix-typoThe rebase replays your commits on top of the newest upstream main, so you resolve any conflicts on your own machine, where you can run the tests. Because rebasing rewrites your branch's commits, the push needs --force-with-lease. That's acceptable here because the branch lives in your fork and only you work on it. The open pull request updates automatically, so you don't need to open a new one.
Some projects would rather you didn't rewrite commits that reviewers have already seen. In that case run git merge upstream/main instead and finish with a normal git push. CONTRIBUTING.md or a maintainer's comment usually tells you which they prefer.
GitHub Forks Syntax
Fork workflow
# 1. Click Fork on GitHub, then:
git clone https://github.com/<you>/<project>.git
cd <project>
git remote add upstream https://github.com/<owner>/<project>.git
git switch -c fix-typo
# edit, commit
git push -u origin fix-typo
# 2. Open a pull request on GitHub
git fetch upstream && git merge upstream/main # stay in syncGitHub Forks Summary
- A fork is your own copy of someone else's repository on GitHub.
- Clone your fork, and add the original as a remote called upstream.
- Fetch and merge upstream/main to stay up to date; push your work to origin.
- Open the pull request from your fork's branch to the original repository.
- Read CONTRIBUTING.md and start with issues labelled good first issue.
GitHub Forks Examples
Each example shows the code, the output it produces and what each part does.
Setting up a fork
git clone https://github.com/samlee/recipe-api.git
cd recipe-api
git remote add upstream https://github.com/open-kitchen/recipe-api.git
git remote -vCloning into 'recipe-api'...
origin https://github.com/samlee/recipe-api.git (fetch)
origin https://github.com/samlee/recipe-api.git (push)
upstream https://github.com/open-kitchen/recipe-api.git (fetch)
upstream https://github.com/open-kitchen/recipe-api.git (push)Line-by-line explanation
- Line 1Clone your fork (samlee), not the original project.
- Line 3Add the original project (open-kitchen) as upstream.
- Line 4Two remotes: origin for your copy, upstream for the source.
Syncing with upstream
git switch main
git fetch upstream
git merge upstream/main
git push origin mainAlready on 'main'
From https://github.com/open-kitchen/recipe-api
4d2e1f0..8b9c0a1 main -> upstream/main
Updating 4d2e1f0..8b9c0a1
Fast-forward
README.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
To https://github.com/samlee/recipe-api.git
4d2e1f0..8b9c0a1 main -> mainLine-by-line explanation
- Line 2Download new commits from the original project.
- Line 3A fast-forward, because you never commit directly to main in a fork.
- Line 4Update your fork on GitHub too.
A first contribution
git switch -c fix-readme-typo
git commit -am "docs: fix typo in installation steps"
git push -u origin fix-readme-typo[fix-readme-typo 2f3a4b5] docs: fix typo in installation steps
1 file changed, 1 insertion(+), 1 deletion(-)
remote: Create a pull request for 'fix-readme-typo' on GitHub by visiting:
remote: https://github.com/samlee/recipe-api/pull/new/fix-readme-typoLine-by-line explanation
- Line 1A branch for one small change.
- Line 3Push to your fork. GitHub prints a link to open the pull request against the original project.
Common GitHub Forks Mistakes
Cloning the original instead of your fork
git clone https://github.com/open-kitchen/recipe-api.git
git push # Permission deniedgit clone https://github.com/samlee/recipe-api.gitWorking on main in a fork
git switch main
git commit -am "Add feature"git switch -c add-feature
git commit -am "Add feature"Commits on your fork's main make syncing with upstream messy.
A surprise big change
Open a 1,500-line pull request rewriting the project's structureOpen an issue first: "Would you accept a change to ...?" then send a small PRGitHub Forks in Real Projects
Open source in practice
Every popular open-source project, from Python itself to VS Code and React, accepts contributions through forks and pull requests. Many maintainers label approachable tasks good first issue or help wanted; searching for those labels is the best way to find a first contribution. Documentation fixes, clearer error messages and tests are all valuable contributions, and they're excellent practice.
GitHub Forks FAQ
Can I fork a private repository?
Only if you have access to it and forking is allowed. Organizations can turn off forking of their private repositories. A fork of a private repository is private too, and you lose access to it if your access to the original is removed.
What happens to my fork if the original repository is deleted?
For a public repository, deleting the original doesn't delete its public forks; your fork stays, with all its history. It just no longer has an upstream to sync from or send pull requests to.
How do I delete a fork?
Open your fork's Settings and use the option to delete the repository at the bottom of the page, typing its name to confirm. This deletes only your copy and its history on GitHub; the original project isn't affected. Push or merge anything you want to keep first.
Can I fork my own repository?
Not into the same account, because GitHub keeps one fork of a repository per account. To start a separate project from your own code, use a template repository, or create a new empty repository and push a copy of the history to it.
Why doesn't my fork have an Issues tab?
Issues are turned off by default on forks, since bug reports normally belong in the original project. If you want issues for your own copy, turn them on under Features in the fork's Settings.
GitHub Forks Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the command that adds the original project as a remote.
git remote add https://github.com/open-kitchen/recipe-api.git
What is a fork?
After forking and cloning, what does origin point to?
Which commands bring the original project's new commits into your local main?
When opening a PR from a fork, what should the base repository be?
GitHub Forks Quiz
5 questions to check what you learned.
Why do you need a fork to contribute to most open-source projects?
- Forks are faster
- GitHub requires a fork for every PR
- Forks are private
- You don't have permission to push to the original repository
What does the Sync fork button do?
- Deletes your fork
- Updates your fork on GitHub with the original project's new commits
- Merges your PR
- Creates a new branch
Which file usually explains how a project wants contributions made?
- LICENSE
- .gitignore
- CONTRIBUTING.md
- package.json
Which label often marks issues suitable for newcomers?
- good first issue
- wontfix
- duplicate
- invalid
Why keep your fork's main identical to upstream's main?
- GitHub deletes forks that differ
- Pull requests only work from main
- Syncing stays a simple fast-forward, and new branches start from the project's latest code
- It makes the fork private