GitForking Workflow

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
  1. Fork the upstream repository on GitHub/GitLab (creates your personal server-side copy).

  2. Clone your fork locally.

  3. Add the upstream remote so you can pull in the original project's changes.

  4. Create a branch on your fork for the specific change.

  5. Commit and push to your fork's branch.

  6. Open a Pull Request from your fork's branch to the upstream's main branch.

  7. Respond to review feedback, push more commits to your fork's branch.

  8. Maintainer merges the PR into upstream.

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

Bash
# 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

Bash
# 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)

Bash
# 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)

Bash
# 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

Bash
# 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
Forks do not automatically stay in sync
Your fork is a snapshot of the upstream repository at the moment you forked it. As upstream accumulates new commits, your fork falls behind. You must manually sync your fork's `main` with upstream's `main` to avoid basing new work on outdated code.

Sync your fork with upstream

Bash
# 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)

Bash
# 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

Bash
# 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

Bash
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

Bash
# 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
Your fork is yours to experiment on freely
One underappreciated benefit of the forking workflow is that your fork is entirely yours. You can push broken commits, force-push, experiment wildly, and reorganise history on your fork without affecting anyone else. The upstream repository is protected at all times.
Configure upstream as a read-only remote
Prevent accidental pushes to upstream by removing its push URL: `git remote set-url --push upstream no-pushing` After this, `git push upstream` will fail with a helpful error message instead of a permissions error.