Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2639)

Unified Diff: git_cl.py

Issue 11262057: git_cl sanity checks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: git_cl.py
diff --git a/git_cl.py b/git_cl.py
index 21ade2a28e9987cfdc76425e64f8f0f027b6b1e6..f65d11ce5c5c79d89a0c6558113523cbe37005fd 100755
--- a/git_cl.py
+++ b/git_cl.py
@@ -163,6 +163,7 @@ def is_dirty_git_tree(cmd):
return True
return False
+
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|.
@@ -426,12 +427,12 @@ class Changelist(object):
self.GetBranch() # Poke the lazy loader.
return self.branchref
- def FetchUpstreamTuple(self):
+ @staticmethod
+ def FetchUpstreamTuple(branch):
"""Returns a tuple containg remote and remote ref,
e.g. 'origin', 'refs/heads/master'
"""
remote = '.'
- branch = self.GetBranch()
upstream_branch = RunGit(['config', 'branch.%s.merge' % branch],
error_ok=True).strip()
if upstream_branch:
@@ -468,22 +469,28 @@ or verify this branch is set up to track another (via the --track argument to
def GetUpstreamBranch(self):
if self.upstream_branch is None:
- remote, upstream_branch = self.FetchUpstreamTuple()
+ remote, upstream_branch = self.FetchUpstreamTuple(self.GetBranch())
if remote is not '.':
upstream_branch = upstream_branch.replace('heads', 'remotes/' + remote)
self.upstream_branch = upstream_branch
return self.upstream_branch
- def GetRemote(self):
+ def GetRemoteBranch(self):
if not self._remote:
- self._remote = self.FetchUpstreamTuple()[0]
- if self._remote == '.':
-
+ remote, branch = None, self.GetBranch()
+ seen_branches = set()
+ while branch not in seen_branches:
+ seen_branches.add(branch)
+ remote, branch = self.FetchUpstreamTuple(branch)
+ branch = ShortBranchName(branch)
+ if remote != '.' or branch.startswith('refs/remotes'):
+ break
+ else:
remotes = RunGit(['remote'], error_ok=True).split()
if len(remotes) == 1:
- self._remote, = remotes
+ remote, = remotes
elif 'origin' in remotes:
- self._remote = 'origin'
+ 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 '
@@ -495,8 +502,48 @@ or verify this branch is set up to track another (via the --track argument to
'associated with. You may prevent this message by '
'running "git svn info" as documented here: %s',
GIT_INSTRUCTIONS_URL)
+ branch = 'HEAD'
+ if branch.startswith('refs/remotes'):
+ self._remote = (remote, branch)
+ else:
+ self._remote = (remote, 'refs/remotes/%s/%s' % (remote, branch))
return self._remote
+ def GitSanityChecks(self, upstream_git_obj):
+ """Checks git repo status and ensures diff is from local commits."""
+
+ # Verify the commit we're diffing against is in our current branch.
+ upstream_sha = RunGit(['rev-parse', '--verify', upstream_git_obj]).strip()
+ common_ancestor = RunGit(['merge-base', upstream_sha, 'HEAD']).strip()
+ if upstream_sha != common_ancestor:
+ print >> sys.stderr, (
+ 'ERROR: %s is not in the current branch. You may need to rebase '
+ 'your tracking branch' % upstream_sha)
+ return False
+
+ # List the commits inside the diff, and verify they are all local.
+ commits_in_diff = RunGit(
+ ['rev-list', '^%s' % upstream_sha, 'HEAD']).splitlines()
+ code, remote_branch = RunGitWithCode(['config', 'gitcl.remotebranch'])
+ remote_branch = remote_branch.strip()
+ if code != 0:
+ _, remote_branch = self.GetRemoteBranch()
+
+ commits_in_remote = RunGit(
+ ['rev-list', '^%s' % upstream_sha, remote_branch]).splitlines()
+
+ common_commits = set(commits_in_diff) & set(commits_in_remote)
+ if common_commits:
+ print >> sys.stderr, (
+ 'ERROR: Your diff contains %d commits already in %s.\n'
+ 'Run "git log --oneline %s..HEAD" to get a list of commits in '
+ 'the diff. If you are using a custom git flow, you can override'
+ ' the reference used for this check with "git config '
+ 'gitcl.remotebranch <git-ref>".' % (
+ len(common_commits), remote_branch, upstream_git_obj))
+ return False
+ return True
+
def GetGitBaseUrlFromConfig(self):
"""Return the configured base URL from branch.<branchname>.baseurl.
@@ -510,7 +557,7 @@ or verify this branch is set up to track another (via the --track argument to
Returns None if there is no remote.
"""
- remote = self.GetRemote()
+ remote, _ = self.GetRemoteBranch()
return RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip()
def GetIssue(self):
@@ -607,6 +654,9 @@ or verify this branch is set up to track another (via the --track argument to
self.has_issue = False
def GetChange(self, upstream_branch, author):
+ if not self.GitSanityChecks(upstream_branch):
+ DieWithError('\nGit sanity check failure')
+
root = RunCommand(['git', 'rev-parse', '--show-cdup']).strip() or '.'
absroot = os.path.abspath(root)
@@ -1018,8 +1068,8 @@ def CMDpresubmit(parser, args):
if args:
base_branch = args[0]
else:
- # Default to diffing against the "upstream" branch.
- base_branch = cl.GetUpstreamBranch()
+ # Default to diffing against the common ancestor of the upstream branch.
+ base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip()
cl.RunHook(committing=not options.upload, upstream_branch=base_branch,
may_prompt=False, verbose=options.verbose,
@@ -1216,9 +1266,9 @@ def CMDupload(parser, args):
# TODO(ukai): is it ok for gerrit case?
base_branch = args[0]
else:
- # Default to diffing against the "upstream" branch.
- base_branch = cl.GetUpstreamBranch()
- args = [base_branch + "..."]
+ # Default to diffing against common ancestor of upstream branch
+ base_branch = RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip()
+ args = [base_branch]
if not options.bypass_hooks:
hook_results = cl.RunHook(committing=False, upstream_branch=base_branch,
@@ -1310,6 +1360,7 @@ def SendUpstream(parser, args, cmd):
'before attempting to %s.' % (base_branch, cmd))
return 1
+ base_branch = RunGit(['merge-base', base_branch, 'HEAD']).strip()
if not options.bypass_hooks:
author = None
if options.contributor:
@@ -1403,7 +1454,7 @@ def SendUpstream(parser, args, cmd):
RunGit(['cherry-pick', cherry_pick_commit])
if cmd == 'push':
# push the merge branch.
- remote, branch = cl.FetchUpstreamTuple()
+ remote, branch = cl.FetchUpstreamTuple(cl.GetBranch())
retcode, output = RunGitWithCode(
['push', '--porcelain', remote, 'HEAD:%s' % branch])
logging.debug(output)
@@ -1656,7 +1707,9 @@ def CMDtry(parser, args):
# Process --bot and --testfilter.
if not options.bot:
# Get try slaves from PRESUBMIT.py files if not specified.
- change = cl.GetChange(cl.GetUpstreamBranch(), None)
+ change = cl.GetChange(
+ RunGit(['merge-base', cl.GetUpstreamBranch(), 'HEAD']).strip(),
+ None)
options.bot = presubmit_support.DoGetTrySlaves(
change,
change.LocalPaths(),
« no previous file with comments | « no previous file | tests/git_cl_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698