fix(update): stop a timed-out git from leaving .git/index.lock behind

subprocess.run's timeout SIGKILLs only the direct git child, so the lock
is left behind and git's helpers are orphaned. On a slow SD card the same
pull then times out on every retry and recreates the lock, so removing it
by hand does not help.

- run_git starts git in its own session, stops the group with SIGTERM
  before SIGKILL, and clears the lock if nothing owns it. Update Code's
  pull, checkout, reset and stash go through it, with a 600s pull timeout.
- Read-only calls (describe --dirty, status, the update-check fetch) set
  GIT_OPTIONAL_LOCKS=0 so a timed-out poll cannot take the lock.
- A timed-out pull returns a clear error; a rebase left by an interrupted
  update is aborted before pulling.
- The manual-fix hint says to stop the services and kill running git.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-10-29 11:27:45 -04:00
co-authored by Claude Sonnet 5.5
parent fa51ebab5f
commit e506c1b576
8 changed files with 176 additions and 37 deletions
+3 -1
View File
@@ -24,6 +24,8 @@ import re
import subprocess # nosec B404 - list-form argv only, no shell # nosemgrep
from pathlib import Path
from web_interface import git_index_lock
PROJECT_ROOT = Path(__file__).resolve().parent.parent
CHANNELS = ('stable', 'beta')
DEFAULT_CHANNEL = 'stable'
@@ -105,7 +107,7 @@ class ChannelStatus(dict):
def _git(project_dir, run, *args, timeout=30):
run = run or subprocess.run
run = run or git_index_lock.run_git
return run(['git', *args], cwd=str(project_dir), capture_output=True, text=True, timeout=timeout)