fix(update): preserve archive metadata in git checkouts

- Skip expanded archive metadata when updating Git worktrees
- Retain commit metadata for archive-only installations
- Cover repositories, linked worktrees, and packaged installs
This commit is contained in:
DazedAnon 2026-07-25 08:27:43 -05:00
parent 0a618c5608
commit 33038978cc
2 changed files with 64 additions and 1 deletions

View file

@ -131,6 +131,20 @@ class UpdateThread(QThread):
return False
return True
@classmethod
def should_install_to_root(cls, rel: Path, root: Path) -> bool:
"""Return True when *rel* may be copied into the selected install root.
Git expands ``.git_archival.txt`` while creating a source archive. Keep
that expanded file in archive-only installs, but do not copy it back
into a live checkout where it would dirty the worktree on every update.
"""
if not cls.should_install(rel):
return False
if rel.as_posix() == ".git_archival.txt" and (root / ".git").exists():
return False
return True
@classmethod
def resolve_archive_root(cls, extract_dir: Path) -> Path:
"""Locate the single top-level folder inside an extracted archive.
@ -281,7 +295,11 @@ class UpdateThread(QThread):
install_files = [
src
for src in extracted.rglob("*")
if src.is_file() and self.should_install(src.relative_to(extracted))
if src.is_file()
and self.should_install_to_root(
src.relative_to(extracted),
root,
)
]
if not install_files:
raise RuntimeError(

View file

@ -68,6 +68,51 @@ class UpdateThreadInstallFilterTests(unittest.TestCase):
with self.subTest(rel=rel):
self.assertFalse(UpdateThread.should_install(Path(rel)))
def test_preserves_archive_metadata_in_git_checkout(self):
from gui.main import UpdateThread
with tempfile.TemporaryDirectory() as raw:
root = Path(raw)
(root / ".git").mkdir()
self.assertFalse(
UpdateThread.should_install_to_root(
Path(".git_archival.txt"),
root,
)
)
self.assertTrue(
UpdateThread.should_install_to_root(Path("gui/main.py"), root)
)
def test_preserves_archive_metadata_with_git_file(self):
"""Linked worktrees and submodules use a .git file, not a directory."""
from gui.main import UpdateThread
with tempfile.TemporaryDirectory() as raw:
root = Path(raw)
(root / ".git").write_text("gitdir: elsewhere\n", encoding="utf-8")
self.assertFalse(
UpdateThread.should_install_to_root(
Path(".git_archival.txt"),
root,
)
)
def test_installs_archive_metadata_outside_git_checkout(self):
from gui.main import UpdateThread
with tempfile.TemporaryDirectory() as raw:
root = Path(raw)
self.assertTrue(
UpdateThread.should_install_to_root(
Path(".git_archival.txt"),
root,
)
)
class UpdateThreadArchiveRootTests(unittest.TestCase):
"""Gitea zips nest files under a single top folder (repo display name)."""