This commit is contained in:
2026-05-27 23:24:12 +03:00
parent d2c60c87e2
commit 477e30a9f2
36 changed files with 1348 additions and 306 deletions

View File

@@ -8,6 +8,7 @@ import os
from fastapi import HTTPException
from git import Repo
from git.exc import GitCommandError
from src.core.logger import belief_scope, logger
@@ -173,12 +174,60 @@ class GitServiceBranchMixin:
# @PURPOSE: Switch to a specific branch (concurrent-safe).
# @PRE Repository exists and the specified branch name exists.
# @POST The repository working directory is updated to the specified branch.
# @SIDE_EFFECT May raise HTTPException(409) if local changes conflict with checkout.
# @SIDE_EFFECT May raise HTTPException(500) if Git operation fails for other reasons.
def checkout_branch(self, dashboard_id: int, name: str):
with self._locked(dashboard_id):
with belief_scope("GitService.checkout_branch"):
repo = self.get_repo(dashboard_id)
logger.reason(f"Checking out branch {name}", extra={"src": "checkout_branch"})
repo.git.checkout(name)
try:
repo.git.checkout(name)
except GitCommandError as e:
stderr = str(e.stderr or "")
details = str(e)
lowered = stderr.lower()
if "local changes" in lowered or "would be overwritten" in lowered:
# Parse the list of files from stderr
files = []
for line in stderr.split("\n"):
stripped = line.strip()
if stripped.startswith("\t") and (
stripped.endswith(".yaml") or "/" in stripped
):
files.append(stripped.strip())
raise HTTPException(
status_code=409,
detail={
"error_code": "GIT_CHECKOUT_LOCAL_CHANGES",
"message": (
f"Невозможно переключиться на ветку '{name}'"
f"локальные изменения будут перезаписаны. "
f"Зафиксируйте или отложите изменения."
),
"message_en": (
f"Cannot checkout branch '{name}'"
f"local changes would be overwritten. "
f"Commit or stash your changes first."
),
"files": files,
"next_steps": [
"Зафиксируйте изменения (Commit) в текущей ветке перед переключением",
"Отложите изменения через Stash (вручную: git stash)",
"Отмените локальные изменения, если они не нужны",
],
"next_steps_en": [
"Commit your changes in the current branch before switching",
"Stash your changes manually: git stash",
"Discard local changes if not needed",
],
},
)
logger.error(f"[checkout_branch][Coherence:Failed] {e}")
raise HTTPException(
status_code=500,
detail=f"Git checkout failed: {details}",
)
# endregion checkout_branch
# region commit_changes [C:4] [TYPE Function] [SEMANTICS git,commit,stage,lock]