git_migrate_default_branch.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/env vpython3
  2. # Copyright 2020 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Migrate local repository onto new default branch."""
  6. import fix_encoding
  7. import gerrit_util
  8. import git_common
  9. import metrics
  10. from lib import scm
  11. import sys
  12. import logging
  13. from six.moves import urllib
  14. def GetGerritProject(remote_url):
  15. """Returns Gerrit project name based on remote git URL."""
  16. if remote_url is None:
  17. raise RuntimeError('can\'t detect Gerrit project.')
  18. project = urllib.parse.urlparse(remote_url).path.strip('/')
  19. if project.endswith('.git'):
  20. project = project[:-len('.git')]
  21. # *.googlesource.com hosts ensure that Git/Gerrit projects don't start with
  22. # 'a/' prefix, because 'a/' prefix is used to force authentication in
  23. # gitiles/git-over-https protocol. E.g.,
  24. # https://chromium.googlesource.com/a/v8/v8 refers to the same repo/project
  25. # as
  26. # https://chromium.googlesource.com/v8/v8
  27. if project.startswith('a/'):
  28. project = project[len('a/'):]
  29. return project
  30. def GetGerritHost(git_host):
  31. parts = git_host.split('.')
  32. parts[0] = parts[0] + '-review'
  33. return '.'.join(parts)
  34. def main():
  35. remote = git_common.run('remote')
  36. # Use first remote as source of truth
  37. remote = remote.split("\n")[0]
  38. if not remote:
  39. raise RuntimeError('Could not find any remote')
  40. url = scm.GIT.GetConfig(git_common.repo_root(), 'remote.%s.url' % remote)
  41. host = urllib.parse.urlparse(url).netloc
  42. if not host:
  43. raise RuntimeError('Could not find remote host')
  44. project_head = gerrit_util.GetProjectHead(GetGerritHost(host),
  45. GetGerritProject(url))
  46. if project_head != 'refs/heads/main':
  47. raise RuntimeError("The repository is not migrated yet.")
  48. # User may have set to fetch only old default branch. Ensure fetch is tracking
  49. # main too.
  50. git_common.run('config', '--unset-all',
  51. 'remote.origin.fetch', 'refs/heads/*')
  52. git_common.run('config', '--add',
  53. 'remote.origin.fetch', '+refs/heads/*:refs/remotes/origin/*')
  54. logging.info("Running fetch...")
  55. git_common.run('fetch', remote)
  56. logging.info("Updating remote HEAD...")
  57. git_common.run('remote', 'set-head', '-a', remote)
  58. branches = git_common.get_branches_info(True)
  59. if 'master' in branches:
  60. logging.info("Migrating master branch...")
  61. if 'main' in branches:
  62. logging.info('You already have master and main branch, consider removing '
  63. 'master manually:\n'
  64. ' $ git branch -d master\n')
  65. else:
  66. git_common.run('branch', '-m', 'master', 'main')
  67. branches = git_common.get_branches_info(True)
  68. for name in branches:
  69. branch = branches[name]
  70. if not branch:
  71. continue
  72. if 'master' in branch.upstream:
  73. logging.info("Migrating %s branch..." % name)
  74. new_upstream = branch.upstream.replace('master', 'main')
  75. git_common.run('branch', '--set-upstream-to', new_upstream, name)
  76. git_common.remove_merge_base(name)
  77. if __name__ == '__main__':
  78. fix_encoding.fix_encoding()
  79. logging.basicConfig(level=logging.INFO)
  80. with metrics.collector.print_notice_and_exit():
  81. try:
  82. logging.info("Starting migration")
  83. main()
  84. logging.info("Migration completed")
  85. except RuntimeError as e:
  86. logging.error("Error %s" % str(e))
  87. sys.exit(1)