Fork and Upstream Workflow
When contributing to projects you don't have write access to, you work through a fork. This lesson covers the complete fork workflow used in open source development.
What is a Fork?
A fork is your personal copy of someone else's repository on GitHub. You can:
- Push changes freely to your fork
- Experiment without affecting the original
- Submit pull requests to the original project
1┌─────────────────────────────────┐2│ Original Repository │3│ (github.com/org/project) │4│ "upstream" │5└───────────────┬─────────────────┘6 │ fork7 ▼8┌─────────────────────────────────┐9│ Your Fork │10│ (github.com/you/project) │11│ "origin" │12└───────────────┬─────────────────┘13 │ clone14 ▼15┌─────────────────────────────────┐16│ Local Repository │17│ (your machine) │18└─────────────────────────────────┘
Creating a Fork
On GitHub
- Go to the repository you want to contribute to
- Click the "Fork" button (top right)
- GitHub creates a copy under your account
With GitHub CLI
bash1$ gh repo fork org/project2✓ Created fork you/project3? Would you like to clone the fork? Yes4Cloning into 'project'...
This forks and clones in one step.
Setting Up Remotes
After forking and cloning, configure two remotes:
| Remote | Points To | Purpose |
|---|---|---|
origin | Your fork | Push your changes |
upstream | Original repo | Pull latest changes |
Rename Origin (Optional)
Some prefer explicit naming:
bash1$ git remote rename origin origin-self
Add Upstream
bash1$ git remote add upstream git@github.com:org/project.git
Verify Remotes
bash1$ git remote -v2origin git@github.com:you/project.git (fetch)3origin git@github.com:you/project.git (push)4upstream git@github.com:org/project.git (fetch)5upstream git@github.com:org/project.git (push)
Syncing Your Fork
The original project continues to evolve. Keep your fork updated:
Fetch Upstream Changes
bash1$ git fetch upstream2From github.com:org/project3 * [new branch] main -> upstream/main4 abc1234..def5678 develop -> upstream/develop
Update Your Main Branch
bash1$ git checkout main2$ git rebase upstream/main3First, rewinding head to replay your work on top of it...4Fast-forwarded main to upstream/main.
Push Updated Main to Your Fork
bash1$ git push origin main
If your fork has diverged, you may need:
bash1$ git push origin main --force-with-lease
Contributing via Fork
Standard Workflow
bash1# 1. Sync with upstream2$ git fetch upstream3$ git checkout main4$ git rebase upstream/main56# 2. Create feature branch7$ git checkout -b feature/my-contribution89# 3. Make changes10$ vim file.txt11$ git add file.txt12$ git commit -m "feat: add my contribution"1314# 4. Push to your fork15$ git push -u origin feature/my-contribution1617# 5. Open PR to upstream18$ gh pr create --repo org/project --base main --head you:feature/my-contribution
PR from Fork to Upstream
When creating a PR from a fork, specify:
--repo: The upstream repository--base: Branch in upstream to merge into--head: Your fork and branch (username:branch)
bash1$ gh pr create \2 --repo org/project \3 --base main \4 --head you:feature/my-contribution \5 --title "Add my contribution" \6 --body "Description of changes"
Keeping Feature Branch Updated
If upstream changes while you're working:
bash1# Fetch latest2$ git fetch upstream34# Rebase your feature onto updated main5$ git rebase upstream/main67# Force push to update PR8$ git push --force-with-lease origin feature/my-contribution
Fork Sync Commands Summary
| Task | Commands |
|---|---|
| Sync fork main | git fetch upstream && git checkout main && git rebase upstream/main && git push origin main |
| Update feature branch | git fetch upstream && git rebase upstream/main && git push --force-with-lease |
| Create PR to upstream | gh pr create --repo org/project --base main --head you:branch |
Common Fork Workflows
Workflow 1: Quick Fix
bash1$ gh repo fork org/project --clone2$ cd project3$ git checkout -b fix/typo4# ... make fix ...5$ git add . && git commit -m "fix: typo in readme"6$ git push -u origin fix/typo7$ gh pr create --repo org/project --fill
Workflow 2: Long-Term Contribution
bash1# Initial setup (once)2$ gh repo fork org/project --clone3$ cd project4$ git remote add upstream git@github.com:org/project.git56# Before each contribution7$ git fetch upstream8$ git checkout main9$ git rebase upstream/main10$ git push origin main1112# Create feature13$ git checkout -b feature/new-thing14# ... work ...15$ git push -u origin feature/new-thing16$ gh pr create --repo org/project
Key Takeaway
Fork workflow: fork → clone → add upstream → sync regularly → branch → commit → push to fork → PR to upstream. Keep your fork synchronized with upstream to minimize merge conflicts when contributing.