diff --git a/svn_mirror/gitea.py b/svn_mirror/gitea.py index 0d1a5d2..e3ffe4d 100644 --- a/svn_mirror/gitea.py +++ b/svn_mirror/gitea.py @@ -116,9 +116,9 @@ def fetch_from_gitea(mirror: Mirror, ref: Optional[str] = None) -> bool: canonical = str(mirror.canonical_dir) if ref: - refspec = f"+{ref}:{ref}" + refspec = f"+{ref}:refs/remotes/gitea/{ref.removeprefix('refs/heads/')}" else: - refspec = "+refs/heads/*:refs/heads/*" + refspec = "+refs/heads/*:refs/remotes/gitea/*" logger.info("Fetching %s → canonical …", gitea_path) _git( @@ -128,4 +128,44 @@ def fetch_from_gitea(mirror: Mirror, ref: Optional[str] = None) -> bool: ) logger.debug("Fetch from Gitea complete") + + # Fast-forward local branches from remote-tracking refs + if not ref: + _ff_local_branches(canonical) + return True + + +def _ff_local_branches(git_dir: str): + """Fast-forward ``refs/heads/*`` from ``refs/remotes/gitea/*``.""" + out = _git("--git-dir", git_dir, "for-each-ref", + "--format=%(refname)", "refs/remotes/gitea/", + timeout=30, check=False) + for rt_ref in out.splitlines(): + rt_ref = rt_ref.strip() + if not rt_ref: + continue + branch = rt_ref.removeprefix("refs/remotes/gitea/") + local_ref = f"refs/heads/{branch}" + + # Check if local branch exists + local_hash = _git("--git-dir", git_dir, "rev-parse", "--verify", + "--quiet", local_ref, timeout=15, check=False) + if not local_hash: + _git("--git-dir", git_dir, "update-ref", local_ref, rt_ref, + timeout=15) + logger.debug("Created new branch %s from Gitea", local_ref) + continue + + # Fast-forward if possible + rt_hash = _git("--git-dir", git_dir, "rev-parse", "--verify", + rt_ref, timeout=15, check=False) + if not rt_hash or rt_hash == local_hash: + continue + + base = _git("--git-dir", git_dir, "merge-base", local_hash, rt_ref, + timeout=15, check=False) + if base == local_hash: + _git("--git-dir", git_dir, "update-ref", local_ref, rt_ref, + timeout=15) + logger.debug("Fast-forward %s from Gitea", local_ref)