fix: use git fetch from Gitea side to transfer objects + update refs without triggering pre-receive hook
This commit is contained in:
+37
-35
@@ -4,7 +4,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from .mirror import Mirror
|
from .mirror import Mirror
|
||||||
|
|
||||||
@@ -52,10 +52,11 @@ def _git(*args: str, timeout: int = 300, check: bool = True) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def push_to_gitea(mirror: Mirror) -> bool:
|
def push_to_gitea(mirror: Mirror) -> bool:
|
||||||
"""Sync canonical refs to Gitea's bare repo via direct ref updates.
|
"""Sync canonical → Gitea via ``git fetch`` from Gitea's side.
|
||||||
|
|
||||||
Uses ``git update-ref`` to bypass Gitea's pre-receive hook, then
|
``git fetch`` transfers objects + updates refs without triggering
|
||||||
fires Gitea's ``post-receive`` hook manually so the UI refreshes.
|
Gitea's ``pre-receive`` hook, then fires ``post-receive`` manually
|
||||||
|
for the UI to refresh.
|
||||||
|
|
||||||
Returns True if anything changed.
|
Returns True if anything changed.
|
||||||
"""
|
"""
|
||||||
@@ -66,49 +67,50 @@ def push_to_gitea(mirror: Mirror) -> bool:
|
|||||||
|
|
||||||
canonical = str(mirror.canonical_dir)
|
canonical = str(mirror.canonical_dir)
|
||||||
|
|
||||||
# Collect canonical refs
|
# Grab old refs so we can detect what changed
|
||||||
out = _git("--git-dir", canonical, "for-each-ref",
|
old_refs: Dict[str, str] = {}
|
||||||
|
out = _git("--git-dir", str(gitea_path), "for-each-ref",
|
||||||
"--format=%(objectname) %(refname)",
|
"--format=%(objectname) %(refname)",
|
||||||
"refs/heads/", "refs/tags/",
|
"refs/heads/", "refs/tags/",
|
||||||
timeout=30, check=False)
|
timeout=30, check=False)
|
||||||
canonical_refs: Dict[str, str] = {}
|
|
||||||
for line in (out or "").splitlines():
|
for line in (out or "").splitlines():
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
obj_hash, ref = line.split(None, 1)
|
h, r = line.split(None, 1)
|
||||||
canonical_refs[ref] = obj_hash
|
old_refs[r] = h
|
||||||
|
|
||||||
|
# Gitea fetches from canonical — this transfers objects + refs,
|
||||||
|
# and DOES NOT trigger Gitea's pre-receive hook.
|
||||||
|
_git(
|
||||||
|
"--git-dir", str(gitea_path), "fetch", "--prune",
|
||||||
|
canonical,
|
||||||
|
"+refs/heads/*:refs/heads/*",
|
||||||
|
"+refs/tags/*:refs/tags/*",
|
||||||
|
timeout=300,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build the changelist for post-receive
|
||||||
changed: list = []
|
changed: list = []
|
||||||
for ref, obj_hash in canonical_refs.items():
|
cur_refs: dict = {}
|
||||||
gitea_hash = _git("--git-dir", str(gitea_path), "rev-parse",
|
out = _git("--git-dir", str(gitea_path), "for-each-ref",
|
||||||
"--verify", "--quiet", ref,
|
"--format=%(objectname) %(refname)",
|
||||||
timeout=15, check=False)
|
"refs/heads/", "refs/tags/",
|
||||||
if obj_hash != gitea_hash:
|
timeout=30, check=False)
|
||||||
if gitea_hash:
|
for line in (out or "").splitlines():
|
||||||
_git("--git-dir", str(gitea_path), "update-ref", ref,
|
|
||||||
obj_hash, gitea_hash, timeout=15)
|
|
||||||
else:
|
|
||||||
_git("--git-dir", str(gitea_path), "update-ref", ref,
|
|
||||||
obj_hash, timeout=15)
|
|
||||||
changed.append((gitea_hash or "0" * 40, obj_hash, ref))
|
|
||||||
logger.debug("Updated %s in Gitea", ref)
|
|
||||||
|
|
||||||
# Prune refs in Gitea not in canonical
|
|
||||||
gitea_out = _git("--git-dir", str(gitea_path), "for-each-ref",
|
|
||||||
"--format=%(objectname) %(refname)",
|
|
||||||
"refs/heads/", "refs/tags/",
|
|
||||||
timeout=30, check=False)
|
|
||||||
for line in (gitea_out or "").splitlines():
|
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
obj_hash, ref = line.split(None, 1)
|
h, r = line.split(None, 1)
|
||||||
if ref not in canonical_refs:
|
cur_refs[r] = h
|
||||||
_git("--git-dir", str(gitea_path), "update-ref", "-d", ref,
|
old = old_refs.get(r, "0" * 40)
|
||||||
obj_hash, timeout=15)
|
if h != old:
|
||||||
changed.append((obj_hash, "0" * 40, ref))
|
changed.append((old, h, r))
|
||||||
logger.debug("Pruned %s from Gitea", ref)
|
|
||||||
|
# Detect deletions (refs present before fetch but gone now)
|
||||||
|
for r, old_h in old_refs.items():
|
||||||
|
if r not in cur_refs:
|
||||||
|
changed.append((old_h, "0" * 40, r))
|
||||||
|
|
||||||
if not changed:
|
if not changed:
|
||||||
logger.debug("No new commits to push to Gitea")
|
logger.debug("No new commits to push to Gitea")
|
||||||
|
|||||||
Reference in New Issue
Block a user