Chapter 02
Git and GitHub for contributors
Working in a repository you do not own: forks, branches, keeping in sync with upstream, rebasing and readable commits.
Fork
- What
- Your own copy of someone else's repository on GitHub, where you can push branches without write access to the original.
- Why
- It is how outside contributors propose changes: push to your fork, then open a pull request into the original project.
gh repo fork owner/project --clone
cd project
git remote -vOrigin and upstream
- What
- Conventional remote names:
originpoints to your fork,upstreampoints to the original project you forked from. - Why
- You pull the latest changes from upstream and push your branches to origin. Mixing them up is a common source of confusion.
git remote add upstream \
https://github.com/owner/project.git
git fetch upstreamFeature branch
- What
- A short-lived branch created from the latest upstream main for one change, named after what it does.
- Why
- One branch per pull request keeps changes separate, so you can work on several at once and your fork's main stays clean.
git switch main
git pull upstream main
git switch -c fix/parse-empty-configWatch out
Committing directly to your fork's main branch, which makes later pull requests carry unrelated commits.
Keeping a fork in sync
Also called Sync fork
- What
- Bringing new commits from upstream into your fork and branches, by fetching upstream and rebasing or merging.
- Why
- Projects move fast. Branches based on old code conflict more and may fail CI against the current main.
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin mainRebase
Also called rebasing
- What
- Replaying your branch's commits on top of a newer base, such as the latest upstream main, which rewrites their history.
- Why
- It keeps a linear history and resolves conflicts in your branch before review. Many projects ask contributors to rebase rather than merge main in.
git fetch upstream
git rebase upstream/main
git status
git add path/to/resolved-file
git rebase --continueWatch out
Rebasing a branch other people have based work on, which rewrites history under them.
Merge conflict
- What
- When Git cannot combine changes automatically because two commits edited the same lines, and it marks the file for you to resolve by hand.
- Why
- Conflicts are normal in active projects. Resolving them carefully, then running tests, keeps your pull request mergeable.
Watch out
Accepting your own side of every conflict without reading what upstream changed.
Good commit message
Also called commit message
- What
- A short imperative subject line of about 50 characters, a blank line, then a body explaining what changed and why.
- Why
- Reviewers and future maintainers read history to understand decisions. Clear messages make review and
git loguseful.
Fix crash when config file is empty
Loading an empty YAML file returned None and
the validator assumed a dict. Treat None as an
empty config and add a regression test.
Fixes #482Watch out
Messages like "fix", "wip" or "changes" that tell nobody anything.
Conventional Commits
- What
- A commit message convention with a type prefix such as
feat:,fix:ordocs:, an optional scope, andBREAKING CHANGEfor incompatible changes. - Why
- Many projects use it to generate changelogs and decide version bumps automatically, so their CI may reject messages that do not follow it.
- Example
- feat(cli): add --dry-run flag, or fix(parser): handle empty config files
Squashing and force-pushing
Also called force-push, squash on merge, interactive rebase, squashing
- What
- Combining several commits into one, for example with interactive rebase, then updating your remote branch with a force push because history changed.
- Why
- Maintainers often want tidy commits.
--force-with-leaserefuses to overwrite the remote if it has commits you have not seen.
git rebase -i upstream/main
git push --force-with-lease origin fix/parse-empty-configWatch out
Using plain --force, which can silently delete a maintainer's commits pushed to your branch.
Everyday Git commands
Also called everyday commands
- What
- The commands used constantly while contributing:
status,diff,add -p,stash,log --onelineandrestore. - Why
- Checking what changed before each commit avoids pushing stray files, debug prints and unrelated formatting changes.
git status
git diff
git add -p
git stash push -m "wip"
git log --oneline -5