Anatomy of a GitHub contribution
Git records the history and GitHub hosts it, adding forks, pull requests, and review on top. Every line below is either a plain git command working on your own machine or a gh command talking to GitHub over the network.
File extensions: .sh
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside a GitHub contribution
Repository
The project plus its entire history, stored in a hidden .git folder.
A repository ("repo") is one project's files together with every version of them there has ever been. The history lives in a hidden .git directory next to your files; delete that folder and you are left with an ordinary folder of files and no memory of how they got that way. A repo on GitHub is that same thing on a server, wrapped in a web page with issues, pull requests, releases, and permissions. GitHub is not a different kind of repository, it is a copy of yours that happens to have a URL, which is why every command below is either reading from or writing to one.
Fork
Your own server-side copy of someone else's repository.
Forking creates a full copy of a repository under your own account. You get write access to the copy without needing any permission on the original, which is the whole point: it is how open source accepts changes from strangers safely. The fork remembers where it came from, so GitHub can still offer to merge your work back. You only need a fork when you cannot push to the original. If you are on the team, skip it and branch directly in the shared repo. Note that a fork is a GitHub concept, not a git one: git itself has no idea your repo is a copy of anything.
Clone
Downloads a full local copy of a repository, history and all.
git clone <url> copies an entire repository onto your machine: every file, every branch, every commit ever made. This is not a checkout of the latest version, it is the whole database, which is why git can show you a five-year-old diff with no network connection. Cloning also wires up a remote named origin pointing back at the URL you cloned from, so later git push and git pull already know where to go. "Clone" is the local copy; "fork" is the server-side one. You usually make a fork and then clone the fork.
Remote (`origin`, `upstream`)
A nickname for a repository URL you exchange commits with.
A remote is just a saved URL with a short name. By convention origin is the copy you push to (your fork, or the shared repo if you have access) and upstream is the original project you forked from. Nothing in git enforces those names; they are a convention so strong that tools assume it. git remote -v lists them. Because a clone only sets up origin, working on a fork means adding upstream yourself with git remote add upstream <url>, which is what makes it possible to pull in the original project's new commits later.
Sync (`fetch`, `pull`)
Bring down commits other people made since you last looked.
git fetch downloads new commits from a remote and updates your record of where its branches are, without touching any file you are working on. git pull is fetch followed immediately by a merge into your current branch, so it changes your files. Fetch is the safe one to run at any time; pull is the one that can surprise you. On a fork this is the "your branch is 47 commits behind" problem. The fix is git fetch upstream then merging upstream/main into your main. GitHub calls the one-click version of this **Sync fork** in the web UI, and gh repo sync on the command line.
Merge conflict
Two people changed the same lines, so git stops and asks you.
Git merges by comparing changes rather than files, and it resolves the overwhelming majority of them without help. A conflict happens only when two branches changed the same lines of the same file, because there is no rule that says whose version wins. Git marks the spot with <<<<<<<, =======, and >>>>>>> and stops. Resolving one is manual and unglamorous: open the file, decide what the code should actually say, delete the markers, git add the file, and finish with git merge --continue. A conflict is not an error or a sign anyone did anything wrong. It is git refusing to guess.
Branch
A movable name for one line of work, so main stays shippable.
A branch is a lightweight, movable pointer to a commit. Creating one is instant and costs essentially nothing, because git is not copying files, it is writing down a name. git switch -c fix/readme-typo makes a new branch from where you are and moves you onto it. The convention is that main always works and every change happens on its own short-lived branch, which is then reviewed and merged. GitHub has defaulted new repositories to main rather than master since October 2020. git switch and git restore are the modern split of the old, overloaded git checkout.
Stage (`git add`)
Pick exactly which changes go into the next commit.
git add moves changes into the staging area (also called the index), a holding pen between your working files and the history. Nothing is committed until you stage it, which is what lets you turn one messy afternoon of edits into three clean, separately reviewable commits. This extra step is the part of git that most confuses newcomers and the part experienced users would fight hardest to keep. git status shows what is staged, unstaged, and untracked; git add -p walks you through a file hunk by hunk so you can stage half of it.
Commit
A permanent snapshot of the staged changes, plus a message.
A commit records the complete state of the project at one moment, who made it, when, which commit came before it, and why. That last part is the message, and it is the only piece git cannot generate for you. It gets a unique hash like a3f9c21, which is how every other command refers to it. Commits are the unit of history: they are what you revert, cherry-pick, bisect through, and blame. A good message explains the *why* in the first line and leaves the *what* to the diff, which is already right there. git commit -m "fix" is a message you are writing to yourself, at 2am, six months from now.
Push
Upload your commits to a remote so other people can see them.
Until you push, every commit you have made exists only on your laptop. git push -u origin <branch> sends the branch to the remote and, thanks to -u, remembers the pairing so plain git push works from then on. Pushing never destroys someone else's work, because git rejects a push that would drop commits you do not have. --force overrides that check and is how history gets deleted for everyone. --force-with-lease is the version that first confirms nobody else pushed while you were not looking, and is what you almost always actually want.
Pull request (merge request)
A formal ask: "please merge my branch into yours."
A pull request wraps a branch in a conversation. It shows the diff, runs the checks, collects review comments, and provides the button that merges it. The name comes from the original workflow of emailing a maintainer to ask them to *pull* from your repo; GitHub turned that email into a page. GitLab calls the identical concept a **merge request**, and Bitbucket calls it a pull request too. The difference is branding, not behavior. A pull request is not part of git: close every PR and your commits are untouched, because a PR is a proposal *about* branches that lives entirely on the host.
Checks (CI on the PR)
Automated builds and tests that run against your branch.
Every push to a pull request can kick off a CI pipeline that builds the project, runs the tests, and reports back as a green tick or a red cross on the PR itself. That report is the "check". See the CI pipeline page for what is actually inside one of those runs. Repository rules can make specific checks **required**, which disables the merge button until they pass. GitHub calls those rules **rulesets** now (the older per-branch version is still there as branch protection rules), and a **merge queue** can re-run them on the merged result so main never breaks from two PRs that were each green al
Review
A human reads the diff and approves, comments, or requests changes.
A review is a bundle of comments plus one of three verdicts: approve, comment, or request changes. Comments can be anchored to individual lines of the diff, and "request changes" blocks the merge until the reviewer clears it, so it is a genuine gate rather than an opinion. Review is the reason pull requests exist. It is also where "LGTM" (looks good to me) comes from, and where the well-known asymmetry lives: a one-line change gets nine comments about naming, while a two-thousand-line refactor gets approved in forty seconds.
Merge
Combine the branch into the target. Three strategies, one result.
A **merge commit** keeps every commit on the branch and adds one more that joins the two histories, preserving exactly what happened. **Squash** flattens the whole branch into a single new commit on the target, so main reads as one tidy change per pull request. **Rebase** replays each commit onto the tip of the target, giving a straight line with no merge commit at all. GitHub offers all three and starts you on the merge commit; plenty of projects switch to squash because it makes main readable and makes reverting a whole feature a one-command job. Whichever you pick, deleting the branch after
Official GitHub site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.