Merging locally — as in Stay Off Main — completes the CLI loop, but nobody else saw the diff first. Hosts exist so a teammate (or future-you) can read the change, comment, and only then update main. This page is that review loop: push the feature you already know how to build, open a pull request, read the host diff, merge on the host, then pull main locally.
Snapshot basics live in Git Without the Panic. If main moved while you worked, update the feature before you open the PR — that replay is Git Rebase. Conflict recovery is still When Push Fails.
Before you start: a host you can push to
A pull request is a host feature, not a Git object. A local bare remote cannot open one. You need a GitHub (or GitLab) repository you can push to — an existing project, or a throwaway.
The GitHub CLI (gh) is optional but preferred here: same review loop without clicking through the website. Confirm it is installed and logged in:
gh --version
gh auth status
You should see a logged-in GitHub account. If gh is missing, skip to the UI path later — the mental model is the same.
Note: gh talks to GitHub. If origin is GitLab, use the merge-request UI in that section instead of inventing a fake PR on a bare clone.
Throwaway GitHub lab (fork-free: you push a branch to origin and open a PR into main). From a scratch folder:
mkdir -p git-pr-lab
cd git-pr-lab
git init
echo 'App v1' > README.md
git add README.md
git commit -m "Initial README"
git branch -M main
gh repo create git-pr-lab --public --source=. --remote=origin --push
Or clone a GitHub repo you already own and work inside that clone. Delete git-pr-lab (and the GitHub repo) when you finish.
Mental model: a request to merge A into B
A pull request is a request on the host to merge one branch into another — usually feature/login into main — plus a title, a discussion thread, and a diff the host computes for you. Git itself still only has commits and branch names. The PR is the review wrapper around “please take these commits.”
Nothing lands on main until someone merges the PR (you, a reviewer, or both). Closing the PR without merging leaves both branches as they were.
Note: Open the PR while you are on the feature branch. A PR that compares main to main is empty.
Hero use case: open the PR and read the diff
Create and publish a feature branch the same way as in Stay Off Main — git switch -c, commit, git push -u. This page starts after that push.
git switch -c feature/login
echo 'Login form placeholder' > login.txt
git add login.txt
git commit -m "Add login placeholder"
git push -u origin feature/login
Pushing still does not change main on the remote. Open a pull request from the current branch into the repo default (main):
gh pr create --title "Add login placeholder" --body "Small lab PR: one file, one commit."
https://github.com/OWNER/git-pr-lab/pull/1
--title and --body skip the interactive editor. --base main is implied when main is the default; set it explicitly if the repo default is something else.
Read the request and the file diff without leaving the terminal:
gh pr view
gh pr diff
gh pr view prints title, state (OPEN), base, and URL. gh pr diff is the same patch a reviewer sees on the host. Confirm the change is login.txt and that the base is main. Open the same PR in the browser when you want comments or the visual file list:
gh pr view --web
Note: If the feature drifted behind main, update it first (Git Rebase), push, then open or refresh the PR — reviewers should not have to reconstruct that catch-up for you.
Review checklist: commits, files, base
Before you merge — even on a solo lab — glance at three things:
- Base branch — the PR targets
main(or the branch you meant), not another feature. - Commits —
gh pr viewplus the commit list on the host; they should tell one story, not five “wip” snapshots you would rather squash. - Files —
gh pr diffmatches the title. No leftover debug files, credentials, or unrelated refactors.
You are not doing a full code-review course here. You are checking that the host is about to merge the change you think it is.
Merge on the host, then pull main
Three common merge styles (GitHub names; GitLab’s merge request offers the same idea):
| Style | What lands on main | When |
|---|---|---|
| Merge commit | Feature commits plus a merge commit | You want the full branch trail |
| Squash | One new commit on main | Noisy WIP commits; keep main linear |
| Rebase and merge | Each PR commit replayed, no merge commit | Linear history, keep individual commits |
From the feature branch (or pass the PR number):
gh pr merge --merge
Squash instead when the branch is messy:
gh pr merge --squash --delete-branch
--rebase is the third form. --delete-branch removes the remote feature name after a successful merge — same idea as deleting a remote branch in Stay Off Main.
Merging on the host does not update your local main. Switch home and pull:
git switch main
git pull
git log --oneline --decorate -n 5
You should see the merge commit, or the squash commit, on local main. Then delete the local feature label if you no longer need it:
git branch -d feature/login
Note: After squash or rebase-merge, -d may refuse — the original feature SHAs are not on main. Confirm the PR is merged on the host, then use -D only to drop that leftover local label. Do not merge the old feature branch into local main after a squash; you would duplicate the work. Pull the host result instead.
If the host reports conflicts, resolve them the same way as in When Push Fails — update the feature, push, and merge the PR again. You are not merging locally into main as the source of truth; the host merge is.
UI path if you do not have gh
Same request, different clicks. After git push -u origin feature/login, GitHub often prints a compare URL. Open:
https://github.com/OWNER/REPO/compare/main...feature/login
Create pull request → title and body → Create pull request. Review the Files changed tab. Merge using Create a merge commit, Squash and merge, or Rebase and merge, then git switch main && git pull locally as above.
On GitLab: Merge requests → New merge request. Source = feature/login, target = main. Submit, read the diffs, merge, then pull main the same way.
Note: Do not paste a PR into a bare git remote. If there is no GitHub or GitLab project, there is no pull request — merge locally as in Stay Off Main instead.
Quick reference card
| Goal | Command |
|---|---|
| Check GitHub CLI login | gh auth status |
| Open a PR from current branch | gh pr create --title "..." --body "..." |
| Show PR summary | gh pr view |
| Show PR patch | gh pr diff |
| Open PR in the browser | gh pr view --web |
| Merge (merge commit) | gh pr merge --merge |
| Merge (squash) | gh pr merge --squash |
| Merge (rebase) | gh pr merge --rebase |
| Delete remote branch on merge | add --delete-branch |
| Update local main after host merge | git switch main then git pull |
| GitHub compare URL | https://github.com/OWNER/REPO/compare/main...feature/name |
Practice drills
Inside git-pr-lab (or any GitHub clone you can push to; recreate the throwaway repo if needed):
- From
main, createfeature/docs, add a line toREADME.md, commit, push with upstream tracking, and open a PR withgh pr create. - Run
gh pr viewandgh pr diff. Confirm the base ismainand onlyREADME.mdchanged. - Say which merge style you would pick for five noisy “wip” commits versus two clean logical commits — and why.
- Merge the PR on the host (
gh pr merge --squashor--merge), switch tomain, andgit pull. Confirmgit logonmainshows the change. - Push a new branch
feature/ui-laband open the GitHub compare URL (or GitLab new merge request) withoutgh pr create. Create the request in the UI, then merge or close it and pullmainif you merged.
Solid answers — clear and portable:
git switch main
git switch -c feature/docs
echo 'Docs link' >> README.md
git add README.md && git commit -m "Add docs link"
git push -u origin feature/docs
gh pr create --title "Add docs link" --body "Lab PR for the review loop."
gh pr view
gh pr diff
# 3: squash the noisy WIP branch; merge-commit (or rebase-merge) the two clean commits
gh pr merge --squash --delete-branch
git switch main
git pull
git log --oneline --decorate -n 5
git switch -c feature/ui-lab
echo 'UI lab' > ui.txt
git add ui.txt && git commit -m "Add UI lab note"
git push -u origin feature/ui-lab
# open https://github.com/OWNER/REPO/compare/main...feature/ui-lab
If those five feel routine, you already practice the team habit: work on a named branch, publish it, ask the host to merge after a look at the diff, then pull main so your clone matches. Do not merge locally as a substitute for that review. Day-one snapshots remain in Git Without the Panic. Branch create, push -u, and local merge stay in Stay Off Main. When you need one commit on another branch without taking the whole feature, continue with Cherry-Pick.