Stage 2 · Tools
Remote Collaboration
Fork & Upstream Workflow
Contributing to open source with forks, upstream remotes, and sync patterns.
Why Fork?
Forking creates a server-side copy of a repository under your own account. This is the standard way to contribute to open source projects where you don't have write access to the original repository. You make changes in your fork and then submit a pull request back to the upstream project.
Forking is also useful in enterprise settings where you want to customize a library or maintain a diverged version without affecting the original. It gives you complete control over your copy while keeping a clear link to the source.
A clone is a local copy. A fork is a server-side copy on GitHub (or GitLab/Bitbucket) that lives in your account. You clone your fork, not the upstream repo. The fork maintains a reference to the original for syncing.
Forking Setup
After forking a repository on GitHub, you need to clone your fork locally and configure the upstream remote. This two-remote setup — origin pointing to your fork, upstream pointing to the original — is the foundation of the forking workflow.
git clone https://github.com/YOUR-USER/awesome-project.git
cd awesome-project
git remote -vClones your fork and shows remotes. You'll see origin pointing to your fork. The upstream repo is not configured yet.
git remote add upstream https://github.com/ORIGINAL-OWNER/awesome-project.git
git remote -vAdds the original repository as upstream. Now you have two remotes: origin (your fork, read-write) and upstream (original, read-only).
If you accidentally try to push to upstream, Git will reject it because you lack write access. But you can configure remote.upstream.push to disable as an extra safety measure.
Keeping Your Fork Synced
The upstream repository evolves constantly. To keep your fork current, you fetch from upstream and merge or rebase the changes into your local main branch. Then push the updated main to your fork.
git fetch upstream
git checkout main
git merge upstream/main
git push origin mainFetches the latest from upstream, merges it into your local main, and pushes the updated main to your fork. This keeps your fork aligned with the original project.
git fetch upstream
git checkout main
git rebase upstream/main
git push origin main --force-with-leaseRebasing instead of merging keeps your fork's main branch linear. Since you're the only one working on your fork's main, force pushing is safe here.
git fetch --prune origin
git branch -d feature/old
git push origin --delete feature/oldAfter a PR is merged, delete the feature branch from your fork to keep it clean. Pruning removes remote-tracking references to deleted branches.
Always create feature branches in your fork. If you make changes directly on main in your fork, syncing with upstream becomes complicated. Keep main as a mirror of upstream.
Contributing via Fork
The standard contribution flow for open source: sync your fork, create a feature branch, make changes, push to your fork, and open a PR against the upstream repository.
# 1. Sync your fork
git fetch upstream
git checkout main
git merge upstream/main
# 2. Create a feature branch
git checkout -b fix/null-pointer
# 3. Make changes and commit
git add .
git commit -m "fix: handle null user in auth middleware"
# 4. Push to your fork
git push origin fix/null-pointer
# 5. Create PR against upstream
gh pr create \
--repo ORIGINAL-OWNER/awesome-project \
--title "Fix null pointer in auth middleware" \
--body "Fixes #301"Each step is deliberate: sync first so your branch is based on the latest code, then create a focused branch, commit with a conventional message, push to your fork, and open the PR against the upstream repo.
If the upstream repo changes while your PR is open, rebase on the latest upstream main and force push to your fork. This keeps the PR mergeable and shows reviewers you're working with current code.
Using gh repo fork
GitHub CLI can fork a repository and clone it in one command, automating the setup that would otherwise require multiple manual steps.
gh repo fork ORIGINAL-OWNER/awesome-project --cloneCreates a fork on GitHub under your account, clones it locally, and sets origin to your fork and upstream to the original. The --clone flag handles everything.
gh repo fork ORIGINAL-OWNER/awesome-project --clone=falseCreates the fork on GitHub without cloning. Useful if you want to add the upstream remote to an existing local clone instead.
Fork vs Branch Workflow
Both workflows achieve the same goal — enabling code review before merging — but they differ in access control, complexity, and trust model.
| Aspect | Branch Workflow | Fork Workflow |
|---|---|---|
| Write access | Direct push to feature branches in the same repo | Push only to your own fork |
| Trust model | Trusted contributors get branch access | Anyone can contribute without repo access |
| Complexity | Simple — one remote, one repo | Two remotes, sync overhead |
| CI triggers | PRs trigger CI automatically | Fork PRs may need explicit CI approval |
| Best for | Internal teams, small orgs | Open source, external contributors |
Internal teams use branch workflows for speed. External contributors use forks for isolation. Projects like Kubernetes accept both — team members branch, community members fork.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.