72 lines
No EOL
18 KiB
HTML
72 lines
No EOL
18 KiB
HTML
<!DOCTYPE html><html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type" /><meta content="width=device-width, initial-scale=1" name="viewport" /><!--replace-start-0--><!--replace-start-5--><!--replace-start-8--><title>Rebasing - My Zettelkasten</title><!--replace-end-8--><!--replace-end-5--><!--replace-end-0--><link href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.7/dist/semantic.min.css" rel="stylesheet" /><link href="https://fonts.googleapis.com/css?family=Merriweather|Libre+Franklin|Roboto+Mono&display=swap" rel="stylesheet" /><!--replace-start-1--><!--replace-start-4--><!--replace-start-7--><link href="https://raw.githubusercontent.com/srid/neuron/master/assets/neuron.svg" rel="icon" /><meta content="Rebasing is a way to integrate changes from one branch into another. In this regarding it is like merging a branch B into another branch A. However rebasing differs from normal merging in the way in which it modifies the Git history." name="description" /><meta content="Rebasing" property="og:title" /><meta content="My Zettelkasten" property="og:site_name" /><meta content="article" property="og:type" /><meta content="Git_rebasing" property="neuron:zettel-id" /><meta content="Git_rebasing" property="neuron:zettel-slug" /><meta content="git" property="neuron:zettel-tag" /><script type="application/ld+json">[]</script><style type="text/css">body{background-color:#eeeeee !important;font-family:"Libre Franklin", serif !important}body .ui.container{font-family:"Libre Franklin", serif !important}body h1, h2, h3, h4, h5, h6, .ui.header, .headerFont{font-family:"Merriweather", sans-serif !important}body code, pre, tt, .monoFont{font-family:"Roboto Mono","SFMono-Regular","Menlo","Monaco","Consolas","Liberation Mono","Courier New", monospace !important}body div.z-index p.info{color:#808080}body div.z-index ul{list-style-type:square;padding-left:1.5em}body div.z-index .uplinks{margin-left:0.29999em}body .zettel-content h1#title-h1{background-color:rgba(33,133,208,0.1)}body nav.bottomPane{background-color:rgba(33,133,208,2.0e-2)}body div#footnotes{border-top-color:#2185d0}body p{line-height:150%}body img{max-width:100%}body .deemphasized{font-size:0.94999em}body .deemphasized:hover{opacity:1}body .deemphasized:not(:hover){opacity:0.69999}body .deemphasized:not(:hover) a{color:#808080 !important}body div.container.universe{padding-top:1em}body div.zettel-view ul{padding-left:1.5em;list-style-type:square}body div.zettel-view .pandoc .highlight{background-color:#ffff00}body div.zettel-view .pandoc .ui.disabled.fitted.checkbox{margin-right:0.29999em;vertical-align:middle}body div.zettel-view .zettel-content .metadata{margin-top:1em}body div.zettel-view .zettel-content .metadata div.date{text-align:center;color:#808080}body div.zettel-view .zettel-content h1{padding-top:0.2em;padding-bottom:0.2em;text-align:center}body div.zettel-view .zettel-content h2{border-bottom:solid 1px #4682b4;margin-bottom:0.5em}body div.zettel-view .zettel-content h3{margin:0px 0px 0.4em 0px}body div.zettel-view .zettel-content h4{opacity:0.8}body div.zettel-view .zettel-content div#footnotes{margin-top:4em;border-top-style:groove;border-top-width:2px;font-size:0.9em}body div.zettel-view .zettel-content div#footnotes ol > li > p:only-of-type{display:inline;margin-right:0.5em}body div.zettel-view .zettel-content aside.footnote-inline{width:30%;padding-left:15px;margin-left:15px;float:right;background-color:#d3d3d3}body div.zettel-view .zettel-content .overflows{overflow:auto}body div.zettel-view .zettel-content code{margin:auto auto auto auto;font-size:100%}body div.zettel-view .zettel-content p code, li code, ol code{padding:0.2em 0.2em 0.2em 0.2em;background-color:#f5f2f0}body div.zettel-view .zettel-content pre{overflow:auto}body div.zettel-view .zettel-content dl dt{font-weight:bold}body div.zettel-view .zettel-content blockquote{background-color:#f9f9f9;border-left:solid 10px #cccccc;margin:1.5em 0px 1.5em 0px;padding:0.5em 10px 0.5em 10px}body div.zettel-view .zettel-content.raw{background-color:#dddddd}body .ui.label.zettel-tag{color:#000000}body .ui.label.zettel-tag a{color:#000000}body nav.bottomPane ul.backlinks > li{padding-bottom:0.4em;list-style-type:disc}body nav.bottomPane ul.context-list > li{list-style-type:lower-roman}body .footer-version img{-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%);-ms-filter:grayscale(100%);-o-filter:grayscale(100%);filter:grayscale(100%)}body .footer-version img:hover{-webkit-filter:grayscale(0%);-moz-filter:grayscale(0%);-ms-filter:grayscale(0%);-o-filter:grayscale(0%);filter:grayscale(0%)}body .footer-version, .footer-version a, .footer-version a:visited{color:#808080}body .footer-version a{font-weight:bold}body .footer-version{margin-top:1em !important;font-size:0.69999em}@media only screen and (max-width: 768px){body div#zettel-container{margin-left:0.4em !important;margin-right:0.4em !important}}body span.zettel-link-container span.zettel-link a{color:#2185d0;font-weight:bold;text-decoration:none}body span.zettel-link-container span.zettel-link a:hover{background-color:rgba(33,133,208,0.1)}body span.zettel-link-container span.extra{color:auto}body span.zettel-link-container.errors{border:solid 1px #ff0000}body span.zettel-link-container.errors span.zettel-link a:hover{text-decoration:none !important;cursor:not-allowed}body [data-tooltip]:after{font-size:0.69999em}body div.tag-tree div.node{font-weight:bold}body div.tag-tree div.node a.inactive{color:#555555}body .tree.flipped{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}body .tree{overflow:auto}body .tree ul.root{padding-top:0px;margin-top:0px}body .tree ul{position:relative;padding:1em 0px 0px 0px;white-space:nowrap;margin:0px auto 0px auto;text-align:center}body .tree ul::after{content:"";display:table;clear:both}body .tree ul:last-child{padding-bottom:0.1em}body .tree li{display:inline-block;vertical-align:top;text-align:center;list-style-type:none;position:relative;padding:1em 0.5em 0em 0.5em}body .tree li::before{content:"";position:absolute;top:0px;right:50%;border-top:solid 2px #cccccc;width:50%;height:1.19999em}body .tree li::after{content:"";position:absolute;top:0px;right:50%;border-top:solid 2px #cccccc;width:50%;height:1.19999em}body .tree li::after{right:auto;left:50%;border-left:solid 2px #cccccc}body .tree li:only-child{padding-top:0em}body .tree li:only-child::after{display:none}body .tree li:only-child::before{display:none}body .tree li:first-child::before{border-style:none;border-width:0px}body .tree li:first-child::after{border-radius:5px 0px 0px 0px}body .tree li:last-child::after{border-style:none;border-width:0px}body .tree li:last-child::before{border-right:solid 2px #cccccc;border-radius:0px 5px 0px 0px}body .tree ul ul::before{content:"";position:absolute;top:0px;left:50%;border-left:solid 2px #cccccc;width:0px;height:1.19999em}body .tree li div.forest-link{border:solid 2px #cccccc;padding:0.2em 0.29999em 0.2em 0.29999em;text-decoration:none;display:inline-block;border-radius:5px 5px 5px 5px;color:#333333;position:relative;top:2px}body .tree.flipped li div.forest-link{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}</style><script
|
||
async=""
|
||
id="MathJax-script"
|
||
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
|
||
></script>
|
||
<link
|
||
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/themes/prism.min.css"
|
||
rel="stylesheet"
|
||
/><link rel="preconnect" href="https://fonts.googleapis.com" /><link
|
||
rel="preconnect"
|
||
href="https://fonts.gstatic.com"
|
||
crossorigin
|
||
/><link
|
||
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Serif:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
|
||
rel="stylesheet"
|
||
/>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/components/prism-core.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||
<style>
|
||
body .ui.container,
|
||
body ul {
|
||
font-family: "IBM Plex Sans" !important;
|
||
}
|
||
body blockquote {
|
||
border-left-width: 3px !important;
|
||
font-style: italic;
|
||
}
|
||
.headerFont,
|
||
.ui.header,
|
||
body h1,
|
||
h2,
|
||
h3,
|
||
h4,
|
||
h5,
|
||
h6 {
|
||
font-family: "IBM Plex Sans Condensed" !important;
|
||
}
|
||
body p {
|
||
line-height: 1.4;
|
||
}
|
||
.monoFont,
|
||
body code,
|
||
pre,
|
||
tt {
|
||
font-family: "IBM Plex Mono" !important;
|
||
font-size: 12px !important;
|
||
line-height: 1.4 !important;
|
||
}
|
||
</style>
|
||
<!--replace-end-7--><!--replace-end-4--><!--replace-end-1--></head><body><div class="ui fluid container universe"><!--replace-start-2--><!--replace-start-3--><!--replace-start-6--><div class="ui text container" id="zettel-container" style="position: relative"><div class="zettel-view"><article class="ui raised attached segment zettel-content"><div class="pandoc"><h1 id="title-h1">Rebasing</h1><p>Rebasing is a way to integrate changes from one branch into another. In this regarding it is like merging a branch B into another branch A. However rebasing differs from normal merging in the way in which it modifies the Git history.</p><p>In a normal merge of branch B into branch A, Git creates a new commit that combines the changes of branches B and A. This is known as the merge commit and is evident from the following automatic commit message that is generated:</p><pre><code class="language-none">Merge branch B of github.com:thomasabishop/remote-repository into A</code></pre><p><img src="/static/normal-merge-again.svg" /></p><p>In this scenario the merge commit has two or more parent commits each representing the history of the merged branches. The resulting history of A will include the commits of B. Basically the two histories are combined.</p><p>This would give us a history that looks like the following, with different colours for the separate SHAs of each merged branch:</p><p><img src="/static/combined-merge-hist.svg" /></p><p>If we were to create a rebase branch of A from B, there would be a new singular history without distinguishing multiple parents that combines the commits of A and B. The rebased branch’s commits are recreated with new commit IDs and new timestamps, based on the current state of the branch that you are rebasing onto. This is obviously potentially destructive because it does not preserve the respective branch’s separate history. It rewrites history as a continuous stream of commits in a single branch.</p><p>When a rebase is applied, it will put the diverging B commits at the tip of A like so:</p><p><img src="/static/rebase-tip-chage.svg" /></p><p>And then rebrand the previous A commits to be continuous with B presenting a flat and linear Git history like the following:</p><p><img src="/static/single-git-history-rebase.svg" /></p><h2 id="benefits-use-cases">Benefits, use-cases</h2><blockquote><p>The purpose of rebasing is to ensure that the commit history of a project is as linear and simple as possible, by incorporating changes from one branch into another, as if the changes had been made on the other branch all along.</p></blockquote><p>A common use-case is with feature branches as it makes the features fit more seamlessly with the <code>main</code> or <code>develop</code> branch.</p><p>It is also a technique that can be used to integrate recent commits without merging.</p><p>When to use one over the other:</p><ul><li><strong>Merge</strong> to allow commits to stand out or to be clearly grouped</li><li><strong>Merge</strong> to bring large feature branches back into main</li><li><strong>Rebase</strong> to add minor commits in a main branch into a feature branch</li><li><strong>Rebase</strong> when you need to move commits from one branch to another</li></ul><p>So in terms of my personal workflow, I should be using</p><ul><li>Merge when I want to bring a feature into develop</li><li>Merge when I want to bring develop into main for a release</li><li>Merge any time the feature branch is already public and being used by others.</li><li>Rebase to capture small changes in the parent branch</li><li>Rebase when I have branched from a branch because a refactor or something has become more complex than originally anticipated.</li></ul><h2 id="syntax">Syntax</h2><p>For example if we are working on a feature branch off of <code>main</code>, we would run the following from this feature branch:</p><pre><code class="language-none">git rebase main</code></pre><p>This will move the feature branch to the tip of <code>main</code>.</p><p>If this completes successfully, we would then go on to merge the feature with main.</p><p>If conflicts occur, the rebase will halt. You fix the conflicts and then run:</p><pre><code class="language-none">git rebase --continue</code></pre><p>Or if you don’t want to resolve the conflict (not advised):</p><pre><code class="language-none">git rebase --skip</code></pre><p>Or stop the whole process:</p><pre><code class="language-none">git rebase --abort</code></pre><h3 id="isolate-the-point-at-which-one-branch-diverges-from-another">Isolate the point at which one branch diverges from another</h3><p>This can be useful to check before you create a rebase:</p><pre><code class="language-none">git merge-base main feature/some-feature
|
||
|
||
c33acc84f06fcb94e0e87d9adb240c038da6d71c</code></pre><h2 id="golden-rule-of-rebasing">Golden rule of rebasing</h2><p>When we rebase we remove the additional merge commit but we are changing history. The commits are still there but the SHAs are changed. For this reason <strong>you should not rebase a public branch</strong>, otherwise you will mess up your collaborators history. You should do your rebasing locally and then make a pull request.</p><h2 id="difference-from-cherry-picking">Difference from cherry-picking</h2><p>The main difference between the two approaches is that <span class="zettel-link-container errors"><span class="zettel-link" title="Wiki-link does not refer to any existing zettel"><a>Cherry_picking_a_branch</a></span></span> is a more selective process, where you can pick and choose specific commits that you want to include in another branch. This can be useful when you only want to apply specific changes or fixes from one branch to another, without including all the changes made in the original branch.</p><p>On the other hand, rebasing is a more comprehensive process that can include all the changes from one branch to another, but it modifies the commit history, making it more linear and easier to understand. Unlike rebasing, cherry-picking does not modify the commit history of either branch.</p><h2 id="squashing-commits">Squashing commits</h2><p>This is a handy feature of rebasing. It allows you to combine multiple commits into one. This is useful when you have been doing a lot of trial and error to resolve a bug and you have lots of small commits that are not that important in themselves.</p><p>We use the interactive rebase tool for this.</p><p>Checkout the branch where the commit you want to squash is located.</p><p>Then run:</p><pre><code class="language-none">git rebase -i HEAD~n</code></pre><p>Where <code>n</code> is the number of commits you want to squash starting from the most recent. This will open an interactive rebase window, listing the commits. You can then use the keywords to decide what you want to do with them. In our case this will be <code>s</code> for squash.</p><p><img src="/static/git-interactive-rebase.png" /></p><h3 id="example">Example</h3><p>I made a small fix commit because something went wrong during build. I do not want this commit to be in the history because it is so minor. Instead I want to incorporate these changes into the last public commit.</p><p>Trivial commit is <code>xy</code> Previous commit is <code>aa</code></p><pre><code class="language-none">git rebase -i HEAD~2</code></pre><p>This displays:</p><pre><code class="language-none">pick xy
|
||
pick aa</code></pre><p>Change this to:</p><pre><code class="language-none">pick xy
|
||
squash aa</code></pre><p>Now <code>xy == aa</code></p><h3 id="another-example">Another example</h3><p>Here we will rebase the interim commits into the last feature commit</p><pre><code class="sh language-sh">git rebase -i HEAD~10</code></pre><pre><code class="language-none">pick a691a7667 feature (shared-nav) add active app check
|
||
pick 74a07fdb1 interim: add logging
|
||
pick 9af4e2652 interim: more logging
|
||
pick 51b36f667 interim: use href not origin
|
||
pick 33f161198 interim : try catch handler
|
||
pick 41c144ddf interim: remove didLoadCheck
|
||
pick ebd1c9f24 interim: fix flash star
|
||
pick 77af452e7 interim: rm redundant active app check
|
||
pick 79a9b737a iterim: test ternary
|
||
pick a90d23223 interim: further tidying</code></pre><pre><code class="language-none">pick a691a7667 feature (shared-nav) add active app check
|
||
squash 74a07fdb1 interim: add logging
|
||
squash 9af4e2652 interim: more logging
|
||
squash 51b36f667 interim: use href not origin
|
||
squash 33f161198 interim : try catch handler
|
||
squash 41c144ddf interim: remove didLoadCheck
|
||
squash ebd1c9f24 interim: fix flash star
|
||
squash 77af452e7 interim: rm redundant active app check
|
||
squash 79a9b737a iterim: test ternary
|
||
squash a90d23223 interim: further tidying</code></pre><h2 id="git-pull-rebase"><code>git pull rebase</code></h2><p>We can use this command to combine a rebase with a pull. This way we silently update our local version of a branch with the remote, without adding a merge commit.</p><pre><code class="language-none">git pull --rebase</code></pre><p>Add <code>--rebase=preserve</code> to keep merges that have been done <em>locally</em>. It is generally a good idea to do this.</p></div></article><nav class="ui attached segment deemphasized bottomPane" id="neuron-tags-pane"><div><span class="ui basic label zettel-tag" title="Tag">git</span></div></nav><nav class="ui bottom attached icon compact inverted menu blue" id="neuron-nav-bar"><!--replace-start-9--><!--replace-end-9--><a class="right item" href="impulse.html" title="Open Impulse"><i class="wave square icon"></i></a></nav></div></div><!--replace-end-6--><!--replace-end-3--><!--replace-end-2--><div class="ui center aligned container footer-version"><div class="ui tiny image"><a href="https://neuron.zettel.page"><img alt="logo" src="https://raw.githubusercontent.com/srid/neuron/master/assets/neuron.svg" title="Generated by Neuron 1.9.35.3" /></a></div></div></div></body></html> |