Forking Workflow
The forking workflow is the standard model for open-source contribution on platforms like GitHub and GitLab. Instead of every contributor pushing branches to a single shared repository, each contributor creates their own server-side copy (a fork) of the repository. All work happens on the fork. Changes reach the original (upstream) repository only through a reviewed, approved Pull Request. This model enables thousands of strangers to contribute to the same project without any of them needing write access to the canonical repository.
Forks vs branches — key distinction
A branch is a pointer within a single repository. A fork is a separate, independent copy of the entire repository on the hosting platform (GitHub, GitLab, etc.). They share Git history but are stored separately.
Dimension | Branch | Fork |
|---|---|---|
Location | Within a single repository | A separate server-side repository |
Who can create it? | Anyone with write access to the repo | Anyone (even without write access to original) |
Push access needed? | Yes (to the original repo) | Only to your own fork (not the original) |
Isolation | Logical only | Complete server-side isolation |
Used for | Internal team work | Open-source contributions, safe experimentation |
Sync with origin | Automatic via fetch | Manual (add upstream remote, fetch, merge) |
The complete open-source contribution flow
Fork the upstream repository on GitHub/GitLab (creates your personal server-side copy).
Clone your fork locally.
Add the upstream remote so you can pull in the original project's changes.
Create a branch on your fork for the specific change.
Commit and push to your fork's branch.
Open a Pull Request from your fork's branch to the upstream's main branch.
Respond to review feedback, push more commits to your fork's branch.
Maintainer merges the PR into upstream.
Sync your fork with upstream to stay current.
Step 1: Fork the repository
Forking is done in the web UI. Click the "Fork" button on GitHub or GitLab. This creates github.com/your-username/project as a copy of github.com/original-org/project.
Fork via GitHub CLI
# Fork on GitHub without leaving the terminal gh repo fork original-org/project # ✓ Created fork your-username/project # ? Would you like to clone the fork? Yes # Cloning into 'project'... # Now you have: # origin → github.com/your-username/project (your fork) # upstream → github.com/original-org/project (the original)
Step 2: Clone your fork and add upstream
Clone fork and configure remotes
# Clone your fork (not the original) git clone https://github.com/your-username/project.git cd project # Verify remotes git remote -v # origin https://github.com/your-username/project.git (fetch) # origin https://github.com/your-username/project.git (push) # Add the original repo as "upstream" git remote add upstream https://github.com/original-org/project.git # Verify again git remote -v # origin https://github.com/your-username/project.git (fetch) # origin https://github.com/your-username/project.git (push) # upstream https://github.com/original-org/project.git (fetch) # upstream https://github.com/original-org/project.git (push)
Step 3: Create a branch on your fork
Branch from upstream main (not your fork's potentially stale main)
# Fetch the latest from upstream first git fetch upstream # Create your branch from upstream/main git switch -c fix/typo-in-readme upstream/main # Switched to a new branch 'fix/typo-in-readme' # (alternatively from your local main after syncing — see Step 7)
Step 4 & 5: Make changes and push to your fork
Commit and push to your fork (not upstream)
# Make the fix vim README.md git add README.md git commit -m "docs: fix typo in installation instructions" # Push to YOUR fork (origin), not upstream git push -u origin fix/typo-in-readme # Branch 'fix/typo-in-readme' set up to track remote branch. # To github.com:your-username/project.git # * [new branch] fix/typo-in-readme -> fix/typo-in-readme
Step 6: Open a Pull Request to upstream
Open a PR from your fork to the upstream repo
# GitHub CLI (cross-repository PR) gh pr create --repo original-org/project --base main --head your-username:fix/typo-in-readme --title "Fix typo in installation instructions" --body "Corrects 'requied' → 'required' in the npm install step. Fixes #234." # Or open in browser: # GitHub shows a banner: "Compare & pull request" when you push a branch
Step 7: Keep your fork in sync with upstream
Sync your fork with upstream
# Fetch the latest changes from upstream (not origin) git fetch upstream # From https://github.com/original-org/project # * [new branch] main -> upstream/main # * [new tag] v2.1.0 -> v2.1.0 # Switch to your local main git switch main # Merge or rebase upstream/main into your local main git merge upstream/main # (or rebase for cleaner history: git rebase upstream/main) # Push the synced main to your fork git push origin main # To github.com:your-username/project.git # abc1234..9a8b7c6 main -> main
GitHub web UI sync (one-click alternative)
# On your fork's GitHub page: # Click "Sync fork" → "Update branch" # This syncs main on your fork without touching your local clone. # Then locally: git pull origin main
Keeping a feature branch up to date during long review
Rebase your PR branch onto the latest upstream main
# Fetch latest upstream git fetch upstream # Rebase your feature branch git switch fix/typo-in-readme git rebase upstream/main # Force-push the rebased branch to your fork git push --force-with-lease origin fix/typo-in-readme # (This updates the open PR on GitHub automatically)
Forking workflow in practice: Linux, React, etc.
Linux kernel — Linus Torvalds maintains the authoritative kernel tree. Subsystem maintainers maintain their own trees. Contributors fork, create patches, and send pull requests up the tree. The forking workflow at massive scale.
React (Meta) — external contributors fork facebook/react, make changes, and open PRs. Core team members review and merge.
VS Code (Microsoft) — thousands of contributors fork microsoft/vscode and submit PRs for bug fixes and features.
Homebrew — contributors fork Homebrew/homebrew-core to add or update formula files.
Your own open-source project — once you publish a library or tool publicly, all external contributors will use the forking workflow by default.
Forking workflow vs feature branch workflow
Dimension | Feature Branch Workflow | Forking Workflow |
|---|---|---|
Who can push branches? | Anyone with repo write access | Anyone (to their own fork) |
Write access to main repo required? | Yes (to push branches) | No (only to your fork) |
Number of repositories involved | 1 | Many (1 per contributor + upstream) |
Syncing complexity | Simple (fetch origin) | Manual upstream sync required |
Security model | Trust-based (team members) | Distrust-by-default (any contributor can fork) |
Best for | Internal teams with shared write access | Open source, external contributions |
PR crosses repositories? | No (within same repo) | Yes (from fork to upstream) |
Common errors
Error: accidentally pushed to upstream instead of fork
git push origin main # remote: Permission to original-org/project.git denied to your-username. # fatal: unable to access '...': The requested URL returned error: 403 # This is a safety feature — you cannot push to upstream if you only have # fork access. Double-check your remotes: git remote -v # (make sure origin = your fork, upstream = original)
Error: PR conflicts because fork is out of date
# GitHub shows: "This branch has conflicts that must be resolved" # Fix: sync your fork and rebase the feature branch git fetch upstream git switch fix/my-feature git rebase upstream/main # (resolve any conflicts) git push --force-with-lease origin fix/my-feature