MirrorGitRepository: fix git-fetch failure when local HEAD is invalid
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 5 Mar 2014 12:04:57 +0000 (14:04 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 5 Mar 2014 12:35:49 +0000 (14:35 +0200)
Git fetch fails if local HEAD is a non-symbolic ref and points to a
non-existent object.

We get into this state in CachedRepo if the remote HEAD is invalid (e.g.
points to a non-existent branch) as we forcefully invalidate local HEAD
in this case, too.

Change-Id: I68dff3b4692bef0c3b5399f06c7097af1cf104b3
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp_repocache/__init__.py
tests/test_gbp_repocache.py

index ade3e89ca88f6417d500032aef9f210eba31803f..d1e009e83313866fd55d439b2deed4efd4758e12 100644 (file)
@@ -68,15 +68,22 @@ class MirrorGitRepository(GitRepository): # pylint: disable=R0904
 
     def force_fetch(self):
         """Fetch with specific arguments"""
+        # Set HEAD temporarily as fetch with an invalid non-symbolic HEAD fails
+        orig_head = self.get_ref('HEAD')
+        self.set_ref('HEAD', 'refs/heads/non-existent-tmp-for-fetching')
+
         # Update all refs
-        self._git_command('fetch', ['-q', '-u', '-p', 'origin'])
         try:
-            # Fetch remote HEAD separately
-            self._git_command('fetch', ['-q', '-u', 'origin', 'HEAD'])
-        except GitRepositoryError:
-            # If remote HEAD is invalid, invalidate FETCH_HEAD, too
-            self.set_ref('FETCH_HEAD',
-                         '0000000000000000000000000000000000000000')
+            self._git_command('fetch', ['-q', '-u', '-p', 'origin'])
+            try:
+                # Fetch remote HEAD separately
+                self._git_command('fetch', ['-q', '-u', 'origin', 'HEAD'])
+            except GitRepositoryError:
+                # If remote HEAD is invalid, invalidate FETCH_HEAD, too
+                self.set_ref('FETCH_HEAD',
+                             '0000000000000000000000000000000000000000')
+        finally:
+            self.set_ref('HEAD', orig_head)
 
     def force_checkout(self, commitish):
         """Checkout commitish"""
index 83a1342e9870aec111545174bbe9e28b04d7337f..aa68391e5a90dc70b44bb1a666a02460e1fa0bcc 100644 (file)
@@ -57,6 +57,28 @@ class TestMirrorGitRepository(UnitTestsBase):
         repo.set_ref('MY_REF', sha1)
         eq_(repo.get_ref('MY_REF'), sha1)
 
+    def test_force_fetch(self):
+        """Test fetching"""
+        repo = MirrorGitRepository.clone('testrepo', self.orig_repo.path)
+
+        # Make remote HEAD invalid
+        orig_branch = self.orig_repo.get_branch()
+        with open(os.path.join(self.orig_repo.git_dir, 'HEAD'), 'w') as head:
+            head.write('ref: refs/heads/non-existent-branch\n')
+
+        # Local HEAD should be invalid after fetch
+        repo.force_fetch()
+        eq_(repo.get_ref('FETCH_HEAD'),
+            '0000000000000000000000000000000000000000')
+
+        # Fetch should succeed even if local head is invalid
+        repo.set_ref('HEAD', '1234567890123456789012345678901234567890')
+        repo.force_fetch()
+        eq_(repo.get_ref('HEAD'), '1234567890123456789012345678901234567890')
+
+        # Restore orig repo HEAD
+        self.orig_repo.set_branch(orig_branch)
+
 
 class TestCachedRepo(UnitTestsBase):
     """Test CachedRepo class"""
@@ -163,6 +185,11 @@ class TestCachedRepo(UnitTestsBase):
         # Local HEAD should be invalid, now
         with assert_raises(CachedRepoError):
             repo.update_working_copy('HEAD')
+        repo.close()
+
+        # Init/fetch with invalid local HEAD should succeed
+        repo = self.MockCachedRepo(self.orig_repo.path)
+
         # Test valid refs, too
         ok_(repo.update_working_copy('master'))