fix(update): clear a stale .git/index.lock before Update Code (#801)

* fix(update): clear a stale .git/index.lock before Update Code

A git that subprocess.run's timeout kills (SIGKILL) cannot remove
.git/index.lock, so every later update failed with "Unable to create
.../.git/index.lock: File exists" until the file was removed by hand.

Update Code and the automatic update's rollback now remove the lock when
no git process is running in the checkout and the file is more than a
few seconds old. While another git is running, Update Code says so
instead of failing; when the lock could not be checked, the error names
the rm command that fixes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk

* fix(update): count a git that names the checkout in its arguments as running

git --git-dir/--work-tree can work on the checkout from any working
directory, so the cwd check alone could take such a git's live lock for
a stale one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk

* fix(update): resolve a git's relative path arguments against its cwd

`git -C LEDMatrix ...` or a relative --git-dir started outside the
checkout works on it too; resolve each argument against the process's
working directory before deciding a lock is stale, and count unreadable
arguments as naming the checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SvFtgthKUNEPhJu6RuX9Sk

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-10-26 20:13:40 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 4c883ec2c2
commit fa51ebab5f
6 changed files with 389 additions and 2 deletions
+12 -1
View File
@@ -332,7 +332,16 @@ def channel_status(project_dir=None, fetch=True):
def _perform_core_update_locked(stash_local_changes=True):
project_dir = str(PROJECT_ROOT)
from web_interface import update_channel
from web_interface import update_channel, git_index_lock
# A git killed mid-command (a timed-out pull, a power cut) leaves
# .git/index.lock behind, and every later update then fails with
# "Unable to create .../index.lock: File exists". Remove it when no git
# process can still own it; refuse while one is running.
if git_index_lock.clear_stale_index_lock(project_dir) == git_index_lock.IN_USE:
return {'status': 'error', 'restart_required': False, 'dependency_failures': [],
'message': 'Another git command is running in the LEDMatrix folder; '
'try again in a minute.'}
# Which code to move to: the newest release (stable) or main (beta).
# See web_interface/update_channel.py; it never picks an older commit.
@@ -554,6 +563,8 @@ def _perform_core_update_locked(stash_local_changes=True):
detail = next((ln.strip() for ln in (result.stderr or '').splitlines()
if ln.strip()), '')
pull_message = f"Update failed: {detail}" if detail else "Update failed; check logs for details"
if 'index.lock' in (result.stderr or ''):
pull_message = f"{pull_message} {git_index_lock.manual_fix_hint(project_dir)}"
# Nothing here restarts anything: the pull replaces files on
# disk while the display and web services keep running the code