{"id":107940,"date":"2023-03-15T07:00:00","date_gmt":"2023-03-15T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107940"},"modified":"2023-03-15T09:26:30","modified_gmt":"2023-03-15T16:26:30","slug":"20230315-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230315-00\/?p=107940\/","title":{"rendered":"How can I create a git feature branch that can merge into multiple other branches?"},"content":{"rendered":"<p>A customer had a git repo that had two branches, let&#8217;s call them <code>dev_apple<\/code> and <code>dev_banana<\/code>. These branches were very similar, differing only in a choice of fruit. The customer wanted to create a new branch, call it <code>feature<\/code>, in which they could develop a feature that was not fruit-dependent. When finished, they could then create two pull requests, one to merge <code>feature<\/code> into <code>dev_apple<\/code> and another to merge <code>feature<\/code> into <code>dev_banana<\/code>. Is this possible?<\/p>\n<p>Yes, it&#8217;s possible, and we already explored how it works as a side effect of an earlier investigation into <a title=\"Stop cherry-picking, start merging, Part 3: Avoiding problems by creating a new merge base\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180314-00\/?p=98235\"> merging as a substitute for cherry-picking<\/a>.<\/p>\n<p>Suppose the repo looks like this:<\/p>\n<div id=\"p20230111_head\" style=\"display: none;\">\u00a0<\/div>\n<div id=\"p20230111_defs\" style=\"height: 0;\">\u00a0<\/div>\n<table style=\"margin-left: 1px; text-align: center;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">apple<br \/>\nred<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">A1<\/td>\n<td>&nbsp;<\/td>\n<td>dev_apple<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 80%;\">fruit<br \/>\nred<\/td>\n<td id=\"p20230111_swarr\">\u2199\ufe0e<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">M<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20230111_nwarr\">\u2196\ufe0e<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">B1<\/td>\n<td>&nbsp;<\/td>\n<td>dev_banana<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">banana<br \/>\nred<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>At some starting commit <code>M<\/code>, the code said &#8220;fruit red&#8221;. From the commit, the <code>dev_apple<\/code> branch commited a change to change the code to read &#8220;apple red&#8221;. Meanwhile, from the same starting commit, the <code>dev_banana<\/code> branch commit a change to change the code to &#8220;banana red&#8221;.<\/p>\n<p>Your goal is to create some branch <code>feature<\/code> that changes <code>red<\/code> to <code>blue<\/code>, and then merge that branch into both the <code>dev_apple<\/code> and <code>dev_banana<\/code> branches. The expected result of the merge is that <code>red<\/code> changes to <code>blue<\/code>, but the fruit in each branch remains unchanged. Merging into <code>dev_apple<\/code> produces &#8220;apple blue&#8221;, and merging into <code>dev_banana<\/code> produces &#8220;banana blue&#8221;.<\/p>\n<p>You already know how to do this: Create a patch branch that starts at the common ancestor of the two <code>dev<\/code> branches, which in our example is the initial commit <code>M<\/code>.<\/p>\n<table style=\"margin-left: 1px; text-align: center;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">apple<br \/>\nred<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">A1<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>dev_apple<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 80%;\">fruit<br \/>\nred<\/td>\n<td id=\"p20230111_swarr\">\u2199\ufe0e<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">fruit<br \/>\nblue<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">M<\/td>\n<td id=\"p20230111_larr3\" colspan=\"3\">\u2190 \u2190 \u2190<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">F<\/td>\n<td>&nbsp;<\/td>\n<td>feature<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20230111_nwarr\">\u2196\ufe0e<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">B1<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>dev_banana<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">banana<br \/>\nred<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In this scenario, the patch branch is what we&#8217;re calling the <code>feature<\/code> branch. In that branch, we can make a commit that makes the changes we want to apply to both of the <code>dev<\/code> branches, namely, changing the code to &#8220;fruit blue&#8221;.<\/p>\n<p>Once we&#8217;re happy with the work we&#8217;ve done in the <code>feature<\/code> branch (which could consists of several commits), we can create pull requests to merge the changes into both of the <code>dev<\/code> branches.<\/p>\n<table style=\"margin-left: 1px; text-align: center;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">apple<br \/>\nred<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">apple<br \/>\nblue<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">A1<\/td>\n<td id=\"p20230111_larr3\" colspan=\"3\">\u2190 \u2190 \u2190<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">A2<\/td>\n<td>&nbsp;<\/td>\n<td>dev_apple<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 80%;\">fruit<br \/>\nred<\/td>\n<td id=\"p20230111_swarr\">\u2199\ufe0e<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">fruit<br \/>\nblue<\/td>\n<td id=\"p20230111_swarr\">\u2199\ufe0e<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">M<\/td>\n<td id=\"p20230111_larr3\" colspan=\"3\">\u2190 \u2190 \u2190<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">F<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>feature<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20230111_nwarr\">\u2196\ufe0e<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20230111_nwarr\">\u2196\ufe0e<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">B1<\/td>\n<td id=\"p20230111_larr3\" colspan=\"3\">\u2190 \u2190 \u2190<\/td>\n<td style=\"border: solid 1px gray; width: 50px; font-size: 120%;\">B2<\/td>\n<td>&nbsp;<\/td>\n<td>dev_banana<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">banana<br \/>\nred<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"font-size: 80%;\">banana<br \/>\nblue<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The result of these merges is that the <code>dev_apple<\/code> branch says &#8220;apple blue&#8221; and the <code>dev_banana<\/code> branch says &#8220;banana blue&#8221;, as desired.<\/p>\n<p>Note that this trick assumes that the most recent common ancestor of the <code>dev_apple<\/code> and <code>dev_banana<\/code> branches is not too old, or at least not so old that the code you want to change isn&#8217;t even present. In our case, we&#8217;re in good shape because the common ancestor commit <code>M<\/code> does have the word &#8220;red&#8221; that we want to change to &#8220;blue&#8221;.<\/p>\n<p>The customer was satisfied with this recommendation. My guess is that the split into <code>dev_apple<\/code> and <code>dev_banana<\/code> was relatively recent and temporary, and the expectation was that the two <code>dev<\/code> branches would eventually merge back together once the fruit discrepancy was resolved.<\/p>\n<p>\n<script>\nwindow.addEventListener(\"load\", function() {\n  var fullFF = getComputedStyle(document.body).fontFamily;\n  var simpleFF = fullFF.replace(\/ Emoji\/g, \"\");\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20230111_head\").innerHTML =\n`<s` + `tyle>\nbody { font-family: ${simpleFF}; }\n.emoji { font-family: ${fullFF}; }\n.entry-content th { padding: 1px; } \/* stylesheet workaround *\/\n.entry-content td { padding: 1px; } \/* stylesheet workaround *\/\n<\/s` + `tyle>`;\n}); \/\/ wacky comment to prevent wordpress from injecting random junk\n(function() {\n  var svg = {\n    defs: `<svg width=\"0\" height=\"0\">\n <defs>\n  <marker id=\"arrowhead\" markerWidth=\"5\" markerHeight=\"5\" refX=\"-2\" refY=\"0\"\n    viewBox=\"-6 -6 12 12\" orient=\"auto\">\n    <polygon points=\"-2,0 -5,5 5,0 -5,-5\" fill=\"gray\" stroke=\"gray\"\n      stroke-dasharray=\"1 0\" \/>\n  <\/marker>\n  <path id=\"larr\" d=\"M20,10 L3,10\" stroke=\"gray\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"larr3\" d=\"M98,10 L3,10\" stroke=\"gray\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"nwarr\" d=\"M20,20 L3,3\" stroke=\"gray\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"swarr\" d=\"M20,2 L3,17\" stroke=\"gray\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"swarr3\" d=\"M98,2 L6,57\" stroke=\"gray\"\n   marker-end=\"url(#arrowhead)\" \/>\n <\/defs>\n<\/svg>`,\n    larr3: `<svg width=\"98\" height=\"20\"><use href=\"#larr3\"\/><\/svg>`,\n    nwarr: `<svg width=\"20\" height=\"20\"><use href=\"#nwarr\"\/><\/svg>`,\n    swarr: `<svg width=\"20\" height=\"20\"><use href=\"#swarr\"\/><\/svg>`\n  };\n  Object.keys(svg).forEach(function (key) {\n    Array.prototype.forEach.call(document.querySelectorAll(\"#p20230111_\" + key),\n      function (e) {\n        e.innerHTML = svg[key];\n      });\n  });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just work in your patch branch.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-107940","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Just work in your patch branch.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107940","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107940"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107940\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107940"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107940"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107940"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}