forked from JetBrains/hirschgarten
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmerge-component.py
106 lines (83 loc) · 4.66 KB
/
merge-component.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import argparse
import os
import subprocess
import sys
import tempfile
def error(message):
print(f"ERROR: {message}", file=sys.stderr)
def check_git_filter_repo():
if subprocess.run(["git-filter-repo", "--version"], capture_output=True, check=False).returncode != 0:
error("git-filter-repo is not installed or not in your PATH.")
print("To install git-filter-repo, follow these steps:")
print("1. Ensure you have Python 3 installed.")
print("2. Run: pip3 install git-filter-repo")
print("3. Make sure the installation directory is in your PATH.")
print("For more information, visit: https://github.com/newren/git-filter-repo")
return False
return True
def run_command(command, cwd=None, check=True):
"""Run a shell command and return its output."""
try:
result = subprocess.run(command, cwd=cwd, capture_output=True, text=True, shell=True, check=check)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
if check:
print(f"Error executing command: {command}")
print(f"Error message: {e.stderr}")
sys.exit(1)
return None
def get_local_branches(repo_path):
"""Get a list of local branches in the repository."""
return run_command("git branch --format='%(refname:short)'", cwd=repo_path).split('\n')
def get_remote_branches(repo_path, remote):
"""Get a list of remote branches for a specific remote."""
output = run_command(f"git branch -r --format='%(refname:short)'", cwd=repo_path)
remote_branches = [branch.replace(f"{remote}/", "") for branch in output.split('\n') if branch.startswith(f"{remote}/")]
print(f"Remote branches: {remote_branches}")
return remote_branches
def process_repo(monorepo_path, local_repo_path, subfolder):
"""Process the local repository and merge it into the monorepo."""
print(f"Processing {local_repo_path}...")
with tempfile.TemporaryDirectory(prefix=f"temp-{subfolder}-", dir=os.getcwd()) as temp_dir:
print(f"Created temporary directory: {temp_dir}")
run_command(f"git clone {local_repo_path} {temp_dir}")
run_command(f"git-filter-repo --to-subdirectory-filter {subfolder} --force", cwd=temp_dir)
run_command(f"git remote add {subfolder} {temp_dir}", cwd=monorepo_path)
run_command(f"git fetch {subfolder}", cwd=monorepo_path)
local_branches = get_local_branches(temp_dir)
print(f"Local branches in filtered repo: {local_branches}")
remote_branches = get_remote_branches(monorepo_path, subfolder)
for branch in local_branches:
new_branch_name = f"{subfolder}/{branch}"
if new_branch_name in run_command("git branch", cwd=monorepo_path).split('\n'):
print(f"Branch {new_branch_name} already exists locally, skipping...")
else:
print(f"Creating new branch: {new_branch_name}")
run_command(f"git branch {new_branch_name} {subfolder}/{branch}", cwd=monorepo_path)
# Checkout the new branch
run_command(f"git checkout {new_branch_name}", cwd=monorepo_path)
# Merge main branch allowing unrelated histories
print(f"Merging main branch into {new_branch_name}...")
merge_result = run_command(f"git merge main --allow-unrelated-histories -m 'Merge {new_branch_name} into main'", cwd=monorepo_path, check=False)
if "CONFLICT" in merge_result:
print(f"Merge conflicts occurred in {new_branch_name}. Please resolve them manually.")
else:
print(f"Successfully merged main into {new_branch_name}.")
# Return to the original branch (usually main)
run_command("git checkout -", cwd=monorepo_path)
run_command(f"git remote remove {subfolder}", cwd=monorepo_path)
print(f"Finished processing {local_repo_path}")
def main():
parser = argparse.ArgumentParser(description="Merge a local repository into a monorepo.")
parser.add_argument("monorepo_path", help="Path or URL to the fork of the monorepo")
parser.add_argument("local_repo_path", help="Path to the local repository to merge")
parser.add_argument("subfolder", help="Folder name to put the content in the monorepo")
args = parser.parse_args()
if not check_git_filter_repo():
sys.exit(1)
if not os.path.exists(args.monorepo_path):
run_command(f"git clone {args.monorepo_path} {args.monorepo_path}")
process_repo(args.monorepo_path, args.local_repo_path, args.subfolder)
print("Repository merge process completed successfully!")
if __name__ == "__main__":
main()