[{"data":1,"prerenderedAt":464},["ShallowReactive",2],{"lesson-2026-03-26":3},{"id":4,"title":5,"body":6,"date":447,"description":448,"difficulty":449,"extension":450,"format":451,"meta":452,"navigation":149,"path":453,"progression":146,"seo":454,"stem":455,"subtopic":456,"tags":457,"tldr":461,"topic":44,"triggered":462,"__hash__":463},"lessons\u002Flessons\u002F2026-03-26.md","The Art of git rebase --onto",{"type":7,"value":8,"toc":439},"minimark",[9,22,27,87,102,106,127,186,194,198,201,237,240,244,247,295,302,306,317,328,332,335,424,435],[10,11,12,13,17,18,21],"p",{},"Standard ",[14,15,16],"code",{},"git rebase"," replays your branch commits on top of another branch. But ",[14,19,20],{},"git rebase --onto"," gives you a third argument — and with it, surgical control over exactly which commits go where.",[23,24,26],"h2",{"id":25},"the-three-argument-form","The Three-Argument Form",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-bash shiki shiki-themes github-light","git rebase --onto \u003Cnewbase> \u003Coldbase> \u003Cbranch>\n","bash","",[14,35,36],{"__ignoreMap":33},[37,38,41,45,49,53,57,60,64,67,69,72,74,76,78,81,84],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"s7eDp","git",[37,46,48],{"class":47},"sYBdl"," rebase",[37,50,52],{"class":51},"sYu0t"," --onto",[37,54,56],{"class":55},"sD7c4"," \u003C",[37,58,59],{"class":47},"newbas",[37,61,63],{"class":62},"sgsFI","e",[37,65,66],{"class":55},">",[37,68,56],{"class":55},[37,70,71],{"class":47},"oldbas",[37,73,63],{"class":62},[37,75,66],{"class":55},[37,77,56],{"class":55},[37,79,80],{"class":47},"branc",[37,82,83],{"class":62},"h",[37,85,86],{"class":55},">\n",[10,88,89,90,93,94,97,98,101],{},"Translation: take the commits between ",[14,91,92],{},"oldbase"," and ",[14,95,96],{},"branch",", and replay them onto ",[14,99,100],{},"newbase",".",[23,103,105],{"id":104},"scenario-1-moving-a-branch-to-a-different-parent","Scenario 1: Moving a Branch to a Different Parent",[10,107,108,109,112,113,116,117,119,120,122,123,126],{},"You branched ",[14,110,111],{},"feature-b"," off ",[14,114,115],{},"feature-a",", but now ",[14,118,115],{}," is abandoned and you want ",[14,121,111],{}," based on ",[14,124,125],{},"main",":",[28,128,130],{"className":30,"code":129,"language":32,"meta":33,"style":33},"# Before:\n# main -- A -- B (feature-a) -- C -- D (feature-b)\n\ngit rebase --onto main feature-a feature-b\n\n# After:\n# main -- C' -- D' (feature-b)\n",[14,131,132,138,144,151,169,174,180],{"__ignoreMap":33},[37,133,134],{"class":39,"line":40},[37,135,137],{"class":136},"sAwPA","# Before:\n",[37,139,141],{"class":39,"line":140},2,[37,142,143],{"class":136},"# main -- A -- B (feature-a) -- C -- D (feature-b)\n",[37,145,147],{"class":39,"line":146},3,[37,148,150],{"emptyLinePlaceholder":149},true,"\n",[37,152,154,156,158,160,163,166],{"class":39,"line":153},4,[37,155,44],{"class":43},[37,157,48],{"class":47},[37,159,52],{"class":51},[37,161,162],{"class":47}," main",[37,164,165],{"class":47}," feature-a",[37,167,168],{"class":47}," feature-b\n",[37,170,172],{"class":39,"line":171},5,[37,173,150],{"emptyLinePlaceholder":149},[37,175,177],{"class":39,"line":176},6,[37,178,179],{"class":136},"# After:\n",[37,181,183],{"class":39,"line":182},7,[37,184,185],{"class":136},"# main -- C' -- D' (feature-b)\n",[10,187,188,189,191,192,101],{},"Only commits C and D — the ones unique to ",[14,190,111],{}," — are replayed onto ",[14,193,125],{},[23,195,197],{"id":196},"scenario-2-removing-commits-from-the-middle","Scenario 2: Removing Commits from the Middle",[10,199,200],{},"You made commits A, B, C, D on a branch but B and C were a wrong turn:",[28,202,204],{"className":30,"code":203,"language":32,"meta":33,"style":33},"git rebase --onto A C feature-branch\n\n# Before: main -- A -- B -- C -- D (feature-branch)\n# After:  main -- A -- D' (feature-branch)\n",[14,205,206,223,227,232],{"__ignoreMap":33},[37,207,208,210,212,214,217,220],{"class":39,"line":40},[37,209,44],{"class":43},[37,211,48],{"class":47},[37,213,52],{"class":51},[37,215,216],{"class":47}," A",[37,218,219],{"class":47}," C",[37,221,222],{"class":47}," feature-branch\n",[37,224,225],{"class":39,"line":140},[37,226,150],{"emptyLinePlaceholder":149},[37,228,229],{"class":39,"line":146},[37,230,231],{"class":136},"# Before: main -- A -- B -- C -- D (feature-branch)\n",[37,233,234],{"class":39,"line":153},[37,235,236],{"class":136},"# After:  main -- A -- D' (feature-branch)\n",[10,238,239],{},"Commits B and C are cleanly removed. D is replayed directly onto A.",[23,241,243],{"id":242},"scenario-3-splitting-a-stacked-pr","Scenario 3: Splitting a Stacked PR",[10,245,246],{},"You have a branch with 6 commits but only the first 3 should be in PR #1:",[28,248,250],{"className":30,"code":249,"language":32,"meta":33,"style":33},"git checkout -b pr-2 feature-branch\ngit rebase --onto $(git rev-parse HEAD~3) feature-branch~3 pr-2\n",[14,251,252,267],{"__ignoreMap":33},[37,253,254,256,259,262,265],{"class":39,"line":40},[37,255,44],{"class":43},[37,257,258],{"class":47}," checkout",[37,260,261],{"class":51}," -b",[37,263,264],{"class":47}," pr-2",[37,266,222],{"class":47},[37,268,269,271,273,275,278,280,283,286,289,292],{"class":39,"line":140},[37,270,44],{"class":43},[37,272,48],{"class":47},[37,274,52],{"class":51},[37,276,277],{"class":62}," $(",[37,279,44],{"class":43},[37,281,282],{"class":47}," rev-parse",[37,284,285],{"class":47}," HEAD~3",[37,287,288],{"class":62},") ",[37,290,291],{"class":47},"feature-branch~3",[37,293,294],{"class":47}," pr-2\n",[10,296,297,298,301],{},"Now ",[14,299,300],{},"pr-2"," contains only the last 3 commits, based on the tip of what will be PR #1.",[23,303,305],{"id":304},"pro-tip","Pro Tip",[10,307,308,309,312,313,316],{},"Always use ",[14,310,311],{},"git log --oneline --graph"," before and after a ",[14,314,315],{},"rebase --onto"," operation. The three-argument form is powerful but easy to get wrong if you miscounted commits or picked the wrong base.",[10,318,319,320,323,324,327],{},"If something goes wrong: ",[14,321,322],{},"git reflog"," is your safety net. Every rebase records the pre-rebase HEAD, so you can always ",[14,325,326],{},"git reset --hard"," back to it.",[23,329,331],{"id":330},"example","Example",[10,333,334],{},"Real-world scenario — you started a feature branch off a release branch, but now need it on main:",[28,336,338],{"className":30,"code":337,"language":32,"meta":33,"style":33},"# See where your branch diverged\ngit log --oneline --graph --all\n\n# Count: release-2.1 is 12 commits ahead of main\n# Your feature has 4 commits on top of release-2.1\n\ngit rebase --onto main release-2.1 my-feature\n\n# Verify\ngit log --oneline main..my-feature\n# Should show exactly your 4 commits\n",[14,339,340,345,361,365,370,375,379,395,400,406,418],{"__ignoreMap":33},[37,341,342],{"class":39,"line":40},[37,343,344],{"class":136},"# See where your branch diverged\n",[37,346,347,349,352,355,358],{"class":39,"line":140},[37,348,44],{"class":43},[37,350,351],{"class":47}," log",[37,353,354],{"class":51}," --oneline",[37,356,357],{"class":51}," --graph",[37,359,360],{"class":51}," --all\n",[37,362,363],{"class":39,"line":146},[37,364,150],{"emptyLinePlaceholder":149},[37,366,367],{"class":39,"line":153},[37,368,369],{"class":136},"# Count: release-2.1 is 12 commits ahead of main\n",[37,371,372],{"class":39,"line":171},[37,373,374],{"class":136},"# Your feature has 4 commits on top of release-2.1\n",[37,376,377],{"class":39,"line":176},[37,378,150],{"emptyLinePlaceholder":149},[37,380,381,383,385,387,389,392],{"class":39,"line":182},[37,382,44],{"class":43},[37,384,48],{"class":47},[37,386,52],{"class":51},[37,388,162],{"class":47},[37,390,391],{"class":47}," release-2.1",[37,393,394],{"class":47}," my-feature\n",[37,396,398],{"class":39,"line":397},8,[37,399,150],{"emptyLinePlaceholder":149},[37,401,403],{"class":39,"line":402},9,[37,404,405],{"class":136},"# Verify\n",[37,407,409,411,413,415],{"class":39,"line":408},10,[37,410,44],{"class":43},[37,412,351],{"class":47},[37,414,354],{"class":51},[37,416,417],{"class":47}," main..my-feature\n",[37,419,421],{"class":39,"line":420},11,[37,422,423],{"class":136},"# Should show exactly your 4 commits\n",[10,425,426,427,429,430,93,432,434],{},"The key insight: the second argument (",[14,428,92],{},") defines the boundary. Everything between ",[14,431,92],{},[14,433,96],{}," is what moves.",[436,437,438],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":33,"searchDepth":140,"depth":140,"links":440},[441,442,443,444,445,446],{"id":25,"depth":140,"text":26},{"id":104,"depth":140,"text":105},{"id":196,"depth":140,"text":197},{"id":242,"depth":140,"text":243},{"id":304,"depth":140,"text":305},{"id":330,"depth":140,"text":331},"2026-03-26","Standard git rebase replays your branch commits on top of another branch. But git rebase --onto gives you a third argument — and with it, surgical control over exactly which commits go where.","advanced","md","walkthrough",{},"\u002Flessons\u002F2026-03-26",{"title":5,"description":448},"lessons\u002F2026-03-26","rebase-onto",[44,458,459,460],"rebase","branching","workflow","git rebase --onto lets you transplant a branch to any base — the surgical precision tool most developers never learn.",false,"cvDfWYL-1YFs3A5l9b0QlNx_4g1d3fvUULOnIMj4hKQ",1775249074037]