chore(coding-agent/ipy): removed git utility functions from prelude
- Removed 7 git utility functions and internal _git() wrapper from IPython prelude.
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
- Removed git utility functions (_git, git_status, git_diff, git_log, git_show, git_file_at, git_branch, git_has_changes) from IPython prelude
|
||||
## [8.2.0] - 2026-01-24
|
||||
|
||||
### Added
|
||||
|
||||
@@ -724,188 +724,6 @@ if "__omp_prelude_loaded__" not in globals():
|
||||
_emit_status("insert_at", path=str(p), line=line_num, lines_inserted=len(new_lines), position=pos)
|
||||
return p
|
||||
|
||||
def _git(*args: str, cwd: str | Path | None = None) -> tuple[int, str, str]:
|
||||
"""Run git command, return (returncode, stdout, stderr)."""
|
||||
result = subprocess.run(
|
||||
["git", *args],
|
||||
cwd=str(cwd) if cwd else None,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
return result.returncode, result.stdout, result.stderr
|
||||
|
||||
@_category("Git")
|
||||
def git_status(*, cwd: str | Path | None = None) -> dict:
|
||||
"""Get structured git status: {branch, staged, modified, untracked, ahead, behind}."""
|
||||
code, out, err = _git("status", "--porcelain=v2", "--branch", cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_status", error=err.strip())
|
||||
return {}
|
||||
|
||||
result: dict = {"branch": None, "staged": [], "modified": [], "untracked": [], "ahead": 0, "behind": 0}
|
||||
for line in out.splitlines():
|
||||
if line.startswith("# branch.head "):
|
||||
result["branch"] = line.split(" ", 2)[2]
|
||||
elif line.startswith("# branch.ab "):
|
||||
parts = line.split()
|
||||
for p in parts[2:]:
|
||||
if p.startswith("+"):
|
||||
result["ahead"] = int(p[1:])
|
||||
elif p.startswith("-"):
|
||||
result["behind"] = int(p[1:])
|
||||
elif line.startswith("1 ") or line.startswith("2 "):
|
||||
parts = line.split(" ", 8)
|
||||
xy = parts[1]
|
||||
path = parts[-1]
|
||||
if xy[0] != ".":
|
||||
result["staged"].append(path)
|
||||
if xy[1] != ".":
|
||||
result["modified"].append(path)
|
||||
elif line.startswith("? "):
|
||||
result["untracked"].append(line[2:])
|
||||
|
||||
clean = not any([result["staged"], result["modified"], result["untracked"]])
|
||||
_emit_status("git_status", branch=result["branch"], staged=len(result["staged"]), modified=len(result["modified"]), untracked=len(result["untracked"]), clean=clean, files=result["staged"][:5] + result["modified"][:5])
|
||||
return result
|
||||
|
||||
@_category("Git")
|
||||
def git_diff(
|
||||
*paths: str,
|
||||
staged: bool = False,
|
||||
ref: str | None = None,
|
||||
stat: bool = False,
|
||||
cwd: str | Path | None = None,
|
||||
) -> str:
|
||||
"""Show git diff. staged=True for --cached, ref for commit comparison."""
|
||||
args = ["diff"]
|
||||
if stat:
|
||||
args.append("--stat")
|
||||
if staged:
|
||||
args.append("--cached")
|
||||
if ref:
|
||||
args.append(ref)
|
||||
if paths:
|
||||
args.append("--")
|
||||
args.extend(paths)
|
||||
code, out, err = _git(*args, cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_diff", error=err.strip())
|
||||
return ""
|
||||
lines_count = len(out.splitlines()) if out else 0
|
||||
_emit_status("git_diff", staged=staged, ref=ref, lines=lines_count, preview=out[:500])
|
||||
return out
|
||||
|
||||
@_category("Git")
|
||||
def git_log(
|
||||
n: int = 10,
|
||||
*,
|
||||
oneline: bool = True,
|
||||
ref_range: str | None = None,
|
||||
paths: list[str] | None = None,
|
||||
cwd: str | Path | None = None,
|
||||
) -> list[dict]:
|
||||
"""Get git log as list of {sha, subject, author, date}."""
|
||||
fmt = "%H%x00%s%x00%an%x00%aI" if not oneline else "%h%x00%s%x00%an%x00%aI"
|
||||
args = ["log", f"-{n}", f"--format={fmt}"]
|
||||
if ref_range:
|
||||
args.append(ref_range)
|
||||
if paths:
|
||||
args.append("--")
|
||||
args.extend(paths)
|
||||
code, out, err = _git(*args, cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_log", error=err.strip())
|
||||
return []
|
||||
|
||||
commits = []
|
||||
for line in out.strip().splitlines():
|
||||
parts = line.split("\x00")
|
||||
if len(parts) >= 4:
|
||||
commits.append({"sha": parts[0], "subject": parts[1], "author": parts[2], "date": parts[3]})
|
||||
|
||||
_emit_status("git_log", commits=len(commits), entries=[{"sha": c["sha"][:8], "subject": c["subject"][:50]} for c in commits[:5]])
|
||||
return commits
|
||||
|
||||
@_category("Git")
|
||||
def git_show(ref: str = "HEAD", *, stat: bool = True, cwd: str | Path | None = None) -> dict:
|
||||
"""Show commit details as {sha, subject, author, date, body, files}."""
|
||||
args = ["show", ref, "--format=%H%x00%s%x00%an%x00%aI%x00%b", "--no-patch"]
|
||||
code, out, err = _git(*args, cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_show", ref=ref, error=err.strip())
|
||||
return {}
|
||||
|
||||
parts = out.strip().split("\x00")
|
||||
result = {
|
||||
"sha": parts[0] if len(parts) > 0 else "",
|
||||
"subject": parts[1] if len(parts) > 1 else "",
|
||||
"author": parts[2] if len(parts) > 2 else "",
|
||||
"date": parts[3] if len(parts) > 3 else "",
|
||||
"body": parts[4].strip() if len(parts) > 4 else "",
|
||||
"files": [],
|
||||
}
|
||||
|
||||
if stat:
|
||||
_, stat_out, _ = _git("show", ref, "--stat", "--format=", cwd=cwd)
|
||||
result["files"] = [l.strip() for l in stat_out.strip().splitlines() if l.strip()]
|
||||
|
||||
_emit_status("git_show", ref=ref, sha=result["sha"][:12], subject=result["subject"][:60], files=len(result["files"]))
|
||||
return result
|
||||
|
||||
@_category("Git")
|
||||
def git_file_at(ref: str, path: str, *, lines: tuple[int, int] | None = None, cwd: str | Path | None = None) -> str:
|
||||
"""Get file content at ref. Optional lines=(start, end) for range (1-indexed)."""
|
||||
code, out, err = _git("show", f"{ref}:{path}", cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_file_at", ref=ref, path=path, error=err.strip())
|
||||
return ""
|
||||
|
||||
if lines:
|
||||
all_lines = out.splitlines()
|
||||
start, end = lines
|
||||
start = max(1, start)
|
||||
end = min(len(all_lines), end)
|
||||
selected = all_lines[start - 1 : end]
|
||||
out = "\n".join(selected)
|
||||
_emit_status("git_file_at", ref=ref, path=path, start=start, end=end, lines=len(selected))
|
||||
return out
|
||||
|
||||
_emit_status("git_file_at", ref=ref, path=path, chars=len(out))
|
||||
return out
|
||||
|
||||
@_category("Git")
|
||||
def git_branch(*, cwd: str | Path | None = None) -> dict:
|
||||
"""Get branches: {current, local, remote}."""
|
||||
code, out, _ = _git("branch", "-a", "--format=%(refname:short)%00%(HEAD)", cwd=cwd)
|
||||
if code != 0:
|
||||
_emit_status("git_branch", error="failed to list branches")
|
||||
return {"current": None, "local": [], "remote": []}
|
||||
|
||||
result: dict = {"current": None, "local": [], "remote": []}
|
||||
for line in out.strip().splitlines():
|
||||
parts = line.split("\x00")
|
||||
name = parts[0]
|
||||
is_current = len(parts) > 1 and parts[1] == "*"
|
||||
if is_current:
|
||||
result["current"] = name
|
||||
if name.startswith("remotes/") or "/" in name and not name.startswith("feature/"):
|
||||
result["remote"].append(name)
|
||||
else:
|
||||
result["local"].append(name)
|
||||
if is_current:
|
||||
result["current"] = name
|
||||
|
||||
_emit_status("git_branch", current=result["current"], local=len(result["local"]), remote=len(result["remote"]), branches=result["local"][:10])
|
||||
return result
|
||||
|
||||
@_category("Git")
|
||||
def git_has_changes(*, cwd: str | Path | None = None) -> bool:
|
||||
"""Check if there are uncommitted changes (staged or unstaged)."""
|
||||
code, out, _ = _git("status", "--porcelain", cwd=cwd)
|
||||
has_changes = bool(out.strip())
|
||||
_emit_status("git_has_changes", has_changes=has_changes)
|
||||
return has_changes
|
||||
|
||||
@_category("Agent")
|
||||
def output(
|
||||
*ids: str,
|
||||
|
||||
Reference in New Issue
Block a user