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 view plus the commit list on the host; they should tell one story, not five “wip” snapshots you would rather squash.
  • Files — gh pr diff matches 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):

StyleWhat lands on mainWhen
Merge commitFeature commits plus a merge commitYou want the full branch trail
SquashOne new commit on mainNoisy WIP commits; keep main linear
Rebase and mergeEach PR commit replayed, no merge commitLinear 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

GoalCommand
Check GitHub CLI logingh auth status
Open a PR from current branchgh pr create --title "..." --body "..."
Show PR summarygh pr view
Show PR patchgh pr diff
Open PR in the browsergh 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 mergeadd --delete-branch
Update local main after host mergegit switch main then git pull
GitHub compare URLhttps://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):

  1. From main, create feature/docs, add a line to README.md, commit, push with upstream tracking, and open a PR with gh pr create.
  2. Run gh pr view and gh pr diff. Confirm the base is main and only README.md changed.
  3. Say which merge style you would pick for five noisy “wip” commits versus two clean logical commits — and why.
  4. Merge the PR on the host (gh pr merge --squash or --merge), switch to main, and git pull. Confirm git log on main shows the change.
  5. Push a new branch feature/ui-lab and open the GitHub compare URL (or GitLab new merge request) without gh pr create. Create the request in the UI, then merge or close it and pull main if 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.

Next optional step Move one commit onto another branch without merging the whole feature. Cherry-Pick: Move One Commit Without Merging the Branch