generated from coulomb/repo-seed
fix(consistency): correct behind-remote detection to not trigger on local-ahead
_detect_behind_remote was comparing HEAD != @{u} which incorrectly
triggered C-16 when the local repo had unpushed commits. Fixed to use
git rev-list --count HEAD..@{u} which only counts commits the remote
has that local lacks. Adds test_returns_false_when_local_ahead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -748,8 +748,10 @@ def _check_ghost_duplicates(
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _detect_behind_remote(repo_path: str) -> bool:
|
def _detect_behind_remote(repo_path: str) -> bool:
|
||||||
"""Return True if the local repo is behind its remote tracking branch.
|
"""Return True if the remote tracking branch has commits the local repo lacks.
|
||||||
|
|
||||||
|
"Ahead" (local has unpushed commits) is NOT considered behind.
|
||||||
|
"Diverged" is treated as behind (remote progress could be lost).
|
||||||
Best-effort: returns False on any error (offline, no remote, etc.) so that
|
Best-effort: returns False on any error (offline, no remote, etc.) so that
|
||||||
check-only mode is never blocked by network issues.
|
check-only mode is never blocked by network issues.
|
||||||
"""
|
"""
|
||||||
@@ -758,15 +760,15 @@ def _detect_behind_remote(repo_path: str) -> bool:
|
|||||||
["git", "-C", repo_path, "fetch", "--quiet", "origin"],
|
["git", "-C", repo_path, "fetch", "--quiet", "origin"],
|
||||||
capture_output=True, timeout=15,
|
capture_output=True, timeout=15,
|
||||||
)
|
)
|
||||||
local = subprocess.run(
|
# Count commits in remote that are not in local.
|
||||||
["git", "-C", repo_path, "rev-parse", "HEAD"],
|
# git rev-list HEAD..@{u} → commits remote has that local lacks.
|
||||||
|
result = subprocess.run(
|
||||||
|
["git", "-C", repo_path, "rev-list", "--count", "HEAD..@{u}"],
|
||||||
capture_output=True, text=True, timeout=5,
|
capture_output=True, text=True, timeout=5,
|
||||||
).stdout.strip()
|
)
|
||||||
remote = subprocess.run(
|
if result.returncode != 0:
|
||||||
["git", "-C", repo_path, "rev-parse", "@{u}"],
|
return False # no upstream configured or other error
|
||||||
capture_output=True, text=True, timeout=5,
|
return int(result.stdout.strip() or "0") > 0
|
||||||
).stdout.strip()
|
|
||||||
return bool(local and remote and local != remote)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -450,6 +450,26 @@ class TestDetectBehindRemote:
|
|||||||
subprocess.run(["git", "-C", str(clone), "push", "origin", "HEAD"], capture_output=True)
|
subprocess.run(["git", "-C", str(clone), "push", "origin", "HEAD"], capture_output=True)
|
||||||
assert _detect_behind_remote(str(clone)) is False
|
assert _detect_behind_remote(str(clone)) is False
|
||||||
|
|
||||||
|
def test_returns_false_when_local_ahead(self, tmp_path):
|
||||||
|
"""Local has unpushed commits — NOT considered behind."""
|
||||||
|
import subprocess
|
||||||
|
bare = tmp_path / "bare.git"
|
||||||
|
clone = tmp_path / "clone"
|
||||||
|
bare.mkdir()
|
||||||
|
subprocess.run(["git", "init", "--bare", str(bare)], capture_output=True)
|
||||||
|
subprocess.run(["git", "clone", str(bare), str(clone)], capture_output=True)
|
||||||
|
subprocess.run(
|
||||||
|
["git", "-C", str(clone), "commit", "--allow-empty", "-m", "init"],
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
subprocess.run(["git", "-C", str(clone), "push", "origin", "HEAD:main"], capture_output=True)
|
||||||
|
# Add a local-only commit (not pushed)
|
||||||
|
subprocess.run(
|
||||||
|
["git", "-C", str(clone), "commit", "--allow-empty", "-m", "local only"],
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
assert _detect_behind_remote(str(clone)) is False
|
||||||
|
|
||||||
def test_returns_true_when_behind(self, tmp_path):
|
def test_returns_true_when_behind(self, tmp_path):
|
||||||
"""Remote has a commit the clone doesn't → clone is behind."""
|
"""Remote has a commit the clone doesn't → clone is behind."""
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|||||||
Reference in New Issue
Block a user