|
|
|
#!/usr/bin/env vpython3
|
|
|
|
# Copyright 2020 The Chromium Authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
"""Migrate local repository onto new default branch."""
|
|
|
|
|
|
|
|
import fix_encoding
|
|
|
|
import gerrit_util
|
|
|
|
import git_common
|
|
|
|
import metrics
|
|
|
|
import scm
|
|
|
|
import sys
|
|
|
|
import logging
|
|
|
|
import urllib.parse
|
|
|
|
|
|
|
|
|
|
|
|
def GetGerritProject(remote_url):
|
|
|
|
"""Returns Gerrit project name based on remote git URL."""
|
|
|
|
if remote_url is None:
|
|
|
|
raise RuntimeError('can\'t detect Gerrit project.')
|
|
|
|
project = urllib.parse.urlparse(remote_url).path.strip('/')
|
|
|
|
if project.endswith('.git'):
|
|
|
|
project = project[:-len('.git')]
|
|
|
|
# *.googlesource.com hosts ensure that Git/Gerrit projects don't start with
|
|
|
|
# 'a/' prefix, because 'a/' prefix is used to force authentication in
|
|
|
|
# gitiles/git-over-https protocol. E.g.,
|
|
|
|
# https://chromium.googlesource.com/a/v8/v8 refers to the same repo/project
|
|
|
|
# as
|
|
|
|
# https://chromium.googlesource.com/v8/v8
|
|
|
|
if project.startswith('a/'):
|
|
|
|
project = project[len('a/'):]
|
|
|
|
return project
|
|
|
|
|
|
|
|
|
|
|
|
def GetGerritHost(git_host):
|
|
|
|
parts = git_host.split('.')
|
|
|
|
parts[0] = parts[0] + '-review'
|
|
|
|
return '.'.join(parts)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
remote = git_common.run('remote')
|
|
|
|
# Use first remote as source of truth
|
|
|
|
remote = remote.split("\n")[0]
|
|
|
|
if not remote:
|
|
|
|
raise RuntimeError('Could not find any remote')
|
|
|
|
url = scm.GIT.GetConfig(git_common.repo_root(), 'remote.%s.url' % remote)
|
|
|
|
host = urllib.parse.urlparse(url).netloc
|
|
|
|
if not host:
|
|
|
|
raise RuntimeError('Could not find remote host')
|
|
|
|
|
|
|
|
project_head = gerrit_util.GetProjectHead(GetGerritHost(host),
|
|
|
|
GetGerritProject(url))
|
|
|
|
if project_head != 'refs/heads/main':
|
|
|
|
raise RuntimeError("The repository is not migrated yet.")
|
|
|
|
|
|
|
|
# User may have set to fetch only old default branch. Ensure fetch is
|
|
|
|
# tracking main too.
|
|
|
|
git_common.run('config', '--unset-all', 'remote.origin.fetch',
|
|
|
|
'refs/heads/*')
|
|
|
|
git_common.run('config', '--add', 'remote.origin.fetch',
|
|
|
|
'+refs/heads/*:refs/remotes/origin/*')
|
|
|
|
logging.info("Running fetch...")
|
|
|
|
git_common.run('fetch', remote)
|
|
|
|
logging.info("Updating remote HEAD...")
|
|
|
|
git_common.run('remote', 'set-head', '-a', remote)
|
|
|
|
|
|
|
|
branches = git_common.get_branches_info(True)
|
|
|
|
|
|
|
|
if 'master' in branches:
|
|
|
|
logging.info("Migrating master branch...")
|
|
|
|
if 'main' in branches:
|
|
|
|
logging.info(
|
|
|
|
'You already have master and main branch, consider removing '
|
|
|
|
'master manually:\n'
|
|
|
|
' $ git branch -d master\n')
|
|
|
|
else:
|
|
|
|
git_common.run('branch', '-m', 'master', 'main')
|
|
|
|
branches = git_common.get_branches_info(True)
|
|
|
|
|
|
|
|
for name in branches:
|
|
|
|
branch = branches[name]
|
|
|
|
if not branch:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if 'master' in branch.upstream:
|
|
|
|
logging.info("Migrating %s branch..." % name)
|
|
|
|
new_upstream = branch.upstream.replace('master', 'main')
|
|
|
|
git_common.run('branch', '--set-upstream-to', new_upstream, name)
|
|
|
|
git_common.remove_merge_base(name)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
fix_encoding.fix_encoding()
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
with metrics.collector.print_notice_and_exit():
|
|
|
|
try:
|
|
|
|
logging.info("Starting migration")
|
|
|
|
main()
|
|
|
|
logging.info("Migration completed")
|
|
|
|
except RuntimeError as e:
|
|
|
|
logging.error("Error %s" % str(e))
|
|
|
|
sys.exit(1)
|