Skip to content

Commit

Permalink
scm, git: fix update to non tracked yet branches
Browse files Browse the repository at this point in the history
If branch is not tracked locally, one need to create a reference
while fetching the new revision.
In this case, fetch info flags has NEW_HEAD bit set.

While fetching a new head, only switch to the newly created ref is needed.
  • Loading branch information
fvalette-ledger committed Oct 11, 2024
1 parent 7f22142 commit 51adc34
Showing 1 changed file with 23 additions and 6 deletions.
29 changes: 23 additions & 6 deletions src/outpost/barbican/scm/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: Apache-2.0

from git import Repo, RemoteProgress
from git import Repo, RemoteProgress, FetchInfo
from git.exc import InvalidGitRepositoryError, NoSuchPathError

from ..logger import logger
Expand All @@ -28,6 +28,7 @@ class GitProgressBar(RemoteProgress):
]

OP_CODE_MAP = {getattr(RemoteProgress, _op_code): _op_code for _op_code in OP_CODES}
print(OP_CODE_MAP)

def __init__(self) -> None:
super().__init__()
Expand Down Expand Up @@ -160,9 +161,19 @@ def clone(self) -> None:
def fetch(self) -> None:
logger.info(f"git fetch {self.name} origin/{self.revision}")

fetch_infos = self._repo.remotes.origin.fetch(
refspec=self.revision, progress=GitProgressBar()
) # type: ignore
refspec = self.revision
if not self.is_hex_sha(self.revision):
# As we cloned in single branch, on update, one may change to a not fetched yet reference
# Git need to bound this ref in local repo w/ same name, so fetch w/ refspec=<rev>:<rev>
is_new_ref = True
for ref in self._repo.heads:
if self.revision in ref.name:
is_new_ref = False
break
if is_new_ref:
refspec += ":" + refspec

fetch_infos = self._repo.remote().fetch(refspec=refspec)

# this should never occurs
if len(fetch_infos) != 1:
Expand All @@ -175,8 +186,14 @@ def fetch(self) -> None:
else:
if self._repo.head.is_detached or self._repo.active_branch != self.revision:
self._repo.git.switch(self.revision)
self._reset_head(str(fetch_info.commit))
self._reset(str(fetch_info.commit))

# XXX:
# If a new Head is fetched, switch on new ref is sufficient
# Moreover, fetch info does not have any commit reference yet
# the the following will fail. Thus, skip this step in this case.
if not fetch_info.flags & FetchInfo.NEW_HEAD:
self._reset_head(str(fetch_info.commit))
self._reset(str(fetch_info.commit))

def clean(self) -> None:
logger.info(f"git clean {self.name}")
Expand Down

0 comments on commit 51adc34

Please sign in to comment.