Index: git_cl.py |
diff --git a/git_cl.py b/git_cl.py |
index c2675730cc4fc9c92de43750eca680381a6384bd..0e05c783a091f1a609dd0007476ef93b6ff688f0 100755 |
--- a/git_cl.py |
+++ b/git_cl.py |
@@ -64,9 +64,8 @@ __version__ = '2.0' |
COMMIT_BOT_EMAIL = 'commit-bot@chromium.org' |
DEFAULT_SERVER = 'https://codereview.chromium.org' |
-POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s' |
+POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-land' |
DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' |
-GIT_INSTRUCTIONS_URL = 'http://code.google.com/p/chromium/wiki/UsingGit' |
REFS_THAT_ALIAS_TO_OTHER_REFS = { |
'refs/remotes/origin/lkgr': 'refs/remotes/origin/master', |
'refs/remotes/origin/lkcr': 'refs/remotes/origin/master', |
@@ -558,48 +557,6 @@ def write_try_results_json(output_file, builds): |
write_json(output_file, converted) |
-def MatchSvnGlob(url, base_url, glob_spec, allow_wildcards): |
- """Return the corresponding git ref if |base_url| together with |glob_spec| |
- matches the full |url|. |
- |
- If |allow_wildcards| is true, |glob_spec| can contain wildcards (see below). |
- """ |
- fetch_suburl, as_ref = glob_spec.split(':') |
- if allow_wildcards: |
- glob_match = re.match('(.+/)?(\*|{[^/]*})(/.+)?', fetch_suburl) |
- if glob_match: |
- # Parse specs like "branches/*/src:refs/remotes/svn/*" or |
- # "branches/{472,597,648}/src:refs/remotes/svn/*". |
- branch_re = re.escape(base_url) |
- if glob_match.group(1): |
- branch_re += '/' + re.escape(glob_match.group(1)) |
- wildcard = glob_match.group(2) |
- if wildcard == '*': |
- branch_re += '([^/]*)' |
- else: |
- # Escape and replace surrounding braces with parentheses and commas |
- # with pipe symbols. |
- wildcard = re.escape(wildcard) |
- wildcard = re.sub('^\\\\{', '(', wildcard) |
- wildcard = re.sub('\\\\,', '|', wildcard) |
- wildcard = re.sub('\\\\}$', ')', wildcard) |
- branch_re += wildcard |
- if glob_match.group(3): |
- branch_re += re.escape(glob_match.group(3)) |
- match = re.match(branch_re, url) |
- if match: |
- return re.sub('\*$', match.group(1), as_ref) |
- |
- # Parse specs like "trunk/src:refs/remotes/origin/trunk". |
- if fetch_suburl: |
- full_url = base_url + '/' + fetch_suburl |
- else: |
- full_url = base_url |
- if full_url == url: |
- return as_ref |
- return None |
- |
- |
def print_stats(similarity, find_copies, args): |
"""Prints statistics about the change to the user.""" |
# --no-ext-diff is broken in some versions of Git, so try to work around |
@@ -634,8 +591,6 @@ class Settings(object): |
self.default_server = None |
self.cc = None |
self.root = None |
- self.is_git_svn = None |
- self.svn_branch = None |
self.tree_status_url = None |
self.viewvc_url = None |
self.updated = False |
@@ -698,87 +653,6 @@ class Settings(object): |
return mirror |
return None |
- def GetIsGitSvn(self): |
- """Return true if this repo looks like it's using git-svn.""" |
- if self.is_git_svn is None: |
- if self.GetPendingRefPrefix(): |
- # If PENDING_REF_PREFIX is set then it's a pure git repo no matter what. |
- self.is_git_svn = False |
- else: |
- # If you have any "svn-remote.*" config keys, we think you're using svn. |
- self.is_git_svn = RunGitWithCode( |
- ['config', '--local', '--get-regexp', r'^svn-remote\.'])[0] == 0 |
- return self.is_git_svn |
- |
- def GetSVNBranch(self): |
- if self.svn_branch is None: |
- if not self.GetIsGitSvn(): |
- DieWithError('Repo doesn\'t appear to be a git-svn repo.') |
- |
- # Try to figure out which remote branch we're based on. |
- # Strategy: |
- # 1) iterate through our branch history and find the svn URL. |
- # 2) find the svn-remote that fetches from the URL. |
- |
- # regexp matching the git-svn line that contains the URL. |
- git_svn_re = re.compile(r'^\s*git-svn-id: (\S+)@', re.MULTILINE) |
- |
- # We don't want to go through all of history, so read a line from the |
- # pipe at a time. |
- # The -100 is an arbitrary limit so we don't search forever. |
- cmd = ['git', 'log', '-100', '--pretty=medium'] |
- proc = subprocess2.Popen(cmd, stdout=subprocess2.PIPE, |
- env=GetNoGitPagerEnv()) |
- url = None |
- for line in proc.stdout: |
- match = git_svn_re.match(line) |
- if match: |
- url = match.group(1) |
- proc.stdout.close() # Cut pipe. |
- break |
- |
- if url: |
- svn_remote_re = re.compile(r'^svn-remote\.([^.]+)\.url (.*)$') |
- remotes = RunGit(['config', '--get-regexp', |
- r'^svn-remote\..*\.url']).splitlines() |
- for remote in remotes: |
- match = svn_remote_re.match(remote) |
- if match: |
- remote = match.group(1) |
- base_url = match.group(2) |
- rewrite_root = RunGit( |
- ['config', 'svn-remote.%s.rewriteRoot' % remote], |
- error_ok=True).strip() |
- if rewrite_root: |
- base_url = rewrite_root |
- fetch_spec = RunGit( |
- ['config', 'svn-remote.%s.fetch' % remote], |
- error_ok=True).strip() |
- if fetch_spec: |
- self.svn_branch = MatchSvnGlob(url, base_url, fetch_spec, False) |
- if self.svn_branch: |
- break |
- branch_spec = RunGit( |
- ['config', 'svn-remote.%s.branches' % remote], |
- error_ok=True).strip() |
- if branch_spec: |
- self.svn_branch = MatchSvnGlob(url, base_url, branch_spec, True) |
- if self.svn_branch: |
- break |
- tag_spec = RunGit( |
- ['config', 'svn-remote.%s.tags' % remote], |
- error_ok=True).strip() |
- if tag_spec: |
- self.svn_branch = MatchSvnGlob(url, base_url, tag_spec, True) |
- if self.svn_branch: |
- break |
- |
- if not self.svn_branch: |
- DieWithError('Can\'t guess svn branch -- try specifying it on the ' |
- 'command line') |
- |
- return self.svn_branch |
- |
def GetTreeStatusUrl(self, error_ok=False): |
if not self.tree_status_url: |
error_message = ('You must configure your tree status URL by running ' |
@@ -1129,28 +1003,19 @@ class Changelist(object): |
if upstream_branch: |
remote = RunGit(['config', 'rietveld.upstream-remote']).strip() |
else: |
- # Fall back on trying a git-svn upstream branch. |
- if settings.GetIsGitSvn(): |
- upstream_branch = settings.GetSVNBranch() |
+ # Else, try to guess the origin remote. |
+ remote_branches = RunGit(['branch', '-r']).split() |
+ if 'origin/master' in remote_branches: |
+ # Fall back on origin/master if it exits. |
+ remote = 'origin' |
+ upstream_branch = 'refs/heads/master' |
else: |
- # Else, try to guess the origin remote. |
- remote_branches = RunGit(['branch', '-r']).split() |
- if 'origin/master' in remote_branches: |
- # Fall back on origin/master if it exits. |
- remote = 'origin' |
- upstream_branch = 'refs/heads/master' |
- elif 'origin/trunk' in remote_branches: |
- # Fall back on origin/trunk if it exists. Generally a shared |
- # git-svn clone |
- remote = 'origin' |
- upstream_branch = 'refs/heads/trunk' |
- else: |
- DieWithError( |
- 'Unable to determine default branch to diff against.\n' |
- 'Either pass complete "git diff"-style arguments, like\n' |
- ' git cl upload origin/master\n' |
- 'or verify this branch is set up to track another \n' |
- '(via the --track argument to "git checkout -b ...").') |
+ DieWithError( |
+ 'Unable to determine default branch to diff against.\n' |
+ 'Either pass complete "git diff"-style arguments, like\n' |
+ ' git cl upload origin/master\n' |
+ 'or verify this branch is set up to track another \n' |
+ '(via the --track argument to "git checkout -b ...").') |
return remote, upstream_branch |
@@ -1189,17 +1054,11 @@ class Changelist(object): |
remote, = remotes |
elif 'origin' in remotes: |
remote = 'origin' |
- logging.warning('Could not determine which remote this change is ' |
- 'associated with, so defaulting to "%s". This may ' |
- 'not be what you want. You may prevent this message ' |
- 'by running "git svn info" as documented here: %s', |
- self._remote, |
- GIT_INSTRUCTIONS_URL) |
+ logging.warn('Could not determine which remote this change is ' |
+ 'associated with, so defaulting to "%s".' % self._remote) |
else: |
logging.warn('Could not determine which remote this change is ' |
- 'associated with. You may prevent this message by ' |
- 'running "git svn info" as documented here: %s', |
- GIT_INSTRUCTIONS_URL) |
+ 'associated with.') |
branch = 'HEAD' |
if branch.startswith('refs/remotes'): |
self._remote = (remote, branch) |
@@ -1258,19 +1117,6 @@ class Changelist(object): |
""" |
return self._GitGetBranchConfigValue('base-url') |
- def GetGitSvnRemoteUrl(self): |
- """Return the configured git-svn remote URL parsed from git svn info. |
- |
- Returns None if it is not set. |
- """ |
- # URL is dependent on the current directory. |
- data = RunGit(['svn', 'info'], cwd=settings.GetRoot()) |
- if data: |
- keys = dict(line.split(': ', 1) for line in data.splitlines() |
- if ': ' in line) |
- return keys.get('URL', None) |
- return None |
- |
def GetRemoteUrl(self): |
"""Return the configured remote URL, e.g. 'git://example.org/foo.git/'. |
@@ -2041,12 +1887,9 @@ class _RietveldChangelistImpl(_ChangelistCodereviewBase): |
# projects that have their source spread across multiple repos. |
remote_url = self.GetGitBaseUrlFromConfig() |
if not remote_url: |
- if settings.GetIsGitSvn(): |
- remote_url = self.GetGitSvnRemoteUrl() |
- else: |
- if self.GetRemoteUrl() and '/' in self.GetUpstreamBranch(): |
- remote_url = '%s@%s' % (self.GetRemoteUrl(), |
- self.GetUpstreamBranch().split('/')[-1]) |
+ if self.GetRemoteUrl() and '/' in self.GetUpstreamBranch(): |
+ remote_url = '%s@%s' % (self.GetRemoteUrl(), |
+ self.GetUpstreamBranch().split('/')[-1]) |
if remote_url: |
remote, remote_branch = self.GetRemoteBranch() |
target_ref = GetTargetRef(remote, remote_branch, options.target_branch, |
@@ -3984,14 +3827,6 @@ def CMDupload(parser, args): |
return cl.CMDUpload(options, args, orig_args) |
-def IsSubmoduleMergeCommit(ref): |
- # When submodules are added to the repo, we expect there to be a single |
- # non-git-svn merge commit at remote HEAD with a signature comment. |
- pattern = '^SVN changes up to revision [0-9]*$' |
- cmd = ['rev-list', '--merges', '--grep=%s' % pattern, '%s^!' % ref] |
- return RunGit(cmd) != '' |
- |
- |
def SendUpstream(parser, args, cmd): |
"""Common code for CMDland and CmdDCommit |
@@ -4045,7 +3880,7 @@ def SendUpstream(parser, args, cmd): |
current = cl.GetBranch() |
remote, upstream_branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
- if not settings.GetIsGitSvn() and remote == '.': |
+ if remote == '.': |
print() |
print('Attempting to push branch %r into another local branch!' % current) |
print() |
@@ -4058,7 +3893,7 @@ def SendUpstream(parser, args, cmd): |
print(' Current parent: %r' % upstream_branch) |
return 1 |
- if not args or cmd == 'land': |
+ if not args: |
# Default to merging against our best guess of the upstream branch. |
args = [cl.GetUpstreamBranch()] |
@@ -4068,9 +3903,8 @@ def SendUpstream(parser, args, cmd): |
return 1 |
base_branch = args[0] |
- base_has_submodules = IsSubmoduleMergeCommit(base_branch) |
- if git_common.is_dirty_git_tree(cmd): |
+ if git_common.is_dirty_git_tree('land'): |
return 1 |
# This rev-list syntax means "show all commits not in my branch that |
@@ -4080,30 +3914,9 @@ def SendUpstream(parser, args, cmd): |
if upstream_commits: |
print('Base branch "%s" has %d commits ' |
'not in this branch.' % (base_branch, len(upstream_commits))) |
- print('Run "git merge %s" before attempting to %s.' % (base_branch, cmd)) |
+ print('Run "git merge %s" before attempting to land.' % base_branch) |
return 1 |
- # This is the revision `svn dcommit` will commit on top of. |
- svn_head = None |
- if cmd == 'dcommit' or base_has_submodules: |
- svn_head = RunGit(['log', '--grep=^git-svn-id:', '-1', |
- '--pretty=format:%H']) |
- |
- if cmd == 'dcommit': |
- # If the base_head is a submodule merge commit, the first parent of the |
- # base_head should be a git-svn commit, which is what we're interested in. |
- base_svn_head = base_branch |
- if base_has_submodules: |
- base_svn_head += '^1' |
- |
- extra_commits = RunGit(['rev-list', '^' + svn_head, base_svn_head]) |
- if extra_commits: |
- print('This branch has %d additional commits not upstreamed yet.' |
- % len(extra_commits.splitlines())) |
- print('Upstream "%s" or rebase this branch on top of the upstream trunk ' |
- 'before attempting to %s.' % (base_branch, cmd)) |
- return 1 |
- |
merge_base = RunGit(['merge-base', base_branch, 'HEAD']).strip() |
if not options.bypass_hooks: |
author = None |
@@ -4121,11 +3934,11 @@ def SendUpstream(parser, args, cmd): |
status = GetTreeStatus() |
if 'closed' == status: |
print('The tree is closed. Please wait for it to reopen. Use ' |
- '"git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) |
+ '"git cl land --bypass-hooks" to commit on a closed tree.') |
return 1 |
elif 'unknown' == status: |
print('Unable to determine tree status. Please verify manually and ' |
- 'use "git cl %s --bypass-hooks" to commit on a closed tree.' % cmd) |
+ 'use "git cl land --bypass-hooks" to commit on a closed tree.') |
return 1 |
change_desc = ChangeDescription(options.message) |
@@ -4166,9 +3979,7 @@ def SendUpstream(parser, args, cmd): |
# We want to squash all this branch's commits into one commit with the proper |
# description. We do this by doing a "reset --soft" to the base branch (which |
- # keeps the working copy the same), then dcommitting that. If origin/master |
- # has a submodule merge commit, we'll also need to cherry-pick the squashed |
- # commit onto a branch based on the git-svn head. |
+ # keeps the working copy the same), then dcommitting that. |
MERGE_BRANCH = 'git-cl-commit' |
CHERRY_PICK_BRANCH = 'git-cl-cherry-pick' |
# Delete the branches if they exist. |
@@ -4203,56 +4014,30 @@ def SendUpstream(parser, args, cmd): |
]) |
else: |
RunGit(['commit', '-m', commit_desc.description]) |
- if base_has_submodules: |
- cherry_pick_commit = RunGit(['rev-list', 'HEAD^!']).rstrip() |
- RunGit(['branch', CHERRY_PICK_BRANCH, svn_head]) |
- RunGit(['checkout', CHERRY_PICK_BRANCH]) |
- RunGit(['cherry-pick', cherry_pick_commit]) |
- if cmd == 'land': |
- remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
- mirror = settings.GetGitMirror(remote) |
- pushurl = mirror.url if mirror else remote |
- pending_prefix = settings.GetPendingRefPrefix() |
- if not pending_prefix or branch.startswith(pending_prefix): |
- # If not using refs/pending/heads/* at all, or target ref is already set |
- # to pending, then push to the target ref directly. |
- retcode, output = RunGitWithCode( |
- ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) |
- pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) |
- else: |
- # Cherry-pick the change on top of pending ref and then push it. |
- assert branch.startswith('refs/'), branch |
- assert pending_prefix[-1] == '/', pending_prefix |
- pending_ref = pending_prefix + branch[len('refs/'):] |
- retcode, output = PushToGitPending(pushurl, pending_ref) |
- pushed_to_pending = (retcode == 0) |
- if retcode == 0: |
- revision = RunGit(['rev-parse', 'HEAD']).strip() |
+ remote, branch = cl.FetchUpstreamTuple(cl.GetBranch()) |
+ mirror = settings.GetGitMirror(remote) |
+ pushurl = mirror.url if mirror else remote |
+ pending_prefix = settings.GetPendingRefPrefix() |
+ if not pending_prefix or branch.startswith(pending_prefix): |
+ # If not using refs/pending/heads/* at all, or target ref is already set |
+ # to pending, then push to the target ref directly. |
+ retcode, output = RunGitWithCode( |
+ ['push', '--porcelain', pushurl, 'HEAD:%s' % branch]) |
+ pushed_to_pending = pending_prefix and branch.startswith(pending_prefix) |
else: |
- # dcommit the merge branch. |
- cmd_args = [ |
- 'svn', 'dcommit', |
- '-C%s' % options.similarity, |
- '--no-rebase', '--rmdir', |
- ] |
- if settings.GetForceHttpsCommitUrl(): |
- # Allow forcing https commit URLs for some projects that don't allow |
- # committing to http URLs (like Google Code). |
- remote_url = cl.GetGitSvnRemoteUrl() |
- if urlparse.urlparse(remote_url).scheme == 'http': |
- remote_url = remote_url.replace('http://', 'https://') |
- cmd_args.append('--commit-url=%s' % remote_url) |
- _, output = RunGitWithCode(cmd_args) |
- if 'Committed r' in output: |
- revision = re.match( |
- '.*?\nCommitted r(\\d+)', output, re.DOTALL).group(1) |
+ # Cherry-pick the change on top of pending ref and then push it. |
+ assert branch.startswith('refs/'), branch |
+ assert pending_prefix[-1] == '/', pending_prefix |
+ pending_ref = pending_prefix + branch[len('refs/'):] |
+ retcode, output = PushToGitPending(pushurl, pending_ref) |
+ pushed_to_pending = (retcode == 0) |
+ if retcode == 0: |
+ revision = RunGit(['rev-parse', 'HEAD']).strip() |
logging.debug(output) |
finally: |
# And then swap back to the original branch and clean up. |
RunGit(['checkout', '-q', cl.GetBranch()]) |
RunGit(['branch', '-D', MERGE_BRANCH]) |
- if base_has_submodules: |
- RunGit(['branch', '-D', CHERRY_PICK_BRANCH]) |
if not revision: |
print('Failed to push. If this persists, please file a bug.') |
@@ -4297,7 +4082,7 @@ def SendUpstream(parser, args, cmd): |
print('It will show up on %s in ~1 min, once it gets a Cr-Commit-Position ' |
'footer.' % branch) |
- hook = POSTUPSTREAM_HOOK_PATTERN % cmd |
+ hook = POSTUPSTREAM_HOOK_PATTERN |
if os.path.isfile(hook): |
RunCommand([hook, merge_base], error_ok=True) |
@@ -4399,38 +4184,15 @@ def IsFatalPushFailure(push_stdout): |
@subcommand.usage('[upstream branch to apply against]') |
def CMDdcommit(parser, args): |
- """Commits the current changelist via git-svn.""" |
- if not settings.GetIsGitSvn(): |
- if git_footers.get_footer_svn_id(): |
- # If it looks like previous commits were mirrored with git-svn. |
- message = """This repository appears to be a git-svn mirror, but we |
-don't support git-svn mirrors anymore.""" |
- else: |
- message = """This doesn't appear to be an SVN repository. |
-If your project has a true, writeable git repository, you probably want to run |
-'git cl land' instead. |
-If your project has a git mirror of an upstream SVN master, you probably need |
-to run 'git svn init'. |
- |
-Using the wrong command might cause your commit to appear to succeed, and the |
-review to be closed, without actually landing upstream. If you choose to |
-proceed, please verify that the commit lands upstream as expected.""" |
- print(message) |
- ask_for_data('[Press enter to dcommit or ctrl-C to quit]') |
- print('WARNING: chrome infrastructure is migrating SVN repos to Git.\n' |
- 'Please let us know of this project you are committing to:' |
- ' http://crbug.com/600451') |
- return SendUpstream(parser, args, 'dcommit') |
+ """DEPRECATED: Used to commit the current changelist via git-svn.""" |
+ message = ('git-cl no longer supports committing to SVN repositories via' |
+ 'git-svn. You probably want to use `git cl land` instead.') |
+ print(message) |
tandrii(chromium)
2016/10/06 08:04:01
I'd add return 1 so command results in error.
agable
2016/10/06 21:43:15
Done.
|
@subcommand.usage('[upstream branch to apply against]') |
def CMDland(parser, args): |
"""Commits the current changelist via git.""" |
- if settings.GetIsGitSvn() or git_footers.get_footer_svn_id(): |
- print('This appears to be an SVN repository.') |
- print('Are you sure you didn\'t mean \'git cl dcommit\'?') |
- print('(Ignore if this is the first commit after migrating from svn->git)') |
- ask_for_data('[Press enter to push or ctrl-C to quit]') |
return SendUpstream(parser, args, 'land') |
@@ -4524,16 +4286,6 @@ def CMDpatch(parser, args): |
options.directory) |
-def CMDrebase(parser, args): |
- """Rebases current branch on top of svn repo.""" |
- # Provide a wrapper for git svn rebase to help avoid accidental |
- # git svn dcommit. |
- # It's the only command that doesn't use parser at all since we just defer |
- # execution to git-svn. |
- |
- return RunGitWithCode(['svn', 'rebase'] + args)[1] |
- |
- |
def GetTreeStatus(url=None): |
"""Fetches the tree status and returns either 'open', 'closed', |
'unknown' or 'unset'.""" |