Commit 7dc11449 authored by agable@chromium.org's avatar agable@chromium.org

Fix GitCheckout to be sane and use git-cache

The commit queue uses checkout.GitCheckout to manage the
local git repository. It resets it to a clean state,
commits patches locally, and pushes those changes to the
golden-source-of-truth repo.

This CL fixes the prepare() method to use the new git-cache
tool, and in the process makes it more consistent, more
readable, and more correct. It also makes minor changes to
other methods to bring them in line with the git-cache
approach.

R=iannucci@chromium.org, rmistry@chromium.org
BUG=261619

Review URL: https://codereview.chromium.org/175873003

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@256681 0039d316-1c4b-4281-b951-d872f2087c98
parent 99f9c92f
......@@ -566,66 +566,46 @@ class GitCheckout(CheckoutBase):
# remote branch.
self.working_branch = 'working_branch'
# There is no reason to not hardcode origin.
self.remote = 'origin'
# There is no reason to not hardcode master.
self.master_branch = 'master'
self.pull_remote = 'origin'
self.push_remote = 'upstream'
def prepare(self, revision):
"""Resets the git repository in a clean state.
Checks it out if not present and deletes the working branch.
"""
assert self.remote_branch
assert self.git_url
assert self.remote_branch
self._check_call_git(
['cache', 'populate', self.git_url], timeout=FETCH_TIMEOUT, cwd=None)
cache_path = self._check_output_git(
['cache', 'exists', self.git_url], cwd=None).strip()
if not os.path.isdir(self.project_path):
# Clone the repo if the directory is not present.
logging.info(
'Checking out %s in %s', self.project_name, self.project_path)
self._check_call_git(
['clone', self.git_url, '-b', self.remote_branch, self.project_path],
['clone', '--shared', cache_path, self.project_path],
cwd=None, timeout=FETCH_TIMEOUT)
else:
# Throw away all uncommitted changes in the existing checkout.
self._check_call_git(['checkout', self.remote_branch])
self._check_call_git(
['reset', '--hard', '--quiet',
'%s/%s' % (self.remote, self.remote_branch)])
self._call_git(
['config', 'remote.%s.url' % self.push_remote, self.git_url],
cwd=self.project_path)
if not revision:
revision = self.remote_branch
if not re.match(r'[0-9a-f]{40}$', revision, flags=re.IGNORECASE):
self._check_call_git(['fetch', self.pull_remote, revision])
revision = self.pull_remote + '/' + revision
if revision:
try:
# Look if the commit hash already exist. If so, we can skip a
# 'git fetch' call.
revision = self._check_output_git(['rev-parse', revision])
except subprocess.CalledProcessError:
self._check_call_git(
['fetch', self.remote, self.remote_branch, '--quiet'])
revision = self._check_output_git(['rev-parse', revision])
self._check_call_git(['checkout', '--force', '--quiet', revision])
else:
branches, active = self._branches()
if active != self.master_branch:
self._check_call_git(
['checkout', '--force', '--quiet', self.master_branch])
self._sync_remote_branch()
self._call_git(['clean', '-fdx'])
branches, _ = self._branches()
if self.working_branch in branches:
self._call_git(['branch', '-D', self.working_branch])
return self._get_head_commit_hash()
def _sync_remote_branch(self):
"""Syncs the remote branch."""
# We do a 'git pull origin master:refs/remotes/origin/master' instead of
# 'git pull origin master' because from the manpage for git-pull:
# A parameter <ref> without a colon is equivalent to <ref>: when
# pulling/fetching, so it merges <ref> into the current branch without
# storing the remote branch anywhere locally.
remote_tracked_path = 'refs/remotes/%s/%s' % (
self.remote, self.remote_branch)
self._check_call_git(
['pull', self.remote,
'%s:%s' % (self.remote_branch, remote_tracked_path),
'--quiet'])
return self._get_head_commit_hash()
def _get_head_commit_hash(self):
"""Gets the current revision (in unicode) from the local branch."""
......@@ -720,8 +700,7 @@ class GitCheckout(CheckoutBase):
if self.base_ref:
base_ref = self.base_ref
else:
base_ref = '%s/%s' % (self.remote,
self.remote_branch or self.master_branch)
base_ref = '%s/%s' % (self.pull_remote, self.remote_branch)
found_files = self._check_output_git(
['diff', base_ref,
'--name-only']).splitlines(False)
......@@ -748,13 +727,16 @@ class GitCheckout(CheckoutBase):
# Push to the remote repository.
self._check_call_git(
['push', 'origin', '%s:%s' % (self.working_branch, self.remote_branch),
['push', self.push_remote,
'%s:%s' % (self.working_branch, self.remote_branch),
'--force', '--quiet'])
# Get the revision after the push.
revision = self._get_head_commit_hash()
# Switch back to the remote_branch and sync it.
self._check_call_git(['checkout', self.remote_branch])
self._sync_remote_branch()
# Switch back to the remote_branch.
self._check_call_git(['cache', 'populate', self.git_url])
self._check_call_git(['fetch', self.pull_remote])
self._check_call_git(['checkout', '--force', '--quiet',
'%s/%s' % (self.pull_remote, self.remote_branch)])
# Delete the working branch since we are done with it.
self._check_call_git(['branch', '-D', self.working_branch])
......@@ -794,7 +776,7 @@ class GitCheckout(CheckoutBase):
"""Returns the number of actual commits between both hash."""
self._fetch_remote()
rev2 = rev2 or '%s/%s' % (self.remote, self.remote_branch)
rev2 = rev2 or '%s/%s' % (self.pull_remote, self.remote_branch)
# Revision range is ]rev1, rev2] and ordering matters.
try:
out = self._check_output_git(
......@@ -806,7 +788,7 @@ class GitCheckout(CheckoutBase):
def _fetch_remote(self):
"""Fetches the remote without rebasing."""
# git fetch is always verbose even with -q, so redirect its output.
self._check_output_git(['fetch', self.remote, self.remote_branch],
self._check_output_git(['fetch', self.pull_remote, self.remote_branch],
timeout=FETCH_TIMEOUT)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment