Forks & Open Source
Pull requests inside your own team are simple, because everyone can push branches to the same repository. But you cannot push to a project you do not own, such as a popular open source library or your friend's college project. A fork solves this: it is your own copy of someone else's repository on GitHub, where you can push freely, and from which you can send pull requests back to the original.
This is the workflow behind nearly all open source contributions. In this lesson Rohan, a student in Kochi, contributes a small fix to Priya's sweet-shop repository through a fork.
Fork, origin and upstream
Three copies of the repository are involved, and it helps to name them clearly:
| Copy | Lives on | Remote name on your laptop | You can push? |
|---|---|---|---|
| The original project | GitHub, priya-sharma/sweet-shop | upstream | No |
| Your fork | GitHub, rohan-verma/sweet-shop | origin | Yes |
| Your clone | Your laptop | (none, it is local) | Yes |
Changes flow in a circle: you push to your fork (origin), open a pull request from the fork to the original, and fetch new work from the original (upstream) to stay up to date.
Step 1: fork and clone
On the original repository page, Rohan clicks Fork, keeps the default name, and clicks Create fork. A copy appears at github.com/rohan-verma/sweet-shop. He clones his fork, not the original, because that is where he can push:
git clone git@github.com:rohan-verma/sweet-shop.git
cd sweet-shopStep 2: add the upstream remote
The clone knows only about origin (his fork). To receive new work from the original project, he adds a second remote, by convention called upstream:
git remote add upstream https://github.com/priya-sharma/sweet-shop.git
git remote -vorigin git@github.com:rohan-verma/sweet-shop.git (fetch) origin git@github.com:rohan-verma/sweet-shop.git (push) upstream https://github.com/priya-sharma/sweet-shop.git (fetch) upstream https://github.com/priya-sharma/sweet-shop.git (push)
Using the HTTPS address for upstream is a common trick: he only ever fetches from it, so no login is needed.
Step 3: branch, commit and push to the fork
Never work on the fork's main. Rohan fixes the capitalisation of a heading on a branch and pushes it to his fork:
git switch -c fix-typo-about
git commit -am "Fix capitalisation on about page"
git push -u origin fix-typo-aboutSwitched to a new branch 'fix-typo-about' [fix-typo-about bb2cb23] Fix capitalisation on about page 1 file changed, 1 insertion(+), 1 deletion(-) To github.com:rohan-verma/sweet-shop.git * [new branch] fix-typo-about -> fix-typo-about branch 'fix-typo-about' set up to track 'origin/fix-typo-about'.
Step 4: open the pull request
On his fork's page, GitHub shows a Compare & pull request button. The PR form shows four boxes: the base repository (priya-sharma/sweet-shop) and base branch (main) on the left, and the head repository (rohan-verma/sweet-shop) and compare branch (fix-typo-about) on the right. Check that the base repository is the original, write a clear title and description, and create the PR. Maintainers of the original project review it exactly as in Pull Requests & Code Review. By default, GitHub also lets maintainers push small fixes to your PR branch, which speeds things up.
Step 5: keep up with upstream
While Rohan waits for a review, Kabir's "Mention Sunday opening" commit lands in the original main. Rohan's branch is now behind. He fetches from upstream, rebases his branch on top, and updates his PR with a safe force push (the branch belongs only to him):
git fetch upstream
git rebase upstream/main
git push --force-with-leaseFrom https://github.com/priya-sharma/sweet-shop * [new branch] main -> upstream/main Successfully rebased and updated refs/heads/fix-typo-about. To github.com:rohan-verma/sweet-shop.git + bb2cb23...6d7176a fix-typo-about -> fix-typo-about (forced update)
His fork's main is out of date too. He brings it level with the original and pushes it to the fork:
git switch main
git merge --ff-only upstream/main
git pushSwitched to branch 'main' Your branch is up to date with 'origin/main'. Updating ebe02fd..9f372d2 Fast-forward contact.html | 1 + To github.com:rohan-verma/sweet-shop.git ebe02fd..9f372d2 main -> main
--ff-only guarantees he never creates an accidental merge commit on his fork's main. GitHub also has a Sync fork button on the fork's page that updates the fork's main in the browser; then a git pull brings it to the laptop.
Before you contribute to a real project
Open source projects are run by people, often volunteers. A little preparation makes your PR far more likely to be accepted:
- Read
CONTRIBUTING.md. It explains how the project wants contributions: coding style, how to run the tests, commit message format, and whether to open an issue first. - Read the
LICENSE. Your contribution is shared under the project's license (MIT, Apache 2.0, GPL and so on). - Follow the
CODE_OF_CONDUCT.md. Be polite and patient in every comment. - Start small. Look for issues labelled
good first issueorhelp wanted, documentation fixes or missing tests. Comment on the issue to say you are working on it. - Sign off if asked. Some projects, including the Linux kernel, require a
Signed-off-by:line confirming you have the right to submit the code (the Developer Certificate of Origin).git commit -sadds it using your configured name and email. - Keep the PR focused. One fix per PR, with no unrelated formatting changes.
Common mistakes
- Cloning the original instead of your fork. Your push is then refused. Change the remote:
git remote set-url origin git@github.com:you/project.git. - Working on your fork's
main. Your PR then mixes with every future change. Always branch. - Letting the fork fall far behind. Fetch
upstreamregularly and rebase your branch before asking for review. - Opening a large PR without discussion. For anything big, open an issue first and agree on the approach with the maintainers.
Key points
- A fork is your own copy of someone else's repository on GitHub, where you can push.
- Clone your fork (
origin) and add the original asupstream. - Work on a branch, push it to your fork, and open a PR whose base repository is the original.
- Stay in sync with
git fetch upstream, rebase your branch, and fast-forward your fork'smain(or use Sync fork). - Read
CONTRIBUTING.md, start withgood first issue, keep PRs small, and be polite.
Exercise
Ask a classmate to create a public repository (or create one with a second GitHub account). Fork it, clone your fork, add the original as upstream, fix something small on a branch and open a pull request. While it is open, have the owner push a new commit to main, then bring your branch and your fork's main up to date.
Show solution
git clone git@github.com:you/class-notes.git
cd class-notes
git remote add upstream https://github.com/classmate/class-notes.git
git switch -c fix-date-format
git commit -am "Use DD-MM-YYYY dates in notes"
git push -u origin fix-date-format
git fetch upstream
git rebase upstream/main
git push --force-with-lease
git switch main
git merge --ff-only upstream/main
git pushThe PR updates itself after the force push, now based on the latest main. Your fork's main matches the original again, ready for your next branch.
Quick Quiz
1. In the usual fork setup, what does the upstream remote point to?
origin is your fork; upstream is the original project you fetch updates from.
2. Which repository should you clone after forking?
You push branches to your fork and open the PR from there.
3. Why use git merge --ff-only upstream/main to update your fork's main?
A fast-forward-only update keeps your main a clean copy of upstream.
4. What should you read first before contributing to an open source project?
It explains how the maintainers want contributions made.
Learn Git with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
