{"id":"l-git-2-4","courseId":"git-github","lang":"en","kind":"lesson","summary":"Rebase a feature branch onto main to keep history linear, handle conflicts mid-rebase, tidy commits interactively, and know when the golden rule says to merge instead.","html":"<p>In the last two lessons, combining branches meant merging, and a diverged history earned a merge commit. That’s honest and safe, but on a busy repository <code dir=\"ltr\">git log --graph</code> starts to look like a train map. Rebasing is the other way to combine work: instead of joining two lines, it moves your line so there’s only one.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">What rebase does</h2>\n<p>Your <code dir=\"ltr\">projects-grid</code> branch split from <code dir=\"ltr\">main</code> at <code dir=\"ltr\">b2</code>. Since then <code dir=\"ltr\">main</code> gained <code dir=\"ltr\">c3</code> and your branch has <code dir=\"ltr\">d4</code> and <code dir=\"ltr\">e5</code>. From the branch, run:</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:#0A3069;--shiki-dark:#A5D6FF\"> projects-grid</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> rebase</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> main</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Text</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>Successfully rebased and updated refs/heads/projects-grid.</code></pre></div>\n<p>Git found the commits on your branch that aren’t on <code dir=\"ltr\">main</code> (<code dir=\"ltr\">d4</code>, <code dir=\"ltr\">e5</code>), set them aside, moved your branch to <code dir=\"ltr\">main</code>’s tip, and replayed each change on top, one commit at a time.</p>\n<p>The replayed commits are <strong>new commits</strong>. Same changes and messages, different parents, so different IDs. That’s not a detail; it’s the whole story of when rebase is safe. A commit’s ID includes its parent, so you can’t move a commit, only make a copy somewhere else.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 280\" role=\"img\" aria-labelledby=\"l-git-2-4-t1\"><defs><marker id=\"arrow-l-git-2-4-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-git-2-4-t1\">Before: b2 has two children, c3 on main and d4 then e5 on projects-grid. After rebase: main still ends at c3; new commits d4-prime and e5-prime follow c3 in a straight line, and projects-grid points to e5-prime. The old d4 and e5 are greyed out and unreferenced.</title>\n  <text class=\"d-label-strong\" x=\"20\" y=\"28\">Before</text>\n  <circle class=\"d-box\" cx=\"50\" cy=\"100\" r=\"22\"/>\n  <text class=\"d-code\" x=\"50\" y=\"105\" text-anchor=\"middle\">b2</text>\n  <circle class=\"d-box\" cx=\"150\" cy=\"60\" r=\"22\"/>\n  <text class=\"d-code\" x=\"150\" y=\"65\" text-anchor=\"middle\">c3</text>\n  <circle class=\"d-box\" cx=\"150\" cy=\"140\" r=\"22\"/>\n  <text class=\"d-code\" x=\"150\" y=\"145\" text-anchor=\"middle\">d4</text>\n  <circle class=\"d-box\" cx=\"240\" cy=\"140\" r=\"22\"/>\n  <text class=\"d-code\" x=\"240\" y=\"145\" text-anchor=\"middle\">e5</text>\n  <path class=\"d-line\" d=\"M130 68 L70 92\"/>\n  <path class=\"d-line\" d=\"M130 132 L70 108\"/>\n  <path class=\"d-line\" d=\"M218 140 L172 140\"/>\n  <text class=\"d-code\" x=\"180\" y=\"55\">main</text>\n  <text class=\"d-code\" x=\"180\" y=\"185\">projects-grid</text>\n  <text class=\"d-label-strong\" x=\"350\" y=\"28\">After git rebase main</text>\n  <circle class=\"d-box\" cx=\"380\" cy=\"100\" r=\"22\"/>\n  <text class=\"d-code\" x=\"380\" y=\"105\" text-anchor=\"middle\">b2</text>\n  <circle class=\"d-box\" cx=\"470\" cy=\"100\" r=\"22\"/>\n  <text class=\"d-code\" x=\"470\" y=\"105\" text-anchor=\"middle\">c3</text>\n  <circle class=\"d-box-primary\" cx=\"560\" cy=\"100\" r=\"22\"/>\n  <text class=\"d-code\" x=\"560\" y=\"105\" text-anchor=\"middle\">d4'</text>\n  <circle class=\"d-box-primary\" cx=\"650\" cy=\"100\" r=\"22\"/>\n  <text class=\"d-code\" x=\"650\" y=\"105\" text-anchor=\"middle\">e5'</text>\n  <path class=\"d-line\" d=\"M448 100 L402 100\"/>\n  <path class=\"d-line\" d=\"M538 100 L492 100\"/>\n  <path class=\"d-line\" d=\"M628 100 L582 100\"/>\n  <text class=\"d-code\" x=\"450\" y=\"70\">main</text>\n  <text class=\"d-code\" x=\"600\" y=\"148\">projects-grid</text>\n  <circle class=\"d-box d-dashed\" cx=\"470\" cy=\"210\" r=\"22\"/>\n  <text class=\"d-label-muted\" x=\"470\" y=\"215\" text-anchor=\"middle\">d4</text>\n  <circle class=\"d-box d-dashed\" cx=\"560\" cy=\"210\" r=\"22\"/>\n  <text class=\"d-label-muted\" x=\"560\" y=\"215\" text-anchor=\"middle\">e5</text>\n  <path class=\"d-line d-dashed\" d=\"M448 202 L395 120\"/>\n  <path class=\"d-line d-dashed\" d=\"M538 210 L492 210\"/>\n  <text class=\"d-label-muted\" x=\"380\" y=\"262\">Old commits: no branch points to them now</text>\n</svg><figcaption>Rebase replays your commits on a new base</figcaption></figure>\n<p>Now <code dir=\"ltr\">main</code> is an ancestor of your branch, so bringing the work in is a fast-forward:</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\"> 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\"> merge</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> projects-grid</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">    # Fast-forward</span></span></code></pre></div>\n<p>History is a straight line, as if you’d started the grid after the typo fix.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Conflicts during a rebase</h2>\n<p>Because rebase replays commits one at a time, a conflict stops it at a specific commit. The routine is the one you learned for merges, with different words at the end:</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:#6E7781;--shiki-dark:#8B949E\"># Git stops: CONFLICT (content): Merge conflict in projects.html</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># edit projects.html, remove the markers, check it</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> add</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> projects.html</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> rebase</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --continue</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">      # finish this commit, replay the next</span></span></code></pre></div>\n<p><code dir=\"ltr\">git rebase --abort</code> returns the branch to exactly where it was before you started. <code dir=\"ltr\">git rebase --skip</code> drops the commit that’s conflicting, which is rarely what you want.</p>\n<p>One surprise: during a rebase, “ours” and “theirs” swap. You’re replaying your commits onto <code dir=\"ltr\">main</code>, so HEAD (the top half of a conflict) is <code dir=\"ltr\">main</code>’s side, and your commit is the bottom half. Read the labels, not your instincts.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Tidying with interactive rebase</h2>\n<p>Before you share a branch, you can rewrite its commits. <code dir=\"ltr\">git rebase -i</code> opens a to-do list in your editor:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"4\"><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\"> rebase</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -i</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> main</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">Text</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>pick 4b1e2c0 Add projects grid\npick 9a3d7f1 fix typo\npick c2e8b44 Grid gap on mobile</code></pre></div>\n<p>Change a word in front of a commit and save. <code dir=\"ltr\">reword</code> edits its message, <code dir=\"ltr\">squash</code> or <code dir=\"ltr\">fixup</code> folds it into the commit above (keeping or discarding its message), <code dir=\"ltr\">drop</code> deletes it, and reordering lines reorders commits. Changing <code dir=\"ltr\">pick 9a3d7f1</code> to <code dir=\"ltr\">fixup 9a3d7f1</code> turns three commits into two clean ones. This is how professionals keep “fix typo” commits out of a pull request.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">The golden rule</h2>\n<p>Rebasing replaces commits with copies. That’s harmless when you’re the only one who has them. It’s a mess when someone else has already built on the originals: their history still contains <code dir=\"ltr\">d4</code> and <code dir=\"ltr\">e5</code>, yours contains <code dir=\"ltr\">d4'</code> and <code dir=\"ltr\">e5'</code>, and the next pull produces duplicate commits and baffling conflicts.</p>\n<p>So: <strong>don’t rebase commits that exist outside your repository and that people may have based work on.</strong> In practice:</p>\n<ul>\n<li>Rebase freely on your own branches before you push or before anyone else touches them.</li>\n<li>Never rebase <code dir=\"ltr\">main</code> or any branch other people pull from.</li>\n<li>Rebasing your own pull request branch after pushing it is common and fine if nobody else commits to it. Git will reject the normal push because history was rewritten, so use:</li>\n</ul>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"6\"><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\"> push</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --force-with-lease</span></span></code></pre></div>\n<p><code dir=\"ltr\">--force-with-lease</code> overwrites the remote branch only if it still points where you last saw it. If a teammate pushed in the meantime, it refuses instead of erasing their work.</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>Reaching for git push --force</span></p>\n<p>Plain <code dir=\"ltr\">--force</code> overwrites the remote branch unconditionally. If a reviewer pushed a fix to your branch an hour ago, it’s gone, and nothing on your machine warns you. Make <code dir=\"ltr\">--force-with-lease</code> your only force-push, and never force-push to <code dir=\"ltr\">main</code>. In section 4 you’ll make GitHub refuse such pushes altogether.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">Merge or rebase?</h2>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"Scrollable table\" tabindex=\"0\"><table><thead>\n<tr>\n<th></th>\n<th>Merge</th>\n<th>Rebase</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>History</td>\n<td>True record, with merge commits</td>\n<td>Linear, as if work were sequential</td>\n</tr>\n<tr>\n<td>Commit IDs</td>\n<td>Unchanged</td>\n<td>Rewritten</td>\n</tr>\n<tr>\n<td>Safe on shared branches</td>\n<td>Yes</td>\n<td>No</td>\n</tr>\n<tr>\n<td>Conflicts</td>\n<td>Resolved once</td>\n<td>May recur per replayed commit</td>\n</tr>\n</tbody>\n</table></div><p>A sensible default: rebase your own feature branch onto <code dir=\"ltr\">main</code> to stay current and tidy it before review; merge (often through a pull request) to land it. Many teams also set <code dir=\"ltr\">git pull</code> to rebase your unpushed commits, which you’ll configure in the next section, when your portfolio finally gets a remote.</p>\n","toc":[{"id":"sec-1","text":"What rebase does","level":2},{"id":"sec-2","text":"Conflicts during a rebase","level":2},{"id":"sec-3","text":"Tidying with interactive rebase","level":2},{"id":"sec-4","text":"The golden rule","level":2},{"id":"sec-5","text":"Merge or rebase?","level":2}],"takeaways":["<code dir=\"ltr\">git rebase main</code> replays your branch’s commits on top of <code dir=\"ltr\">main</code>’s tip, creating new commits with new IDs.","After a rebase, merging the branch into <code dir=\"ltr\">main</code> is a fast-forward, so history stays a straight line.","During a rebase conflict, fix the file, <code dir=\"ltr\">git add</code> it, then <code dir=\"ltr\">git rebase --continue</code>; <code dir=\"ltr\">git rebase --abort</code> undoes the whole rebase.","The golden rule is to never rebase commits that other people may have already built on; rebase only your own unshared work.","If you must update a branch you already pushed, use <code dir=\"ltr\">git push --force-with-lease</code>, never a plain <code dir=\"ltr\">--force</code>."],"further":[{"title":"Rebasing (Pro Git)","url":"https://git-scm.com/book/en/v2/Git-Branching-Rebasing"},{"title":"git rebase reference","url":"https://git-scm.com/docs/git-rebase"},{"title":"About Git rebase (GitHub Docs)","url":"https://docs.github.com/en/get-started/using-git/about-git-rebase"}],"quiz":[{"q":"<p>Your branch <code dir=\"ltr\">projects-grid</code> has commits <code dir=\"ltr\">d4</code> and <code dir=\"ltr\">e5</code>. You run <code dir=\"ltr\">git rebase main</code> on it. What happens to <code dir=\"ltr\">d4</code> and <code dir=\"ltr\">e5</code>?</p>","options":[{"text":"They’re moved, keeping their IDs, to sit after <code dir=\"ltr\">main</code>’s tip.","why":"Commits can’t move, because a commit’s ID includes its parent. New parent means a new commit."},{"text":"They’re merged into one commit on <code dir=\"ltr\">main</code>.","why":"Rebase doesn’t squash by default and doesn’t touch <code dir=\"ltr\">main</code>. It rewrites the branch you’re on."},{"text":"Git creates new commits with the same changes on top of <code dir=\"ltr\">main</code>; the branch points to those, and the originals become unreferenced.","why":"Correct. The replayed commits (often written <code dir=\"ltr\">d4'</code> and <code dir=\"ltr\">e5'</code>) have new IDs. The originals are still in the reflog for a while."},{"text":"They’re deleted and you have to recommit the work.","why":"Rebase replays your changes automatically. Nothing needs to be redone by hand unless there’s a conflict."}],"answer":2},{"q":"<p>Mid-rebase, Git reports a conflict in <code dir=\"ltr\">projects.html</code>. You’ve edited the file into shape. What do you run next?</p>","options":[{"text":"<code dir=\"ltr\">git commit -m &quot;Fix conflict&quot;</code>","why":"During a rebase, Git makes the commits itself. Committing by hand adds an extra commit and confuses the replay."},{"text":"<code dir=\"ltr\">git add projects.html</code>, then <code dir=\"ltr\">git rebase --continue</code>","why":"Correct. Staging marks the conflict resolved; <code dir=\"ltr\">--continue</code> finishes that commit and replays the rest."},{"text":"<code dir=\"ltr\">git merge --continue</code>","why":"You’re in a rebase, not a merge. Each operation has its own continue command."},{"text":"<code dir=\"ltr\">git rebase main</code> again from the start","why":"A rebase is already in progress, so Git refuses to start another. Continue or abort the current one."}],"answer":1},{"q":"<p>Which situation breaks the golden rule of rebasing?</p>","options":[{"text":"Rebasing your local, never-pushed <code dir=\"ltr\">footer</code> branch onto <code dir=\"ltr\">main</code>.","why":"Nobody else has these commits, so rewriting them affects only you. This is rebase’s ideal use."},{"text":"Using <code dir=\"ltr\">git rebase -i HEAD~3</code> to squash typo fixes before opening a pull request.","why":"Tidying your own unshared commits is exactly what interactive rebase is for."},{"text":"Running <code dir=\"ltr\">git pull --rebase</code> to put your unpushed commits after your teammates’ new ones.","why":"That rewrites only your local, unpushed commits, so it’s safe and common."},{"text":"Rebasing the shared <code dir=\"ltr\">main</code> branch and force-pushing it while teammates have work built on it.","why":"Correct. Their commits sit on top of the old IDs you just replaced, so their next pull produces duplicates and confusing conflicts."}],"answer":3},{"q":"<p>You rebased your own pull request branch, and <code dir=\"ltr\">git push</code> is now rejected as non-fast-forward. What’s the safe way to update it?</p>","options":[{"text":"<code dir=\"ltr\">git push --force-with-lease</code>","why":"Correct. It overwrites the remote branch only if it’s still where you last saw it, so you won’t silently wipe out a commit someone else pushed since your last fetch."},{"text":"<code dir=\"ltr\">git push --force</code>","why":"That overwrites the remote no matter what, including commits a reviewer pushed since your last fetch."},{"text":"<code dir=\"ltr\">git pull</code> and then push.","why":"Pulling merges the old commits back in next to their rebased copies, leaving duplicates in the branch."}],"answer":0}],"exercise":{"kind":"fill","language":"bash","template":"git switch projects-grid\ngit {{0}} main                  # replay my commits on top of main\n# CONFLICT in projects.html: edit it, then\ngit add projects.html\ngit rebase {{1}}               # replay the remaining commits\n\n# this branch was already pushed for review, so update it safely\ngit push {{2}}","blanks":[{"answers":["rebase"]},{"answers":["--continue"]},{"answers":["--force-with-lease"]}],"title":"Rebase the projects grid","prompt":"<p>Your <code dir=\"ltr\">projects-grid</code> branch is behind <code dir=\"ltr\">main</code>, and you want a linear history. Fill in the blanks to rebase it, get through one conflict, and update the branch you already pushed for review without risking anyone else’s commits.</p>\n","hints":["The command you need has the same name as the operation.","After <code dir=\"ltr\">git add</code>, a rebase in progress needs one more word to keep going.","There’s a force-push option that checks the remote hasn’t changed since you last fetched. It’s long; it includes the word lease."],"explanation":"<p><code dir=\"ltr\">git rebase main</code> replays the branch’s commits on top of <code dir=\"ltr\">main</code>’s tip. When a replayed commit conflicts, you fix the file, <code dir=\"ltr\">git add</code> it and run <code dir=\"ltr\">git rebase --continue</code> (or <code dir=\"ltr\">--abort</code> to give up). The rebased commits have new IDs, so a normal push is rejected; <code dir=\"ltr\">git push --force-with-lease</code> replaces the remote branch only if nobody pushed to it since you last looked. This is fine on your own review branch, and never on <code dir=\"ltr\">main</code>.</p>\n","checkLabels":{}},"words":704,"readMinutes":3}