diff --git a/gclient_scm.py b/gclient_scm.py index 9bd2b8c176..c91d592fa2 100644 --- a/gclient_scm.py +++ b/gclient_scm.py @@ -501,6 +501,9 @@ class GitWrapper(SCMWrapper): if ':' in revision: revision_ref, _, revision = revision.partition(':') + if revision_ref.startswith('refs/branch-heads'): + options.with_branch_heads = True + mirror = self._GetMirror(url, options, revision_ref) if mirror: url = mirror.mirror_path diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py index 81cc233298..fae7a08c26 100755 --- a/tests/gclient_scm_test.py +++ b/tests/gclient_scm_test.py @@ -981,6 +981,79 @@ class CipdWrapperTestCase(unittest.TestCase): scm.update(None, (), []) +class BranchHeadsFakeRepo(fake_repos.FakeReposBase): + def populateGit(self): + # Creates a tree that looks like this: + # + # 5 refs/branch-heads/5 + # | + # 4 + # | + # 1--2--3 refs/heads/master + self._commit_git('repo_1', {'commit 1': 'touched'}) + self._commit_git('repo_1', {'commit 2': 'touched'}) + self._commit_git('repo_1', {'commit 3': 'touched'}) + self._create_ref('repo_1', 'refs/heads/master', 3) + + self._commit_git('repo_1', {'commit 4': 'touched'}, base=2) + self._commit_git('repo_1', {'commit 5': 'touched'}, base=2) + self._create_ref('repo_1', 'refs/branch-heads/5', 5) + + +class BranchHeadsTest(fake_repos.FakeReposTestBase): + FAKE_REPOS_CLASS = BranchHeadsFakeRepo + + def setUp(self): + super(BranchHeadsTest, self).setUp() + self.enabled = self.FAKE_REPOS.set_up_git() + self.options = BaseGitWrapperTestCase.OptionsObject() + self.url = self.git_base + 'repo_1' + self.mirror = None + mock.patch('sys.stdout').start() + self.addCleanup(mock.patch.stopall) + + def setUpMirror(self): + self.mirror = tempfile.mkdtemp('mirror') + git_cache.Mirror.SetCachePath(self.mirror) + self.addCleanup(gclient_utils.rmtree, self.mirror) + self.addCleanup(git_cache.Mirror.SetCachePath, None) + + def testCheckoutBranchHeads(self): + scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.') + file_list = [] + + self.options.revision = 'refs/branch-heads/5' + scm.update(self.options, None, file_list) + self.assertEqual(self.githash('repo_1', 5), self.gitrevparse(self.root_dir)) + + def testCheckoutUpdatedBranchHeads(self): + # Travel back in time, and set refs/branch-heads/5 to its parent. + subprocess2.check_call( + ['git', 'update-ref', 'refs/branch-heads/5', self.githash('repo_1', 4)], + cwd=self.url) + + # Sync to refs/branch-heads/5 + scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.') + self.options.revision = 'refs/branch-heads/5' + scm.update(self.options, None, []) + + # Set refs/branch-heads/5 back to its original value. + subprocess2.check_call( + ['git', 'update-ref', 'refs/branch-heads/5', self.githash('repo_1', 5)], + cwd=self.url) + + # Attempt to sync to refs/branch-heads/5 again. + self.testCheckoutBranchHeads() + + def testCheckoutBranchHeadsMirror(self): + self.setUpMirror() + self.testCheckoutBranchHeads() + + def testCheckoutUpdatedBranchHeadsMirror(self): + self.setUpMirror() + self.testCheckoutUpdatedBranchHeads() + + class GerritChangesFakeRepo(fake_repos.FakeReposBase): def populateGit(self): # Creates a tree that looks like this: