Skip to content

Commit 51b257c

Browse files
committed
ignore mode-only changes during update
1 parent f3b4381 commit 51b257c

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

src/octopal/cli/main.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,26 @@ def _list_meaningful_worktree_changes(project_root: Path) -> list[str] | None:
301301
if stats.returncode != 0:
302302
return None
303303

304-
# `git diff --numstat` is empty for mode-only changes, so treat those as safe.
305-
if stats.stdout.strip():
304+
stats_lines = [line.strip() for line in stats.stdout.splitlines() if line.strip()]
305+
if not stats_lines:
306+
continue
307+
308+
is_meaningful = False
309+
for line in stats_lines:
310+
parts = line.split("\t")
311+
if len(parts) < 3:
312+
is_meaningful = True
313+
break
314+
315+
added, deleted = parts[0].strip(), parts[1].strip()
316+
if added == "0" and deleted == "0":
317+
continue
318+
319+
# Binary/content changes often show `-` counters and should still block update.
320+
is_meaningful = True
321+
break
322+
323+
if is_meaningful:
306324
changes.append(path)
307325

308326
return changes

tests/test_cli_update.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,30 @@ def fake_run_capture(command: list[str], *, cwd, timeout=10.0):
6262
if command == ["git", "diff", "--name-only"]:
6363
return subprocess.CompletedProcess(command, 0, stdout="scripts/bootstrap.sh\n", stderr="")
6464
if command == ["git", "diff", "--numstat", "--", "scripts/bootstrap.sh"]:
65-
return subprocess.CompletedProcess(command, 0, stdout="", stderr="")
65+
return subprocess.CompletedProcess(command, 0, stdout="0\t0\tscripts/bootstrap.sh\n", stderr="")
6666
raise AssertionError(f"unexpected command: {command}")
6767

6868
monkeypatch.setattr("octopal.cli.main.shutil.which", lambda _name: "/usr/bin/git")
6969
monkeypatch.setattr("octopal.cli.main._run_capture", fake_run_capture)
7070

7171
assert _git_checkout_ready_for_update(tmp_path) == (True, None)
72+
73+
74+
def test_git_checkout_ready_blocks_real_content_changes(monkeypatch, tmp_path) -> None:
75+
(tmp_path / ".git").mkdir()
76+
77+
def fake_run_capture(command: list[str], *, cwd, timeout=10.0):
78+
if command == ["git", "status", "--porcelain"]:
79+
return subprocess.CompletedProcess(command, 0, stdout=" M scripts/bootstrap.sh\n", stderr="")
80+
if command == ["git", "diff", "--name-only"]:
81+
return subprocess.CompletedProcess(command, 0, stdout="scripts/bootstrap.sh\n", stderr="")
82+
if command == ["git", "diff", "--numstat", "--", "scripts/bootstrap.sh"]:
83+
return subprocess.CompletedProcess(command, 0, stdout="3\t1\tscripts/bootstrap.sh\n", stderr="")
84+
raise AssertionError(f"unexpected command: {command}")
85+
86+
monkeypatch.setattr("octopal.cli.main.shutil.which", lambda _name: "/usr/bin/git")
87+
monkeypatch.setattr("octopal.cli.main._run_capture", fake_run_capture)
88+
89+
ok, reason = _git_checkout_ready_for_update(tmp_path)
90+
assert ok is False
91+
assert "scripts/bootstrap.sh" in str(reason)

0 commit comments

Comments
 (0)