Skip to content

Instantly share code, notes, and snippets.

@gilday
Last active January 26, 2023 16:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilday/c92354c9f9154e3ba7350137b95c3082 to your computer and use it in GitHub Desktop.
Save gilday/c92354c9f9154e3ba7350137b95c3082 to your computer and use it in GitHub Desktop.
utility script for merging repos into a monorepo while preserving history
#!/usr/bin/env python
# merge-repos.py
# utility script for merging repos into a monorepo while preserving history
import argparse
from contextlib import contextmanager
import os
import shutil
import subprocess
import sys
import tempfile
def main():
""" main function """
parser = argparse.ArgumentParser(
description="merge repos into a monorepo preseving history")
parser.add_argument(
"repository",
type=str,
help="repo address to merge e.g. git@bitbucket.org:org/dependency-one.git")
parser.add_argument(
"directory",
type=str,
help="directory in which to merge the repository e.g. "
"dependency-one")
parser.add_argument(
"--branch",
type=str,
help="branch to merge",
default="develop")
parser.add_argument(
"--dry-run",
dest="dryRun",
help="skip the git steps in this repo",
action="store_true")
args = parser.parse_args()
print(args.repository)
print(args.directory)
with tempdir() as path:
subprocess.call(["git", "clone", args.repository, path])
subprocess.call(["git", "checkout", args.branch], cwd=path)
newdir = os.path.join(path, args.directory)
files = [(os.path.join(path, x), os.path.join(newdir, x))
for x in os.listdir(path) if x != '.git']
os.makedirs(newdir)
for src, dest in files:
print("moving {} to {}".format(src, dest))
os.rename(src, dest)
subprocess.call(["git", "add", "-A"], cwd=path)
subprocess.call(
[
"git",
"commit",
"-m",
":truck: Merging repositories - moving files to {}".format(
args.directory)],
cwd=path)
if not args.dryRun:
remote = "merge-{}".format(args.directory)
subprocess.call(["git", "remote", "add", remote, path])
subprocess.call(["git",
"pull",
remote,
args.branch,
"--no-edit",
"--allow-unrelated-histories"])
subprocess.call(["git", "remote", "rm", remote])
else:
print("dry-run: skipping git commands")
@contextmanager
def tempdir():
""" creates a temporary directory that is automatically collected when finished with the
context """
path = tempfile.mkdtemp()
try:
yield path
finally:
try:
shutil.rmtree(path)
except IOError:
print(
'Failed to clean up temp dir {}'.format(path),
file=sys.stderr)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment