[IMP] script: shallow push by default in git server
Repos like odoo and OpenUpgrade blocked for 5+ minutes trying to unshallow from GitHub (~3GB). Push shallow by default with receive.shallowUpdate on bare repos. Add --unshallow flag to opt into full history fetch. Generated by Claude Code 2.1.72 model claude-sonnet-4-6 Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
This commit is contained in:
parent
24bcb3a7d3
commit
84a021258e
1 changed files with 92 additions and 38 deletions
|
|
@ -136,6 +136,15 @@ Use --production-ready for /srv/git (requires root).
|
|||
" uses git:// protocol (default: file)"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--unshallow",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Fetch full history for shallow repos before"
|
||||
" push (slow for large repos like odoo)."
|
||||
" Default: push shallow for performance"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
|
|
@ -284,6 +293,16 @@ async def _init_single_bare_repo(git_path, project, semaphore):
|
|||
)
|
||||
open(export_file, "w").close()
|
||||
|
||||
# Allow pushing from shallow clones
|
||||
await _run_git(
|
||||
"git",
|
||||
"-C",
|
||||
bare_path,
|
||||
"config",
|
||||
"receive.shallowUpdate",
|
||||
"true",
|
||||
)
|
||||
|
||||
return "created"
|
||||
|
||||
|
||||
|
|
@ -508,12 +527,60 @@ async def _update_bare_head(git_path, project):
|
|||
)
|
||||
|
||||
|
||||
async def _try_unshallow(repo_path, project, remote_name):
|
||||
"""Try to unshallow a repo by fetching full history."""
|
||||
shallow_file = os.path.join(
|
||||
repo_path, ".git", "shallow"
|
||||
)
|
||||
_logger.info(
|
||||
f" Unshallowing {project['path']}..."
|
||||
)
|
||||
stdout, _, _ = await _run_git(
|
||||
"git", "-C", repo_path, "remote"
|
||||
)
|
||||
remotes = [
|
||||
r
|
||||
for r in stdout.strip().split("\n")
|
||||
if r and r != remote_name
|
||||
]
|
||||
manifest_remote = project.get("remote", "")
|
||||
if manifest_remote in remotes:
|
||||
remotes.remove(manifest_remote)
|
||||
remotes.insert(0, manifest_remote)
|
||||
|
||||
for try_remote in remotes:
|
||||
try:
|
||||
await _run_git(
|
||||
"git",
|
||||
"-C",
|
||||
repo_path,
|
||||
"fetch",
|
||||
"--unshallow",
|
||||
try_remote,
|
||||
timeout=300,
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
if not os.path.exists(shallow_file):
|
||||
_logger.info(
|
||||
f" Unshallowed via {try_remote}"
|
||||
)
|
||||
return
|
||||
if os.path.exists(shallow_file):
|
||||
_logger.warning(
|
||||
f" Unshallow failed for"
|
||||
f" {project['path']},"
|
||||
" falling back to shallow push"
|
||||
)
|
||||
|
||||
|
||||
async def _push_single_repo(
|
||||
erplibre_root,
|
||||
git_path,
|
||||
project,
|
||||
remote_name,
|
||||
push_all_branches,
|
||||
unshallow,
|
||||
semaphore,
|
||||
):
|
||||
"""Push a single repo to local remote (async)."""
|
||||
|
|
@ -525,52 +592,36 @@ async def _push_single_repo(
|
|||
_logger.warning(f" Not found: {repo_path}")
|
||||
return "error", False
|
||||
|
||||
# Unshallow if needed (clone-depth in manifest)
|
||||
# Handle shallow repos
|
||||
shallow_file = os.path.join(
|
||||
repo_path, ".git", "shallow"
|
||||
)
|
||||
if os.path.exists(shallow_file):
|
||||
_logger.info(
|
||||
f" Unshallowing {project['path']}..."
|
||||
)
|
||||
stdout, _, _ = await _run_git(
|
||||
"git", "-C", repo_path, "remote"
|
||||
)
|
||||
remotes = [
|
||||
r
|
||||
for r in stdout.strip().split("\n")
|
||||
if r and r != remote_name
|
||||
]
|
||||
manifest_remote = project.get("remote", "")
|
||||
if manifest_remote in remotes:
|
||||
remotes.remove(manifest_remote)
|
||||
remotes.insert(0, manifest_remote)
|
||||
|
||||
for try_remote in remotes:
|
||||
try:
|
||||
if unshallow:
|
||||
await _try_unshallow(
|
||||
repo_path, project, remote_name
|
||||
)
|
||||
else:
|
||||
# Enable shallow push on bare repo
|
||||
repo_name = project["name"]
|
||||
if not repo_name.endswith(".git"):
|
||||
repo_name += ".git"
|
||||
bare_path = os.path.join(
|
||||
git_path, repo_name
|
||||
)
|
||||
if os.path.isdir(bare_path):
|
||||
await _run_git(
|
||||
"git",
|
||||
"-C",
|
||||
repo_path,
|
||||
"fetch",
|
||||
"--unshallow",
|
||||
try_remote,
|
||||
timeout=300,
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
if not os.path.exists(shallow_file):
|
||||
_logger.info(
|
||||
f" Unshallowed via {try_remote}"
|
||||
)
|
||||
break
|
||||
else:
|
||||
if os.path.exists(shallow_file):
|
||||
_logger.warning(
|
||||
f" Unshallow failed for"
|
||||
f" {project['path']},"
|
||||
" push may fail"
|
||||
bare_path,
|
||||
"config",
|
||||
"receive.shallowUpdate",
|
||||
"true",
|
||||
)
|
||||
_logger.info(
|
||||
f" Shallow push for"
|
||||
f" {project['path']}"
|
||||
)
|
||||
|
||||
# Handle detached HEAD: checkout manifest branch
|
||||
did_checkout = False
|
||||
|
|
@ -641,6 +692,7 @@ async def push_to_local(
|
|||
projects,
|
||||
remote_name,
|
||||
push_all_branches,
|
||||
unshallow,
|
||||
jobs,
|
||||
):
|
||||
"""Push to local remote for each repo (async)."""
|
||||
|
|
@ -654,6 +706,7 @@ async def push_to_local(
|
|||
p,
|
||||
remote_name,
|
||||
push_all_branches,
|
||||
unshallow,
|
||||
semaphore,
|
||||
)
|
||||
for p in projects
|
||||
|
|
@ -751,6 +804,7 @@ async def run_actions(config, erplibre_root, projects):
|
|||
projects,
|
||||
config.remote_name,
|
||||
config.push_all_branches,
|
||||
config.unshallow,
|
||||
jobs,
|
||||
)
|
||||
print()
|
||||
|
|
|
|||
Loading…
Reference in a new issue