GitHub Forks and Open Source

Fork a repository, keep your fork in sync with the original, and contribute to open-source projects through pull requests.

Lesson 10 of 30Intermediate17 min read

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:

WhereWhat it's for
ForkA copy on GitHub, under your accountContributing to a repository you can't push to
CloneA copy on your computerWorking on any repository locally
BranchA line of work inside a repositorySeparating 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:

Terminal
git remote add upstream https://github.com/original-owner/project.git

You 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:

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

GitHub 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:

Terminal
git fetch upstream
git switch fix-typo
git rebase upstream/main
git push --force-with-lease origin fix-typo

The 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 sync

GitHub 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.

Example 1

Setting up a fork

Terminal
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 -v
Output
Cloning 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
  1. Line 1Clone your fork (samlee), not the original project.
  2. Line 3Add the original project (open-kitchen) as upstream.
  3. Line 4Two remotes: origin for your copy, upstream for the source.
Example 2

Syncing with upstream

Terminal
git switch main
git fetch upstream
git merge upstream/main
git push origin main
Output
Already 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 -> main
Line-by-line explanation
  1. Line 2Download new commits from the original project.
  2. Line 3A fast-forward, because you never commit directly to main in a fork.
  3. Line 4Update your fork on GitHub too.
Example 3

A first contribution

Terminal
git switch -c fix-readme-typo
git commit -am "docs: fix typo in installation steps"
git push -u origin fix-readme-typo
Output
[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-typo
Line-by-line explanation
  1. Line 1A branch for one small change.
  2. 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

Don't
git clone https://github.com/open-kitchen/recipe-api.git
git push    # Permission denied
Do
git clone https://github.com/samlee/recipe-api.git

Working on main in a fork

Don't
git switch main
git commit -am "Add feature"
Do
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

Don't
Open a 1,500-line pull request rewriting the project's structure
Do
Open an issue first: "Would you accept a change to ...?" then send a small PR

GitHub 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.

Fill in the blankseasy

Complete the command that adds the original project as a remote.

git remote add  https://github.com/open-kitchen/recipe-api.git
Multiple choiceeasy

What is a fork?

Multiple choicemedium

After forking and cloning, what does origin point to?

Multiple choicemedium

Which commands bring the original project's new commits into your local main?

Multiple choicehard

When opening a PR from a fork, what should the base repository be?

GitHub Forks Quiz

5 questions to check what you learned.

  1. 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
  2. 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
  3. Which file usually explains how a project wants contributions made?

    • LICENSE
    • .gitignore
    • CONTRIBUTING.md
    • package.json
  4. Which label often marks issues suitable for newcomers?

    • good first issue
    • wontfix
    • duplicate
    • invalid
  5. 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