Created
August 25, 2017 16:20
-
-
Save parrotbait/c2f39aca41ad12f81206754ca33678ef to your computer and use it in GitHub Desktop.
Little utility to migrate a git repo from one remote to another (from Bitbucket to Github in this case)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import platform | |
import os | |
import sys | |
import io | |
import getopt | |
import subprocess | |
import shutil | |
def usage(): | |
print sys.exit('migrate_git.py -s <source_repo> -t <target_repo> -d <dry_run>') | |
def log(string): | |
print("--- " + string) | |
# Flush here so we can see the output in XCode | |
sys.stdout.flush() | |
def parse_arguments(argv): | |
source_repo = None | |
target_repo = None | |
dry_run = False | |
try: | |
opts, args = getopt.getopt(argv[1:],"s:t:d",["source_repo=","target_repo=","dry_run"]) | |
except getopt.GetoptError: | |
usage() | |
for opt, arg in opts: | |
if opt == ('-h', '--help'): | |
usage() | |
elif opt in ("-s", "--source_repo"): | |
source_repo = arg | |
elif opt in ("-t", "--target_repo"): | |
target_repo = arg | |
elif opt in ("-d", "--dry_run"): | |
dry_run = True | |
if source_repo is None: | |
usage() | |
return source_repo, target_repo, dry_run | |
def executeCommand(command, reportExitCode = True, printCommand = False, quiet = False): | |
out = None | |
err = None | |
if quiet: | |
out = open(os.devnull, 'w') | |
err = subprocess.STDOUT | |
if printCommand: | |
log(">>> " + command) | |
if reportExitCode: | |
result = subprocess.call(command, shell = True, stdout=out, stderr=err) | |
if result != 0: | |
log ("Error running command with code: " + str(result)) | |
sys.exit(result) | |
return result | |
return subprocess.check_output([command], shell = True) | |
dir_path = os.path.dirname(os.path.realpath(__file__)) | |
test_repo_clone = "test_repo_clone" | |
test_repo_name = "test_repo.git" | |
source_repo, target_repo, dry_run = parse_arguments(sys.argv) | |
if len(source_repo) == 0: | |
log("Missing source repo arguments") | |
usage() | |
sys.exit(1) | |
if dry_run: | |
target_repo = os.path.join(dir_path, test_repo_name) | |
if os.path.exists(target_repo): | |
shutil.rmtree(target_repo) | |
target_repo_clone = os.path.join(dir_path, test_repo_clone) | |
if os.path.exists(target_repo_clone): | |
shutil.rmtree(target_repo_clone) | |
executeCommand("git init --bare " + test_repo_name) | |
else: | |
if len(target_repo) == 0: | |
log("Missing target repo arguments") | |
usage() | |
sys.exit(1) | |
source_directory = os.path.splitext(os.path.basename(source_repo))[0] | |
if os.path.exists(source_directory): | |
shutil.rmtree(source_directory) | |
executeCommand("git clone --recursive -j8 " + source_repo + " " + source_directory) | |
os.chdir(source_directory) | |
executeCommand("git fetch --tags") | |
executeCommand("git remote rename origin old") | |
executeCommand("git remote add origin " + target_repo) | |
list_of_branches_str = executeCommand("git branch -r", False) | |
log ("branches " + list_of_branches_str) | |
list_of_branches = list_of_branches_str.split('\n') | |
for branch in list_of_branches: | |
log("Cloning branch: " + branch.strip()) | |
branch_split = branch.strip().split(" ") | |
if len(branch_split) == 0: | |
continue; | |
actual_branch = branch_split[0].strip() | |
if actual_branch.startswith("old/"): | |
actual_branch = actual_branch[4:] | |
else: | |
log("Invalid branch '%s' - does not start with old/ - must be a local branch" % actual_branch) | |
continue; | |
log ("checking out branch '" + actual_branch + "'") | |
# Checkout and push the branch | |
executeCommand("git checkout " + actual_branch) | |
executeCommand("git push -u origin " + actual_branch) | |
# Push tags | |
executeCommand("git push origin --tags") | |
if dry_run: | |
# Clone our new repo locally | |
executeCommand("git clone --recursive " + target_repo + " " + target_repo_clone) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A dry run (-d option) creates a bare git repo in the same directory as the script and pushes everything to that. Useful to verify everything is ok before pushing to actual target repo.