CINXE.COM
Merging two GitHub repositories without losing commit history - Mozilla Hacks - the Web developer blog
<!doctype html> <html lang="en-US"> <head data-template-path="https://hacks.mozilla.org/wp-content/themes/Hax"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="google-site-verification" content="w2ocEMd5yV9IsGCjhq-7ls67r4VH-Ob6oWdiZpqjN8U"> <meta name="title" content="Merging two GitHub repositories without losing commit history – Mozilla Hacks - the Web developer blog"> <meta property="og:site_name" content="Mozilla Hacks – the Web developer blog"> <meta property="og:url" content="https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history"> <meta property="og:title" content="Merging two GitHub repositories without losing commit history – Mozilla Hacks - the Web developer blog"> <meta property="og:description" content="How do you merge two Git repositories without losing history? This post will take you through the step by step process."> <meta property="og:image" content="https://hacks.mozilla.org/wp-content/uploads/2022/02/moz_blog_header_MDN-Intro-e1646143402836.png"> <meta property="og:image:width" content="1920"> <meta property="og:image:height" content="1080"> <meta property="twitter:title" content="Merging two GitHub repositories without losing commit history – Mozilla Hacks - the Web developer blog"> <meta property="twitter:description" content="How do you merge two Git repositories without losing history? This post will take you through the step by step process."> <meta name="twitter:card" content="summary_large_image"> <meta property="twitter:image" content="https://hacks.mozilla.org/wp-content/uploads/2022/02/moz_blog_header_MDN-Intro-e1646143402836.png"> <meta name="twitter:site" content="@mozhacks"> <link href='//fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic' rel='stylesheet' type='text/css'> <link rel="stylesheet" href="https://hacks.mozilla.org/wp-content/themes/Hax/css/font-awesome.min.css"> <link rel="stylesheet" href="https://hacks.mozilla.org/wp-content/themes/Hax/style.css"> <link rel="stylesheet" href="//cdn.jsdelivr.net/highlight.js/8.6.0/styles/solarized_light.min.css"> <script type="text/javascript"> window.hacks = {}; // http://cfsimplicity.com/61/removing-analytics-clutter-from-campaign-urls var removeUtms = function(){ var l = window.location; if( l.hash.indexOf( "utm" ) != -1 ){ var anchor = l.hash.match(/#(?!utm)[^&]+/); anchor = anchor? anchor[0]: ''; if(!anchor && window.history.replaceState){ history.replaceState({},'', l.pathname + l.search); } else { l.hash = anchor; } }; }; var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-35433268-8'], ['_setAllowAnchor', true]); _gaq.push (['_gat._anonymizeIp']); _gaq.push(['_trackPageview']); _gaq.push( removeUtms ); (function(d, k) { var ga = d.createElement(k); ga.type = 'text/javascript'; ga.async = true; ga.src = 'https://ssl.google-analytics.com/ga.js'; var s = d.getElementsByTagName(k)[0]; s.parentNode.insertBefore(ga, s); })(document, 'script'); </script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-5WVW12ST9K"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-5WVW12ST9K'); </script> <meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' /> <!-- This site is optimized with the Yoast SEO plugin v22.6 - https://yoast.com/wordpress/plugins/seo/ --> <title>Merging two GitHub repositories without losing commit history - Mozilla Hacks - the Web developer blog</title> <meta name="description" content="How do you merge two Git repositories without losing history? This post will take you through the step by step process." /> <link rel="canonical" href="https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/" /> <meta name="twitter:label1" content="Written by" /> <meta name="twitter:data1" content="Schalk Neethling" /> <meta name="twitter:label2" content="Est. reading time" /> <meta name="twitter:data2" content="15 minutes" /> <script type="application/ld+json" class="yoast-schema-graph">{"@context":"https://schema.org","@graph":[{"@type":"WebPage","@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/","url":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/","name":"Merging two GitHub repositories without losing commit history - Mozilla Hacks - the Web developer blog","isPartOf":{"@id":"https://hacks.mozilla.org/#website"},"primaryImageOfPage":{"@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#primaryimage"},"image":{"@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#primaryimage"},"thumbnailUrl":"https://hacks.mozilla.org/wp-content/uploads/2022/02/moz_blog_header_MDN-Intro-e1646143402836.png","datePublished":"2022-08-29T07:54:58+00:00","dateModified":"2022-08-29T07:54:58+00:00","author":{"@id":"https://hacks.mozilla.org/#/schema/person/2188b4b0a08fb7ba63b834d189b60b36"},"description":"How do you merge two Git repositories without losing history? This post will take you through the step by step process.","breadcrumb":{"@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#primaryimage","url":"https://hacks.mozilla.org/wp-content/uploads/2022/02/moz_blog_header_MDN-Intro-e1646143402836.png","contentUrl":"https://hacks.mozilla.org/wp-content/uploads/2022/02/moz_blog_header_MDN-Intro-e1646143402836.png","width":1920,"height":1080},{"@type":"BreadcrumbList","@id":"https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://hacks.mozilla.org/"},{"@type":"ListItem","position":2,"name":"Articles","item":"https://hacks.mozilla.org/articles/"},{"@type":"ListItem","position":3,"name":"Merging two GitHub repositories without losing commit history"}]},{"@type":"WebSite","@id":"https://hacks.mozilla.org/#website","url":"https://hacks.mozilla.org/","name":"Mozilla Hacks - the Web developer blog","description":"hacks.mozilla.org","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://hacks.mozilla.org/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https://hacks.mozilla.org/#/schema/person/2188b4b0a08fb7ba63b834d189b60b36","name":"Schalk Neethling","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https://hacks.mozilla.org/#/schema/person/image/15105800a0270a384212262298083881","url":"https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=96","contentUrl":"https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=96","caption":"Schalk Neethling"},"description":"I am a Mozillian, an evangelist, writer and developer with a passion for open source, web standards and accessibility. I have been so involved with these worlds that I feel they have become a part of me and cannot foresee a future where these topics will not be a part of my daily life.","sameAs":["http://schalkneethling.com","https://x.com/schalkneethling"],"url":"https://hacks.mozilla.org/author/sneethlingmozilla-com/"}]}</script> <!-- / Yoast SEO plugin. --> <link rel="alternate" type="application/rss+xml" title="Mozilla Hacks - the Web developer blog » Feed" href="https://hacks.mozilla.org/feed/" /> <link rel="alternate" type="application/rss+xml" title="Mozilla Hacks - the Web developer blog » Comments Feed" href="https://hacks.mozilla.org/comments/feed/" /> <link rel="alternate" type="application/rss+xml" title="Mozilla Hacks - the Web developer blog » Merging two GitHub repositories without losing commit history Comments Feed" href="https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/feed/" /> <link rel='stylesheet' id='wp-block-library-css' href='https://hacks.mozilla.org/wp-includes/css/dist/block-library/style.min.css?ver=6.6.1' type='text/css' media='all' /> <style id='co-authors-plus-coauthors-style-inline-css' type='text/css'> .wp-block-co-authors-plus-coauthors.is-layout-flow [class*=wp-block-co-authors-plus]{display:inline} </style> <style id='co-authors-plus-avatar-style-inline-css' type='text/css'> .wp-block-co-authors-plus-avatar :where(img){height:auto;max-width:100%;vertical-align:bottom}.wp-block-co-authors-plus-coauthors.is-layout-flow .wp-block-co-authors-plus-avatar :where(img){vertical-align:middle}.wp-block-co-authors-plus-avatar:is(.alignleft,.alignright){display:table}.wp-block-co-authors-plus-avatar.aligncenter{display:table;margin-inline:auto} </style> <style id='co-authors-plus-image-style-inline-css' type='text/css'> .wp-block-co-authors-plus-image{margin-bottom:0}.wp-block-co-authors-plus-image :where(img){height:auto;max-width:100%;vertical-align:bottom}.wp-block-co-authors-plus-coauthors.is-layout-flow .wp-block-co-authors-plus-image :where(img){vertical-align:middle}.wp-block-co-authors-plus-image:is(.alignfull,.alignwide) :where(img){width:100%}.wp-block-co-authors-plus-image:is(.alignleft,.alignright){display:table}.wp-block-co-authors-plus-image.aligncenter{display:table;margin-inline:auto} </style> <link rel='stylesheet' id='prismatic-blocks-css' href='https://hacks.mozilla.org/wp-content/plugins/prismatic/css/styles-blocks.css?ver=6.6.1' type='text/css' media='all' /> <style id='safe-svg-svg-icon-style-inline-css' type='text/css'> .safe-svg-cover{text-align:center}.safe-svg-cover .safe-svg-inside{display:inline-block;max-width:100%}.safe-svg-cover svg{height:100%;max-height:100%;max-width:100%;width:100%} </style> <style id='classic-theme-styles-inline-css' type='text/css'> /*! This file is auto-generated */ .wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none} </style> <style id='global-styles-inline-css' type='text/css'> :root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;} :where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;} :where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;} :root :where(.wp-block-pullquote){font-size: 1.5em;line-height: 1.6;} </style> <script type="text/javascript" src="https://hacks.mozilla.org/wp-includes/js/jquery/jquery.min.js?ver=3.7.1" id="jquery-core-js"></script> <script type="text/javascript" src="https://hacks.mozilla.org/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1" id="jquery-migrate-js"></script> <script type="text/javascript" src="https://hacks.mozilla.org/wp-content/themes/Hax/js/analytics.js?ver=6.6.1" id="analytics-js"></script> <link rel="https://api.w.org/" href="https://hacks.mozilla.org/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://hacks.mozilla.org/wp-json/wp/v2/posts/47913" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://hacks.mozilla.org/xmlrpc.php?rsd" /> <link rel='shortlink' href='https://hacks.mozilla.org/?p=47913' /> <link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://hacks.mozilla.org/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fhacks.mozilla.org%2F2022%2F08%2Fmerging-two-github-repositories-without-losing-commit-history%2F" /> <link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://hacks.mozilla.org/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fhacks.mozilla.org%2F2022%2F08%2Fmerging-two-github-repositories-without-losing-commit-history%2F&format=xml" /> </head> <body> <div class="outer-wrapper"> <header class="section section--fullwidth header"> <div class="masthead row"> <div class="branding block block--3"> <h1> <a href="https://hacks.mozilla.org"> <img class="branding__logo" src="https://hacks.mozilla.org/wp-content/themes/Hax/img/mdn-logo-mono.svg"> <img class="branding__wordmark" src="https://hacks.mozilla.org/wp-content/themes/Hax/img/wordmark.svg" alt="Mozilla"> <span class="branding__title">Hac<span class="logo-askew">k</span>s</span> </a> </h1> </div> <div class="search block block--2"> <form class="search__form" method="get" action="https://hacks.mozilla.org/"> <input type="search" name="s" class="search__input" placeholder="Search Mozilla Hacks" value=""> <i class="fa fa-search search__badge"></i> </form> </div> <nav class="social"> <a class="social__link youtube" href="http://www.youtube.com/user/mozhacks" title="YouTube"><i class="fa fa-youtube" aria-hidden="true"></i><span>Hacks on YouTube</span></a> <a class="social__link twitter" href="https://twitter.com/mozhacks" title="Twitter"><i class="fa fa-twitter" aria-hidden="true"></i><span>@mozhacks on Twitter</span></a> <a class="social__link rss" href="https://hacks.mozilla.org/feed/" title="RSS Feed"><i class="fa fa-rss" aria-hidden="true"></i><span>Hacks RSS Feed</span></a> <a class="fx-button" href="https://www.mozilla.org/firefox/download/thanks/?utm_source=hacks.mozilla.org&utm_medium=referral&utm_campaign=header-download-button&utm_content=header-download-button">Download Firefox</a> </nav> </div> </header> <div id="content-head" class="section"> <h1 class="post__title">Merging two GitHub repositories without losing commit history</h1> <div class="byline"> <h3 class="post__author"> <img alt='Avatar photo' src='https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=64' srcset='https://secure.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?s=128 2x' class='avatar avatar-64 photo' height='64' width='64' decoding='async'/> By <a class="url" href="http://schalkneethling.com" rel="external me">Schalk Neethling</a> </h2> <div class="post__meta"> Posted on <abbr class="published" title="2022-08-29T00:54:58-07:00"> August 29, 2022 </abbr> <span class="entry-cat">in <a href="https://hacks.mozilla.org/category/featured/" rel="category tag" title="View all posts in Featured Article" >Featured Article</a>, <a href="https://hacks.mozilla.org/category/git-github/" rel="category tag" title="View all posts in Git & GitHub" >Git & GitHub</a>, and <a href="https://hacks.mozilla.org/category/mdn/" rel="category tag" title="View all posts in MDN" >MDN</a> </span> <div class="socialshare" data-type="bubbles"></div> </div> </div> </div> <main id="content-main" class="section article"> <article class="post" role="article"> <article id="81bbaff4-5f9f-4d40-891c-c7849a2fa6ec" class="page sans"> <header> <h1 class="page-title">Merging two GitHub repositories without losing history</h1> </header> <div class="page-body"> <p id="d76979e8-387a-41c4-979e-c5986dd3b0c0" class="">We are in the process of merging smaller example code repositories into larger parent repositories on the MDN Web Docs project. While we thought that copying the files from one repository into the new one would lose commit history, we felt that this might be an OK strategy. After all, we are not deleting the old repository but archiving it.</p> <p id="5731f3f5-0a4f-40e0-bbb9-bbf63d98b0fa" class="">After having moved a few of these, we did <a href="https://github.com/mdn/dom-examples/issues/134">receive an issue from a community member</a> stating that it is not ideal to lose history while moving these repositories and that there <a href="https://github.com/mdn/dom-examples/issues/134">could be a relatively simple way</a> to avoid this. I experimented with a couple of different options and finally settled on a strategy based on the one <a href="https://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/">shared by Eric Lee on his blog</a>.</p> <blockquote id="f5391a9d-5e78-4aaf-bde4-84fae94a16e4" class=""><p><strong>tl;dr</strong> The approach is to use basic git commands to apply all of the histories of our old repo onto a new repo without needing special tooling.</p></blockquote> <nav id="a244ef85-138a-4d8e-a059-0a4dd12d2a87" class="block-color-gray table_of_contents"> <div class="table_of_contents-item table_of_contents-indent-0"><a class="table_of_contents-link" href="#0abdb9ef-9200-447c-9348-b5d8bac5b185">Getting started</a></div> <div class="table_of_contents-item table_of_contents-indent-0"><a class="table_of_contents-link" href="#367b4f61-defe-46ee-a0ea-e25bcafc59fa">How to exclude subdirectories when using <code>mv</code></a></div> <div class="table_of_contents-item table_of_contents-indent-0"><a class="table_of_contents-link" href="#dbcc4e95-edfa-4f98-a2e0-c4691f4fd050">Handling hidden files and creating a pull request</a></div> <div class="table_of_contents-item table_of_contents-indent-0"><a class="table_of_contents-link" href="#0272b87e-05fc-4ddb-96fa-7867df545657">Merging our repositories</a></div> <div class="table_of_contents-item table_of_contents-indent-1"><a class="table_of_contents-link" href="#c7bd35e7-333b-4e4e-bdff-7f145a5c2637">In Conclusion</a></div> </nav> <h2 id="0abdb9ef-9200-447c-9348-b5d8bac5b185" class="">Getting started</h2> <p id="94c91a76-2437-4bbc-b70b-6f1463af29a7" class="">For the experiment, I used the <a href="https://github.com/mdn/sw-test"><code>sw-test</code></a> repository that is meant to be merged into the <a href="https://github.com/mdn/dom-examples"><code>dom-examples</code></a> repository.</p> <p id="e026f2d9-ab20-42e2-9787-b71edd3fb29c" class="">This is how Eric describes the first steps:</p> <pre id="7c984405-6ffd-4577-a56a-7af104413a32" class="code code-wrap"><code># Assume the current directory is where we want the new repository to be created # Create the new repository git init # Before we do a merge, we need to have an initial commit, so we’ll make a dummy commit dir > deleteme.txt git add . git commit -m “Initial dummy commit” # Add a remote for and fetch the old repo git remote add -f old_a <OldA repo URL> # Merge the files from old_a/master into new/master git merge old_a/master</code></pre> <p id="1ec6e693-4c83-47bb-ae27-999a1f0da4b0" class="">I could skip everything up to the <code>git remote ...</code> step as my target repository already had some history, so I started as follows:</p> <pre id="91ca30c5-293f-464a-8a49-84b3f0a0ae7f" class="code code-wrap"><code>git clone https://github.com/mdn/dom-examples.git cd dom-examples</code></pre> <p id="5e489297-b8ab-454b-9ff6-becfa188a995" class="">Running <code>git log</code> on this repository, I see the following commit history:</p> <pre id="1a1124c2-cc64-4db1-bd58-be3ba946ea54" class="code code-wrap"><code>commit cdfd2aeb93cb4bd8456345881997fcec1057efbb (HEAD -> master, upstream/master) Merge: 1c7ff6e dfe991b Author: Date: Fri Aug 5 10:21:27 2022 +0200 Merge pull request #143 from mdn/sideshowbarker/webgl-sample6-UNPACK_FLIP_Y_WEBGL “Using textures in WebGL”: Fix orientation of Firefox logo commit dfe991b5d1b34a492ccd524131982e140cf1e555 Author: Date: Fri Aug 5 17:08:50 2022 +0900 “Using textures in WebGL”: Fix orientation of Firefox logo Fixes <https://github.com/mdn/content/issues/10132> commit 1c7ff6eec8bb0fff5630a66a32d1b9b6b9d5a6e5 Merge: be41273 5618100 Author: Date: Fri Aug 5 09:01:56 2022 +0200 Merge pull request #142 from mdn/sideshowbarker/webgl-demo-add-playsInline-drop-autoplay WebGL sample8: Drop “autoplay”; add “playsInline” commit 56181007b7a33907097d767dfe837bb5573dcd38 Author: Date: Fri Aug 5 13:41:45 2022 +0900 </code></pre> <p id="9b0be3c8-62aa-4e6f-a982-603c03944ded" class="">With the current setup, I could continue from the <code>git remote</code> command, but I wondered if the current directory contained files or folders that would conflict with those in the service worker repository. I searched around some more to see if anyone else had run into this same situation but did not find an answer. Then it hit me! I need to prepare the service worker repo to be moved.</p> <p id="f28077e4-2c8f-4248-a235-2eb80207d7c8" class="">What do I mean by that? I need to create a new directory in the root of the <code>sw-test</code> repo called <code>service-worker/sw-test</code> and move all relevant files into this new subdirectory. This will allow me to safely merge it into <code>dom-examples</code> as everything is contained in a subfolder already.</p> <p id="a1e3770b-a673-4d74-a4b1-17d7930e9352" class="">To get started, I need to clone the repo we want to merge into <code>dom-</code><code>examples</code>.</p> <pre id="071ba87f-ee28-4b2a-b4fa-61796f8ad20a" class="code code-wrap"><code>git clone https://github.com/mdn/sw-test.git cd sw-test</code></pre> <p id="f032fac1-56ef-4a92-8851-d37700e14143" class="">Ok, now we can start preparing the repo. The first step is to create our new subdirectory.</p> <pre id="131694fb-bbb2-4d49-a9e6-817f221fc635" class="code code-wrap"><code>mkdir service-worker mkdir service-worker/sw-test</code></pre> <p id="35d63bf0-896a-4d02-babe-e39c3f4af44c" class="">With this in place, I simply need to move everything in the root directory to the subdirectory. To do this, we will make use of the <a href="https://www.rapidtables.com/code/linux/mv.html">move (</a><a href="https://www.rapidtables.com/code/linux/mv.html"><code>mv</code></a><a href="https://www.rapidtables.com/code/linux/mv.html">) command</a>:</p> <blockquote id="e4c3d33e-eec2-4e61-8aef-b3f28b1ca5c6" class=""><p>NOTE: Do not yet run any of the commands below at this stage.</p></blockquote> <pre id="42c8e3b9-23e0-42cb-b176-a19a3055be7e" class="code code-wrap"><code> # enable extendedglob for ZSH set -o extendedglob mv ^sw-test(D) service-worker/swtest</code></pre> <p id="f9210a49-47a0-44bc-b148-ab4a94422938" class="">The above command is a little more complex than you might think. It uses a negation syntax. The next section explains why we need it and how to enable it.</p> <h2 id="367b4f61-defe-46ee-a0ea-e25bcafc59fa" class="">How to exclude subdirectories when using <code>mv</code></h2> <p id="69a87233-c045-44b5-a7b3-300acc57ece1" class="">While the end goal seemed simple, I am pretty sure I grew a small animal’s worth of grey hair trying to figure out how to make that last move command work. I read many StackOverflow threads, blog posts, and manual pages for the different commands with varying amounts of success. However, none of the initial set of options quite met my needs. I finally stumbled upon two StackOverflow threads that brought me to the answer.</p> <ul id="c4b53d6d-572d-4dd5-981f-6b62d991d709" class="bulleted-list"> <li style="list-style-type: disc;"><a href="https://unix.stackexchange.com/questions/567970/how-to-move-all-files-in-a-folder-to-a-sub-folder-in-zsh-w-mac-os-x/">How to move all files in a folder to a sub folder in zsh w/ Mac OS X?</a></li> </ul> <ul id="1af8c0d9-acf0-4d52-acc6-4241003f922e" class="bulleted-list"> <li style="list-style-type: disc;"><a href="https://askubuntu.com/questions/91740/how-to-move-all-files-in-current-folder-to-subfolder">How to move all files in current folder to subfolder?</a></li> </ul> <p id="384c80a1-89f5-4e4a-9aeb-9d4ecec6e9dc" class="">To spare you the trouble, here is what I had to do.</p> <blockquote id="744ec536-d86a-4c12-af28-618364341983" class=""><p>First, a note. I am on a Mac using ZSH (since macOS Catalina, this is now the default shell). Depending on your shell, the instructions below may differ.</p></blockquote> <p id="c332b161-7756-4197-b6bb-5b76a1825fc6" class="">For new versions of ZSH, you use the <code>set -o</code> and <code>set +o</code> commands to enable and disable settings. To enable <code>extendedglob</code>, I used the following command:</p> <pre id="b0a08bae-6f4a-4f92-b6e8-82649b3f3e3a" class="code code-wrap"><code> # Yes, this _enables_ it set -o extendedglob</code></pre> <p id="9b36d318-8202-49bb-a955-e40f19f08370" class="">On older versions of ZSH, you use the <code>setopt</code> and <code>unsetopt</code> commands.</p> <pre id="78b9b670-06c0-48a9-8fe4-e1811a7beab7" class="code code-wrap"><code>setopt extendedglob</code></pre> <p id="229b37f6-e148-4b2d-8620-2b34b8d4d39b" class="">With <a href="https://www.gnu.org/software/bash/"><code>bash</code></a>, you can achieve the same using the following command:</p> <pre id="3e2d2907-3827-4fc1-800d-96663de788de" class="code code-wrap"><code>shopt -s extglob</code></pre> <p id="877728bd-5dfe-431c-9133-6d217dfae435" class="">Why do you even have to do this, you may ask? Without this, you will not be able to use the negation operator I use in the above move command, which is the crux of the whole thing. If you do the following, for example:</p> <pre id="ecaaf2de-29ad-474c-a6f0-5df55fe634c5" class="code code-wrap"><code>mkdir service-worker mv * service-worker/sw-test</code></pre> <p id="036aa161-c596-4a20-911b-d16b42368106" class="">It will “work,” but you will see an error message like this:</p> <pre id="04035162-e15c-430a-9f23-f10504643521" class="code code-wrap"><code>mv: rename service-worker to service-worker/sw-test/service-worker: Invalid argument</code></pre> <p id="ae99fd19-d26d-43c2-a167-6681f70f5f76" class="">We <em>want</em> to tell the operating system to move everything into our new subfolder except the subfolder itself. We, therefore, need this negation syntax. It is not enabled by default because it could cause problems if file names contain some of the <code>extendedglob</code> patterns, such as <code>^</code>. So we need to enable it explicitly.</p> <blockquote id="9f6a3340-608b-408c-9b81-5cb9bafc2a78" class=""><p>NOTE: You might also want to disable it after completing your move operation.</p></blockquote> <p id="c0f4da3e-8ee0-47bf-863f-6987e5682ea9" class="">Now that we know how and why we want <code>extendedglob</code> enabled, we move on to using our new powers.</p> <blockquote id="62ff5fad-59a6-477c-b798-1048211422de" class=""><p>NOTE: Do not yet run any of the commands below at this stage.</p></blockquote> <pre id="1d22e143-50b1-4f68-b608-bbef21f49efc" class="code code-wrap"><code>mv ^sw-test(D) service-worker/sw-test</code></pre> <p id="dbdbf5a8-c8d2-4a0a-9369-8d91dd7028d2" class="">The above means:</p> <ul id="8d1f6367-8982-4a47-990c-14ccfcfb473f" class="bulleted-list"> <li style="list-style-type: disc;">Move all the files in the current directory into <code>service-worker/sw-test</code>.</li> </ul> <ul id="f88a5050-a4a7-468f-9185-f33571641913" class="bulleted-list"> <li style="list-style-type: disc;">Do not try to move the <code>service-worker</code> directory itself.</li> </ul> <ul id="41c7b8d9-0811-4bd8-8168-03e120a71df7" class="bulleted-list"> <li style="list-style-type: disc;">The (D) option tells the move command to also move all hidden files, such as <code>.gitignore</code>, and hidden folders, such as <code>.git</code>.</li> </ul> <blockquote id="496dc420-f3fb-4f37-ae38-240f3d705d1c" class=""><p>NOTE: I found that if I typed <code>mv ^sw-test</code> and pressed tab, my terminal would expand the command to <code>mv CODE_OF_CONDUCT.md LICENSE README.md app.js gallery image-list.js index.html service-worker star-wars-logo.jpg style.css sw.js.</code> If I typed <code>mv ^sw-test(D)</code> and pressed tab, it would expand to <code>mv .git .prettierrc CODE_OF_CONDUCT.md LICENSE README.md app.js gallery image-list.js index.html service-worker star-wars-logo.jpg style.css sw.js</code>. This is interesting because it clearly demonstrates what happens under the hood. This allows you to see the effect of using <code>(D)</code> clearly. I am not sure whether this is just a native ZSH thing or one of my terminal plugins, such as <a href="https://fig.io">Fig</a>. Your mileage may vary.</p></blockquote> <h2 id="dbcc4e95-edfa-4f98-a2e0-c4691f4fd050" class="">Handling hidden files and creating a pull request</h2> <p id="a1b6a944-709f-4cdd-9546-67955f162b36" class="">While it is nice to be able to move all of the hidden files and folders like this, it causes a problem. Because the <code>.git</code> folder is transferred into our new subfolder, our root directory is no longer seen as a Git repository. This is a problem.</p> <p id="66d67f7d-7670-4dee-8c37-4e11ba92d101" class="">Therefore, I will not run the above command with <code>(D)</code> but instead move the hidden files as a separate step. I will run the following command instead:</p> <pre id="b9ce4da7-922b-47d7-9168-e739593dffbf" class="code code-wrap"><code>mv ^(sw-test|service-worker) service-worker/sw-test</code></pre> <p id="9d818f74-bd19-4882-885d-53af4feee5e3" class="">At this stage, if you run <code>ls</code> it will look like it moved everything. That is not the case because the <code>ls</code> command does not list hidden files. To do that, you need to pass the <code>-A</code> flag as shown below:</p> <pre id="f9cda63e-4d58-4542-97d3-69cf9b6e5127" class="code code-wrap"><code>ls -A</code></pre> <p id="dd471bba-293d-438a-b07c-b1916124b7c0" class="">You should now see something like the following:</p> <pre id="32ea4022-1ff1-42e8-b8c2-e63bf5ac0bb4" class="code code-wrap"><code>❯ ls -A .git .prettierrc service-worker</code></pre> <p id="9be6f1ec-a57e-4f51-ba85-2f74c3e1ee42" class="">Looking at the above output, I realized that I should not need to move the <code>.git</code> folder. All I needed to do now was to run the following command:</p> <pre id="a38b89f7-92db-4740-adf2-74ebce461563" class="code code-wrap"><code>mv .prettierrc service-worker</code></pre> <p id="b42e5f4c-a1f6-4624-ad6d-52d278e87744" class="">After running the above command, <code>ls -A</code> will now output the following:</p> <pre id="3bb674de-0499-475b-bb18-7df68d7f3b71" class="code code-wrap"><code>❯ ls -A .git simple-service-worker</code></pre> <p id="9fba2646-32cb-42e8-aabb-de142e805b8b" class="">Time to do a little celebration dance 😁</p> <p id="14cac7ce-9f81-4dd8-9e9e-29296d7ee417" class="">We can move on now that we have successfully moved everything into our new subdirectory. However, while doing this, I realized I forgot to create a <a href="https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow">feature branch</a> for the work.</p> <p id="f1e40721-fc71-4779-97c0-4174dbe482a3" class="">Not a problem. I just run the command, <code>git switch -C prepare-repo-for-move</code>. Running <code>git status</code> at this point should output something like this:</p> <pre id="ad0afc74-4282-4896-8183-25d8300e83e7" class="code code-wrap"><code>❯ git status On branch prepare-repo-for-move Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: .prettierrc deleted: CODE_OF_CONDUCT.md deleted: LICENSE deleted: README.md deleted: app.js deleted: gallery/bountyHunters.jpg deleted: gallery/myLittleVader.jpg deleted: gallery/snowTroopers.jpg deleted: image-list.js deleted: index.html deleted: star-wars-logo.jpg deleted: style.css deleted: sw.js Untracked files: (use "git add <file>..." to include in what will be committed) service-worker/ no changes added to commit (use "git add" and/or "git commit -a")</code></pre> <p id="b35b6c18-e9b2-4e65-a663-4ee3895be9d0" class="">Great! Let’s add our changes and commit them.</p> <pre id="d6e285f1-583e-447f-a95b-ee6150ac4691" class="code code-wrap"><code>git add . git commit -m 'Moved all source files into new subdirectory'</code></pre> <p id="ead5ed94-2f52-4105-aa5b-5f36fadfe08d" class="">Now we want to push our changes and open a pull request.</p> <p id="4ef887cd-948a-4e72-9bce-0e3292a69dd5" class="">Woop! Let’s push:</p> <pre id="37a94326-07d9-4515-b884-f0560f631e8b" class="code code-wrap"><code>git push origin prepare-repo-for-move</code></pre> <p id="7e32e78e-6d17-4e60-93bd-4427dc1fb0b7" class="">Head over to your repository on GitHub. You should see a banner like “mv-files-into-subdir had recent pushes less than a minute ago” and a “Compare & pull request” button.</p> <p id="b1d8b977-db39-4109-aa07-b88251e3d057" class="">Click the button and follow the steps to open the <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests">pull request.</a> Once the pull request is green and ready to merge, go ahead and merge!</p> <blockquote id="439ef4b9-d678-434a-b175-290439245561" class=""><p>NOTE: Depending on your workflow, this is the point to ask a team member to review your proposed changes before merging. It is also a good idea to have a look over the changes in the “Files changed” tab to ensure nothing is part of the pull request you did not intend. If any <a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts">conflicts prevent</a> your pull request from being merged, GitHub will warn you about these, and you will need to resolve them. This can be done directly on <a href="http://GitHub.com">GitHub.com</a> or locally and pushed to GitHub as a separate commit.</p></blockquote> <p id="953dd30b-9f60-40ae-9681-7c83f2963c42" class="">When you head back to the code view on GitHub, you should see our new subdirectory and the <code>.gitignore</code> file.</p> <p id="0e8cd16a-eb3e-4afe-8f11-335d68455a4e" class="">With that, our repository is ready to move.</p> <h2 id="0272b87e-05fc-4ddb-96fa-7867df545657" class="">Merging our repositories</h2> <p id="ea33e259-5fa2-4e61-b580-09858e6b63bb" class="">Back in the terminal, you want to switch back to the <code>main</code> branch:</p> <pre id="c5d3d234-78fb-4f74-82d2-c3a53cb29048" class="code code-wrap"><code>git switch main</code></pre> <p id="428a5ebe-af68-4742-b550-09097ba5439a" class="">You can now safely delete the feature branch and pull down the changes from your remote.</p> <pre id="215eafce-b40e-4af5-95e7-96d0af713c62" class="code code-wrap"><code>git branch -D prepare-repo-for-move git pull origin main</code></pre> <p id="c09e504f-957f-4593-9adf-5949e9e1332f" class="">Running <code>ls -A</code> after pulling the latest should now show the following:</p> <pre id="250aa99c-27dd-44e6-a4ac-7658ac509392" class="code code-wrap"><code>❯ ls -A .git README.md service-worker</code></pre> <p id="9d98535c-e53c-4044-87e9-53b7258c3455" class="">Also, running <code>git log</code> in the root outputs the following:</p> <pre id="190f4579-d331-471e-b2e8-e7f6312505b8" class="code code-wrap"><code>commit 8fdfe7379130b8d6ea13ea8bf14a0bb45ad725d0 (HEAD -> gh-pages, origin/gh-pages, origin/HEAD) Author: Schalk Neethling Date: Thu Aug 11 22:56:48 2022 +0200 Create README.md commit 254a95749c4cc3d7d2c7ec8a5902bea225870176 Merge: f5c319b bc2cdd9 Author: Schalk Neethling Date: Thu Aug 11 22:55:26 2022 +0200 Merge pull request #45 from mdn/prepare-repo-for-move chore: prepare repo for move to dom-examples commit bc2cdd939f568380ce03d56f50f16f2dc98d750c (origin/prepare-repo-for-move) Author: Schalk Neethling Date: Thu Aug 11 22:53:13 2022 +0200 chore: prepare repo for move to dom-examples Prepping the repository for the move to dom-examples commit f5c319be3b8d4f14a1505173910877ca3bb429e5 Merge: d587747 2ed0eff Author: Ruth John Date: Fri Mar 18 12:24:09 2022 +0000 Merge pull request #43 from SimonSiefke/add-navigation-preload</code></pre> <p id="03b94e9c-4911-4a67-93b9-b3321f1700bd" class="">Here are the commands left over from where we diverted earlier on.</p> <pre id="c57542e8-26e1-431e-9450-faac351999a6" class="code code-wrap"><code># Add a remote for and fetch the old repo git remote add -f old_a <OldA repo URL> # Merge the files from old_a/master into new/master git merge old_a/master</code></pre> <p id="7d7c8889-3a6e-4073-906e-f296cc0a2b81" class="">Alrighty, let’s wrap this up. First, we need to move into the root of the project to which we want to move our project. For our purpose here, this is the <code>dom-examples</code> directory. Once in the root of the directory, run the following:</p> <pre id="4900ee3a-9d06-49cb-8ca5-9a668872c29f" class="code code-wrap"><code>git remote add -f swtest https://github.com/mdn/sw-test.git</code></pre> <blockquote id="1b47263d-fa34-4aa7-83c9-fc83cdd1d4bc" class=""><p>NOTE: The <code>-f</code> tells Git to fetch the remote branches. The <code>ssw</code> is a name you give to the remote so this could really be anything.</p></blockquote> <p id="0da0b3a3-b3b7-408c-9120-d70c934ef56d" class="">After running the command, I got the following output:</p> <pre id="079a6efa-e7f6-4974-b416-5ad2d7fe66fb" class="code code-wrap"><code>❯ git remote add -f swtest https://github.com/mdn/sw-test.git Updating swtest remote: Enumerating objects: 500, done. remote: Counting objects: 100% (75/75), done. remote: Compressing objects: 100% (57/57), done. remote: Total 500 (delta 35), reused 45 (delta 15), pack-reused 425 Receiving objects: 100% (500/500), 759.76 KiB | 981.00 KiB/s, done. Resolving deltas: 100% (269/269), done. From <https://github.com/mdn/sw-test> * [new branch] gh-pages -> swtest/gh-pages * [new branch] master -> swtest/master * [new branch] move-prettierrc -> swtest/move-prettierrc * [new branch] rename-sw-test -> swtest/rename-sw-test</code></pre> <blockquote id="ca50d8bf-fcab-425e-9d83-0e7af45421bf" class=""><p>NOTE: While we deleted the branch locally, this is not automatically synced with the remote, so this is why you will still see a reference to the <code>rename-sw-test</code> branch. If you wanted to delete it on the remote, you would run the following from the root of that repository: <code>git push origin :rename-sw-test</code> (if you have configured your repository “to <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches">automatically delete head branches</a>”, this will be automatically deleted for you)</p></blockquote> <p id="f0d0e732-07b2-45e2-a7c3-9a7b6b5811c4" class="">Only a few commands left.</p> <blockquote id="9dacbac3-ae67-4cc6-844e-f8840e0867c4" class=""><p>NOTE: Do not yet run any of the commands below at this stage.</p></blockquote> <pre id="fcfe72fd-c24f-466b-8e79-5ff30f2dded0" class="code code-wrap"><code>git merge swtest/gh-pages</code></pre> <p id="bdb293de-5158-49d7-8dc0-30f76ebf097e" class="">Whoops! When I ran the above, I got the following error:</p> <pre id="6fd19b11-462d-4779-8be0-c7b66f6f5573" class="code code-wrap"><code>❯ git merge swtest/gh-pages fatal: refusing to merge unrelated histories</code></pre> <p id="9180f354-b747-490e-b9c4-7e6c23217e35" class="">But this is pretty much exactly what I <em>do</em> want, right? This is the default behavior of the <code>merge</code> command, but you can pass a flag and allow this behavior.</p> <pre id="87f01818-0d90-47a6-8ee9-4cc93c0cd734" class="code code-wrap"><code>git merge swtest/gh-pages --allow-unrelated-histories</code></pre> <blockquote id="44a8b877-25ab-4d27-a360-09e8c8952768" class=""><p>NOTE: Why <code>gh-pages</code>? More often than not, the one you will merge here will be <code>main</code> but for this particular repository, the default branch was named <code>gh-pages</code>. It used to be that when using GitHub pages, you would need a branch called <code>gh-pages</code> that will then be automatically deployed by GitHub to a URL that would be something like mdn.github.io/sw-test.</p></blockquote> <p id="d913f747-247b-4564-b7a8-ade2cabb8bd3" class="">After running the above, I got the following:</p> <pre id="761fe400-631f-4679-80db-237f1ef436b3" class="code code-wrap"><code>❯ git merge swtest/gh-pages --allow-unrelated-histories Auto-merging README.md CONFLICT (add/add): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result.</code></pre> <p id="5cef1260-ecb3-435b-8845-bf38596b48cd" class="">Ah yes, of course. Our current project and the one we are merging both contain a <code>README.md</code>, so Git is asking us to decide what to do. If you open up the <code>README.md</code> file in your editor, you will notice something like this:</p> <pre id="505e70db-844a-454d-8c84-0d42b8cb7fd8" class="code code-wrap"><code><<<<<<< HEAD =======</code></pre> <p id="aeb83b54-c7f0-48b0-9df8-69414f069813" class="">There might be a number of these in the file. You will also see some entries like this, <code>>>>>>>> swtest/gh-pages</code>. This highlights the conflicts that Git is not sure how to resolve. You could go through and clear these manually. In this instance, I just want what is in the <code>README.md</code> at the root of the <code>dom-examples</code> repo, so I will clean up the conflicts or copy the content from the <code>README.md</code> from GitHub.</p> <p id="5081c830-af14-4b40-ac3e-f7b001481612" class="">As Git requested, we will add and commit our changes.</p> <pre id="c83d71e8-8786-489f-88b9-5e545eee6e25" class="code code-wrap"><code>git add . git commit -m 'merging sw-test into dom-examples'</code></pre> <p id="df4823f9-6395-403b-866d-68d6da094c4b" class="">The above resulted in the following output:</p> <pre id="4224e518-674f-49d2-b251-5f3c6f6620fa" class="code code-wrap"><code>❯ git commit [146-chore-move-sw-test-into-dom-examples 4300221] Merge remote-tracking branch 'swtest/gh-pages' into 146-chore-move-sw-test-into-dom-examples</code></pre> <p id="9d63283d-ef3f-4525-af03-3186f16e26da" class="">If I now run <code>git log</code> in the root of the directory, I see the following:</p> <pre id="81163412-53a4-4303-a29d-6e7db20dcafe" class="code code-wrap"><code>commit 4300221fe76d324966826b528f4a901c5f17ae20 (HEAD -> 146-chore-move-sw-test-into-dom-examples) Merge: cdfd2ae 70c0e1e Author: Schalk Neethling Date: Sat Aug 13 14:02:48 2022 +0200 Merge remote-tracking branch 'swtest/gh-pages' into 146-chore-move-sw-test-into-dom-examples commit 70c0e1e53ddb7d7a26e746c4a3412ccef5a683d3 (swtest/gh-pages) Merge: 4b7cfb2 d4a042d Author: Schalk Neethling Date: Sat Aug 13 13:30:58 2022 +0200 Merge pull request #47 from mdn/move-prettierrc chore: move prettierrc commit d4a042df51ab65e60498e949ffb2092ac9bccffc (swtest/move-prettierrc) Author: Schalk Neethling Date: Sat Aug 13 13:29:56 2022 +0200 chore: move prettierrc Move `.prettierrc` into the siple-service-worker folder commit 4b7cfb239a148095b770602d8f6d00c9f8b8cc15 Merge: 8fdfe73 c86d1a1 Author: Schalk Neethling Date: Sat Aug 13 13:22:31 2022 +0200 Merge pull request #46 from mdn/rename-sw-test</code></pre> <p id="a95c9e4d-6612-4383-b984-5da1143d59e4" class="">Yahoooo! That is the history from <code>sw-test</code> now in our current repository! Running <code>ls -A</code> now shows me:</p> <pre id="6680971c-ffff-44a2-8e18-ce46cb80739d" class="code code-wrap"><code>❯ ls -A .git indexeddb-examples screen-wake-lock-api .gitignore insert-adjacent screenleft-screentop CODE_OF_CONDUCT.md matchmedia scrolltooptions LICENSE media server-sent-events README.md media-session service-worker abort-api mediaquerylist streams auxclick payment-request touchevents canvas performance-apis web-animations-api channel-messaging-basic picture-in-picture web-crypto channel-messaging-multimessage pointer-lock web-share drag-and-drop pointerevents web-speech-api fullscreen-api reporting-api web-storage htmldialogelement-basic resize-event web-workers indexeddb-api resize-observer webgl-examples</code></pre> <p id="ac2fb082-6040-4c3c-a9e5-5d544ebba5a8" class="">And if I run <code>ls -A service-worker/</code>, I get:</p> <pre id="60c0f598-0679-483c-b138-36babc6c4a9d" class="code code-wrap"><code>❯ ls -A service-worker/ simple-service-worker</code></pre> <p id="46810345-8809-4774-b558-b4677d5e6e0b" class="">And finally, running <code>ls -A service-worker/simple-service-worker/</code> shows:</p> <pre id="fb69535a-43e8-4176-87cb-a12d2561c080" class="code code-wrap"><code>❯ ls -A service-worker/simple-service-worker/ .prettierrc README.md image-list.js style.css CODE_OF_CONDUCT.md app.js index.html sw.js LICENSE gallery star-wars-logo.jpg</code></pre> <p id="1cdea38c-6f57-4364-9d03-ba7146a2b48b" class="">All that is left is to push to remote.</p> <pre id="bd945452-2b0c-4af0-9d69-3b74491494d3" class="code code-wrap"><code>git push origin 146-chore-mo…dom-examples</code></pre> <blockquote id="f50dcff8-a627-422d-bf31-8d1659c66554" class=""><p><strong>NOTE:</strong> Do not squash merge this pull request, or else all commits will be squashed together as a single commit. Instead, you want to use a merge commit. You can read all the <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github">details about merge methods</a> in their documentation on GitHub.</p></blockquote> <p id="a9dabbb9-49e9-42b2-a201-71306b754045" class="">After you merge the pull request, go ahead and browse the commit history of the repo. You will find that the commit history is intact and merged. o/\o You can now go ahead and either delete or archive the old repository.</p> <p id="2f66dffe-0f3b-45ff-a4ec-ba122d820ce7" class="">At this point having the remote configured for our target repo serve no purpose so, we can safe remove the remote.</p> <pre id="3c72a98b-2607-49db-bc47-3106158623f0" class="code"><code>git remote rm swtest</code></pre> <h3 id="c7bd35e7-333b-4e4e-bdff-7f145a5c2637" class="">In Conclusion</h3> <p id="2bb6b3e5-af58-4b03-ab09-de0190276c51" class="">The steps to accomplish this task is then as follows:</p> <pre id="5de6937b-ebac-438a-9dea-7a6b7f19b47e" class="code"><code># Clone the repository you want to merge git clone https://github.com/mdn/sw-test.git cd sw-test # Create your feature branch git switch -C prepare-repo-for-move # NOTE: With older versions of Git you can run: # git checkout -b prepare-repo-for-move # Create directories as needed. You may only need one, not two as # in the example below. mkdir service-worker mkdir service-worker/sw-test # Enable extendedglob so we can use negation # The command below is for modern versions of ZSH. See earlier # in the post for examples for bash and older versions of ZSH set -o extendedglob # Move everything except hidden files into your subdirectory, # also, exclude your target directories mv ^(sw-test|service-worker) service-worker/sw-test # Move any of the hidden files or folders you _do_ want # to move into the subdirectory mv .prettierrc service-worker # Add and commit your changes git add . git commit -m 'Moved all source files into new subdirectory' # Push your changes to GitHub git push origin prepare-repo-for-move # Head over to the repository on GitHub, open and merge your pull request # Back in the terminal, switch to your `main` branch git switch main # Delete your feature branch # This is not technically required, but I like to clean up after myself :) git branch -D prepare-repo-for-move # Pull the changes you just merged git pull origin main # Change to the root directory of your target repository # If you have not yet cloned your target repository, change # out of your current directory cd .. # Clone your target repository git clone https://github.com/mdn/dom-examples.git # Change directory cd dom-examples # Create a feature branch for the work git switch -C 146-chore-move-sw-test-into-dom-examples # Add your merge target as a remote git remote add -f ssw https://github.com/mdn/sw-test.git # Merge the merge target and allow unrelated history git merge swtest/gh-pages --allow-unrelated-histories # Add and commit your changes git add . git commit -m 'merging sw-test into dom-examples' # Push your changes to GitHub git push origin 146-chore-move-sw-test-into-dom-examples # Open the pull request, have it reviewed by a team member, and merge. # Do not squash merge this pull request, or else all commits will be # squashed together as a single commit. Instead, you want to use a merge commit. # Remove the remote for the merge target git remote rm swtest</code></pre> <p id="ed6f1158-24b8-4ebc-963b-d50dfea02ff0" class="">Hopefully, you now know how to exclude subdirectories using the mv command, set and view shell configuration, and merge the file contents of a git repo into a new repository while preserving the entire commit history using only basic git commands.</p> </div> </article> <section class="about"> <h2 class="about__header">About <a class="url" href="http://schalkneethling.com" rel="external me"> Schalk Neethling </a> </h3> <p>I am a Mozillian, an evangelist, writer and developer with a passion for open source, web standards and accessibility. I have been so involved with these worlds that I feel they have become a part of me and cannot foresee a future where these topics will not be a part of my daily life.</p> <ul class="author-meta fa-ul"><li><i class="fa-li fa fa-globe"></i><a href="http://schalkneethling.com" class="website" rel="me">schalkneethling.com</a></li><li><i class="fa-li fa fa-twitter"></i><a href="http://twitter.com/schalkneethling" class="twitter" rel="me">@schalkneethling</a></li></ul> <p><a class="url" href="https://hacks.mozilla.org/author/sneethlingmozilla-com/">More articles by Schalk Neethling…</a></p> </section> </article> <section class="promo"> <form id="newsletterForm" name="newsletter-form" class="newsletter block block--1 block--polite" action="https://www.mozilla.org/en-US/newsletter/" method="post"> <h2 class="heading">Discover great resources for web development</h2> <p class="newsletter__description">Sign up for the Mozilla Developer Newsletter:</p> <input id="fmt" name="fmt" value="H" type="hidden"> <input id="newsletterNewslettersInput" name="newsletters" value="app-dev" type="hidden"> <div id="newsletterErrors" class="newsletter__errors"></div> <div id="newsletterEmail" class="form__row"> <label for="newsletterEmailInput" class="offscreen">E-mail</label> <input id="newsletterEmailInput" name="email" class="newsletter__input" required="" placeholder="you@example.com" size="30" type="email"> </div> <div id="newsletterPrivacy" class="form__row form__fineprint"> <input id="newsletterPrivacyInput" name="privacy" required="" type="checkbox"> <label for="newsletterPrivacyInput"> I'm okay with Mozilla handling my info as explained in this <a href="https://www.mozilla.org/privacy/">Privacy Policy</a>. </label> </div> <button id="newsletter-submit" type="submit" class="button positive">Sign up now</button> </form> <div id="newsletterThanks" class="newsletter newsletter--thanks block block--1 block--polite hidden"> <h2 class="heading">Thanks! Please check your inbox to confirm your subscription.</h2> <p>If you haven’t previously confirmed a subscription to a Mozilla-related newsletter you may have to do so. Please check your inbox or your spam filter for an email from us. </p> </div> </section> <section class="discussion"> <hr class="dino"> <div class="comments"> <header class="comments__head"> <h3>One comment</h3> </header> <ol class="comments__list" class="hfeed"> <li id="comment-27914" class="comment even thread-even depth-1"> <b class="comment__title vcard"> <cite class="author fn">Jean-Sébastien Bour</cite> </b> <blockquote class="comment__body"> <p>Instead of adding dummy content to it, you can make an empty initial commit with the –allow-empty flag.</p> </blockquote> <a class="comment__meta" href="https://hacks.mozilla.org/2022/08/merging-two-github-repositories-without-losing-commit-history/#comment-27914" rel="bookmark" title="Permanent link to this comment by Jean-Sébastien Bour"><abbr class="published" title="2022-08-29">August 29th, 2022</abbr> at 02:09</a> <p class="comment__util"> </p> </li><!-- #comment-## --> </ol> </div> <p class="comments__closed"><b>Comments are closed for this article.</b></p> </main><!-- /#content-main --> <footer class="footer section section--fullwidth"> <div class="row"> <p class="block block--1"> Except where otherwise noted, content on this site is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/" rel="license external">Creative Commons Attribution Share-Alike License v3.0</a> or any later version. </p> <img class="footer__logo" alt="the Mozilla dino logo" src="https://hacks.mozilla.org/wp-content/themes/Hax/img/dino.svg"> </div> </footer> </div> <script> // External links should open in a new tab. (function () { var postLinks = document.querySelectorAll('#content-main a'); var origin = location.origin; for (var i = 0; i < postLinks.length; i++) { var link = postLinks[i]; if (link.origin !== origin && !link.getAttribute('target')) { link.setAttribute('target', '_blank'); } } })(); window.addEventListener('load', function () { if (document.querySelector('#newsletterForm')) { var script = document.createElement('script'); var path = document.head.getAttribute('data-template-path'); script.setAttribute('src', path + '/js/newsletter.js'); document.head.appendChild(script); } }); </script> </body> </html>