{"id":"l-git-3-3","courseId":"git-github","lang":"en","kind":"lesson","summary":"Open a pull request from a pushed branch, write a description reviewers can act on, review and update code through comments and new commits, and merge with the right method.","html":"<p>On your own, merging a branch is a command. On a team, it’s a conversation: someone else reads the change, asks questions, catches the bug you didn’t see, and only then does it land on <code dir=\"ltr\">main</code>. GitHub’s <strong>pull request</strong> is where that conversation happens. Even on a solo portfolio it’s worth using, because in a few lessons you’ll attach automated checks to it, and because employers look at how you work, not only at what you built.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">From branch to pull request</h2>\n<p>You’ve built a filter for the projects page on a branch and pushed it:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -c</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> projects-filter</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># …commits…</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> push</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -u</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> origin</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> projects-filter</span></span></code></pre></div>\n<p>The push output includes a link: <code dir=\"ltr\">Create a pull request for 'projects-filter' on GitHub by visiting: https://github.com/maya-okafor/portfolio/pull/new/projects-filter</code>. Open it, or click the “Compare &amp; pull request” banner on the repository page. Check the two branch selectors: <strong>base</strong> is where the work should go (<code dir=\"ltr\">main</code>), <strong>compare</strong> is your branch.</p>\n<p>With the GitHub CLI, <code dir=\"ltr\">gh pr create</code> asks for a title and body in the terminal, and <code dir=\"ltr\">gh pr create --fill</code> uses your commit messages.</p>\n<p>If the work isn’t ready but you want early feedback, open it as a <strong>draft pull request</strong>. It can’t be merged until you mark it ready, and it tells reviewers to look at direction, not detail.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Write a description people can act on</h2>\n<p>The title says what the change does: “Add tag filter to projects page”. The body answers three questions:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"markdown\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Markdown</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-light-font-weight:bold;--shiki-dark:#79C0FF;--shiki-dark-font-weight:bold\">## What</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">Adds tag buttons above the project grid; clicking one hides cards without that tag.</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-light-font-weight:bold;--shiki-dark:#79C0FF;--shiki-dark-font-weight:bold\">## Why</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">The grid has 14 projects now and visitors asked for a way to find the React ones.</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-light-font-weight:bold;--shiki-dark:#79C0FF;--shiki-dark-font-weight:bold\">## How to check</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">1.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> Open projects.html</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">2.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> Click \"React\": only 5 cards remain</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">3.</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> Click \"All\": all 14 return</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">Closes #12</span></span></code></pre></div>\n<p>Add a screenshot for anything visual; you can paste images straight into the box. The last line uses a closing keyword: when this pull request merges into the default branch, issue 12 closes automatically and the two link to each other. <code dir=\"ltr\">Fixes</code> and <code dir=\"ltr\">Resolves</code> work too.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">The review</h2>\n<p>A reviewer opens the <strong>Files changed</strong> tab, which shows the diff between your branch and its base. They can comment on any line, select several lines for a broader comment, or write a <strong>suggestion</strong>: a proposed replacement you can apply with one click as a commit. When done, they submit a review as <strong>Comment</strong>, <strong>Approve</strong> or <strong>Request changes</strong>.</p>\n<p>To respond, you don’t open anything new. Make the changes locally, commit, and push to the same branch:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> commit</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -am</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Rename filter class to project-filter\"</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> push</span></span></code></pre></div>\n<p>The pull request updates, and the reviewer can see only what changed since their last review. Reply to each comment, resolve conversations that are settled, and ask for another look.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Reviewing well</span></p>\n<p>When you review, start by running the change, not reading it. Comment on the code, never the person; ask questions (“what happens with zero projects?”) rather than issuing verdicts. Mark small preferences as optional, often prefixed “nit:”, so the author knows what blocks approval. Approve once it’s good, not once it’s how you would have written it.</p>\n</aside>\n<p>Keep pull requests small. Under about 400 changed lines, a reviewer can actually think about every line; a 2,000-line pull request gets skimmed and approved. If a feature is big, split it into a sequence of pull requests that each leave the site working.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Merging: three buttons, three histories</h2>\n<p>When approved, the merge button offers up to three methods, which repository settings can limit:</p>\n<ul>\n<li><strong>Create a merge commit</strong>: all your commits plus a merge commit, like <code dir=\"ltr\">git merge --no-ff</code>.</li>\n<li><strong>Squash and merge</strong>: your commits combined into one new commit on <code dir=\"ltr\">main</code>, titled after the pull request.</li>\n<li><strong>Rebase and merge</strong>: your commits replayed onto <code dir=\"ltr\">main</code> one by one, with no merge commit.</li>\n</ul>\n<p>Squash and merge is a popular default for small pull requests: <code dir=\"ltr\">main</code> gets one clean commit per change, and “fix typo” commits vanish. Merge commits suit larger work where the individual commits tell a useful story. Pick one per repository and stick to it.</p>\n<p>After merging, click <strong>Delete branch</strong> on GitHub, then tidy up locally:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">Terminal</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> main</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> pull</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> branch</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -D</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> projects-filter</span></span></code></pre></div>\n<p>Why <code dir=\"ltr\">-D</code> and not <code dir=\"ltr\">-d</code>? After a squash or rebase merge, your branch’s original commits aren’t ancestors of <code dir=\"ltr\">main</code> (GitHub made new ones), so <code dir=\"ltr\">-d</code> thinks the work is unmerged. Once GitHub shows the pull request as merged, <code dir=\"ltr\">-D</code> is safe.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Reusing a merged branch</span></p>\n<p>After a squash merge, continuing on the same branch for the next feature means your branch still carries the old, pre-squash commits. The next pull request shows them again and conflicts with their squashed twin on <code dir=\"ltr\">main</code>. Treat a merged branch as finished: delete it, update <code dir=\"ltr\">main</code>, and <code dir=\"ltr\">git switch -c</code> a fresh one.</p>\n</aside>\n<p>Checking out someone else’s pull request to test it is one command with the CLI: <code dir=\"ltr\">gh pr checkout 14</code>. Next, you’ll use the rest of GitHub’s collaboration tools, issues and projects to plan work, and forks to contribute to repositories you don’t own.</p>\n","toc":[{"id":"sec-1","text":"From branch to pull request","level":2},{"id":"sec-2","text":"Write a description people can act on","level":2},{"id":"sec-3","text":"The review","level":2},{"id":"sec-4","text":"Merging: three buttons, three histories","level":2}],"takeaways":["A pull request proposes merging one branch into another and is the place where discussion, review and automated checks happen.","Pushing more commits to the same branch updates the open pull request; you never need to open a new one.","A good description says what changed, why, and how to check it, and `Closes","Merge commit, squash and merge, and rebase and merge produce different history on <code dir=\"ltr\">main</code>; pick one convention per repository.","After a squash merge, start new work on a fresh branch from the updated <code dir=\"ltr\">main</code> instead of continuing on the old branch."],"further":[{"title":"Pull requests (GitHub Docs)","url":"https://docs.github.com/en/pull-requests/reference/pull-requests"},{"title":"Reviewing proposed changes in a pull request","url":"https://docs.github.com/en/pull-requests/how-tos/review-pull-requests/reviewing-proposed-changes-in-a-pull-request"},{"title":"Pull request merges (GitHub Docs)","url":"https://docs.github.com/en/pull-requests/reference/pull-request-merges"},{"title":"Linking a pull request to an issue","url":"https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue"}],"quiz":[{"q":"<p>A reviewer asks you to rename a CSS class in your open pull request. How do you update the pull request?</p>","options":[{"text":"Close it, make the change on a new branch, and open a new pull request.","why":"That throws away the review conversation for no reason. Pull requests are designed to be updated."},{"text":"Commit the change on the same branch and push; the pull request updates automatically.","why":"Correct. A pull request tracks its branch, so new commits appear in it and the reviewer can see exactly what changed since their review."},{"text":"Edit the file in the “Files changed” tab of the pull request.","why":"You can make small edits on GitHub, but it still commits to the branch; it’s not a separate mechanism, and local work is usually easier to test."},{"text":"Ask the reviewer to make the change themselves after merging.","why":"Merging known-unfinished work into <code dir=\"ltr\">main</code> defeats the purpose of review."}],"answer":1},{"q":"<p>Your pull request description ends with `Closes</p>","options":[{"text":"Issue 12 is closed automatically and linked to the pull request.","why":"Correct. Keywords like <code dir=\"ltr\">closes</code>, <code dir=\"ltr\">fixes</code> and <code dir=\"ltr\">resolves</code> followed by an issue number link them, and the merge closes the issue."},{"text":"Pull request number 12 is closed.","why":"The number refers to an issue (issues and pull requests share one numbering), and the keyword links rather than closes another pull request."},{"text":"Nothing; it’s only a comment for humans.","why":"GitHub parses these keywords in pull request descriptions and acts on them when merging into the default branch."}],"answer":0},{"q":"<p>Your team squash-merges pull requests. After yours merged, you kept committing on the same branch and opened a second pull request. It shows your old commits again and conflicts. Why?</p>","options":[{"text":"GitHub forgot that the first pull request was merged.","why":"GitHub remembers. The problem is in the commit graph, not in GitHub’s records."},{"text":"Squash merging deletes the branch on GitHub, so it’s corrupted.","why":"Deleting a branch after merge removes a pointer. Nothing is corrupted."},{"text":"Your branch needs <code dir=\"ltr\">git pull --force</code> to fix the history.","why":"There’s no such fix, and forcing doesn’t change what’s in <code dir=\"ltr\">main</code>."},{"text":"The squash created one new commit on <code dir=\"ltr\">main</code>, so your branch’s original commits still look unmerged to Git.","why":"Correct. The squash commit has the same changes but a different ID. Start each new piece of work on a fresh branch from the updated <code dir=\"ltr\">main</code>."}],"answer":3},{"q":"<p>Which pull request is likely to get the most useful review?</p>","options":[{"text":"One pull request with the whole redesign, 2,400 changed lines, titled “Updates”.","why":"Reviewers can’t hold that much in their heads, so they skim and approve. Size and a vague title both work against review."},{"text":"A pull request with no description, because the code speaks for itself.","why":"Code shows what changed, not why, or how to check it. Reviewers waste time reconstructing your intent."},{"text":"A 150-line pull request adding the projects filter, with a screenshot and steps to test it.","why":"Correct. Small, single-purpose, and explained, so the reviewer can actually check that it works."}],"answer":2}],"exercise":{"kind":"order","items":["branch","push","open","review","update","merge","cleanup"],"title":"Ship the projects filter through a pull request","prompt":"<p>Put the steps of the pull request workflow in order, from starting the projects filter to having it on <code dir=\"ltr\">main</code> with your local repository tidy.</p>\n","hints":["A pull request needs a branch that exists on GitHub.","Review feedback is answered by pushing to the same branch, before anything merges.","Local cleanup comes after GitHub has merged and deleted the branch."],"explanation":"<p>Work starts on a fresh branch from an up-to-date <code dir=\"ltr\">main</code>. Pushing it with <code dir=\"ltr\">-u</code> puts it on GitHub, where you open a pull request against <code dir=\"ltr\">main</code> with a clear description. Reviewers comment; you answer by committing and pushing to the same branch, which updates the pull request. Once approved, it’s merged (here, squashed) and the remote branch deleted. Finally you update your local <code dir=\"ltr\">main</code> and delete the local branch.</p>\n","checkLabels":{},"itemText":{"branch":"<code dir=\"ltr\">git switch main</code>, <code dir=\"ltr\">git pull</code>, then <code dir=\"ltr\">git switch -c projects-filter</code>.","push":"Commit the work and run <code dir=\"ltr\">git push -u origin projects-filter</code>.","open":"Open a pull request (base: <code dir=\"ltr\">main</code>) with what, why, how to check, and <code dir=\"ltr\">Closes #12</code>.","review":"A reviewer leaves line comments and requests changes.","update":"Commit the fixes on <code dir=\"ltr\">projects-filter</code> and <code dir=\"ltr\">git push</code>; the pull request updates.","merge":"After approval, click Squash and merge, then Delete branch.","cleanup":"Locally: <code dir=\"ltr\">git switch main</code>, <code dir=\"ltr\">git pull</code>, <code dir=\"ltr\">git branch -D projects-filter</code>."}},"words":761,"readMinutes":4}