From 6f8f67c22d965b02ec14a5dce8155d61d85a013a Mon Sep 17 00:00:00 2001 From: pretyflaco Date: Tue, 5 May 2026 12:36:46 +0300 Subject: [PATCH] chore(sync): rebase pull and push-only-when-ahead Two related defensive improvements to meet/sync.py: 1. Refuse to pull when the cloned sync repo has uncommitted changes, instead of silently swallowing a failed --ff-only pull. Surfaces manual edits in the sync clone before they get clobbered. 2. Switch the routine pull from --ff-only to --rebase so previously- created local meeting commits are preserved when the remote has moved on (e.g. another team member pushed concurrently). 3. After copying files, if there are no new file changes to commit but the local branch is ahead of the upstream (e.g. a previous sync run committed but then network failed before push), push those existing commits instead of returning early with 'already up to date'. No tests added; the sync module's surface is mostly subprocess-driven git plumbing with no existing test fixtures. --- meet/sync.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/meet/sync.py b/meet/sync.py index c7815d0..f41d278 100644 --- a/meet/sync.py +++ b/meet/sync.py @@ -238,6 +238,21 @@ def _run( return result +def _current_branch_ahead_count(repo: Path) -> int: + """Return how many local commits the current branch is ahead of upstream.""" + result = _run( + ["git", "rev-list", "--count", "@{upstream}..HEAD"], + cwd=repo, + check=False, + ) + if result.returncode != 0: + return 0 + try: + return int(result.stdout.strip() or "0") + except ValueError: + return 0 + + def _get_clone_dir() -> Path: """Return the local clone directory for the configured repo.""" config = load_sync_config() @@ -277,8 +292,15 @@ def _log(msg: str) -> None: _run(["git", "clone", repo_url, str(clone_dir)]) _log("Clone complete.") else: - # Pull latest - _run(["git", "pull", "--ff-only"], cwd=clone_dir, check=False) + status = _run(["git", "status", "--porcelain"], cwd=clone_dir) + if status.stdout.strip(): + raise RuntimeError( + f"Sync repo has uncommitted changes at {clone_dir}. " + "Commit, stash, or clean them before syncing." + ) + + # Pull latest, rebasing any previously-created local meeting commits. + _run(["git", "pull", "--rebase"], cwd=clone_dir) return clone_dir @@ -441,6 +463,14 @@ def _log(msg: str) -> None: # Check if there's anything to commit status = _run(["git", "status", "--porcelain"], cwd=repo) if not status.stdout.strip(): + ahead_count = _current_branch_ahead_count(repo) + if ahead_count: + _log(f" No new file changes, but {ahead_count} local commit(s) need pushing.") + _log(" Pushing...") + _run(["git", "push"], cwd=repo) + _log(f" Pushed {ahead_count} existing commit(s).") + return copied + _log(" Nothing to commit — already up to date.") return copied