Skip to content

Cheatsheet: Remotes and forks

Git stores snapshots. Every other command is just navigating those snapshots.

Push and pull are navigating snapshots between machines.

Terminal window
# Inspect
git remote -v # list remotes with URLs
git branch -a # list local + remote-tracking branches
git branch -r # list only remote-tracking branches
git status # ahead/behind information
# Manage remotes
git remote add upstream <url> # add a remote
git remote remove upstream # remove a remote
git remote rename origin myorigin # rename a remote
# Get changes from remote
git fetch # download without merging
git fetch upstream # fetch from a specific remote
git pull # fetch + merge (default)
git pull --rebase # fetch + rebase (preferred)
# Send changes to remote
git push # push current branch (if tracking set)
git push -u origin <branch> # first push, sets tracking
git push --force-with-lease # safe force-push (personal branches only)
# Configure global defaults (run once)
git config --global pull.rebase true # make pull use rebase
git config --global merge.conflictstyle diff3 # better conflict markers (L7)
# Clone
git clone <url> # full copy of a remote repo
git clone <url> <folder-name> # clone into a specific folder
Terminal window
# 1. Fork on GitHub (UI click), then:
git clone https://github.com/<your-username>/<repo>.git
cd <repo>
git remote add upstream https://github.com/<original-owner>/<repo>.git
git remote -v # verify both remotes
# 2. Stay synced with upstream
git switch main
git fetch upstream
git rebase upstream/main
git push origin main
# 3. Contribute
git switch -c feature/my-change
# ... do work, commit
git push -u origin feature/my-change
# ... open PR on GitHub from your fork to upstream
Terminal window
git config --global pull.rebase true

After this, every git pull automatically uses rebase. No more merge-commit clutter.

Caveat: if you have uncommitted changes, git pull --rebase refuses. Either commit first, or git stash + pull + git stash pop.

Is the branch shared with others (main, develop, release/*)?
YES -> NEVER force-push
NO -> continue
Have I rebased / amended commits that are already on the remote?
NO -> regular git push works
YES -> continue
Has anyone else pushed to this branch since my last fetch?
YES -> force-with-lease will refuse; fetch and decide
NO -> git push --force-with-lease
NEVER use plain --force unless you 100% understand the consequences.
ALWAYS use --force-with-lease as the default safe variant.
NameWhat it is
main (local)Your local main branch
origin/mainRead-only label for “what origin’s main looked like at last fetch”
upstream/mainRead-only label for “what upstream’s main looked like at last fetch”

To compare:

Terminal window
git log main..origin/main # commits remote has that you don't
git log origin/main..main # commits you have that remote doesn't
git diff main origin/main # actual code differences

L9 introduces the three production team workflows: GitHub Flow, GitFlow, and Trunk-based Development. Each is a pattern built on the primitives from L5-L8 (branches, PRs, conflicts, remotes). You’ll learn the tradeoffs, when each fits, and how to choose for your team. After L9, you understand the structural choices behind every production engineering team’s git practices.

L9 opens Phase 3. Phase 3 also covers releases + tags (L10), cherry-pick + stash (L11), and rebase deeper (L12).