Skip to content

Commit ffea84b

Browse files
codexByron
authored andcommitted
feat(gix): read reference logs natively
Implement reflog existence and GitPython's exact NUL-delimited read format with native log iteration. Preserve newest-first ordering, identity and raw timestamps while filtering unavailable/non-commit targets as Git does. Orphan log lookup, other formats and log writing remain with Git. The staged version passes Ruff and Python syntax checks. Its SHA-1/SHA-256 native smoke and focused pytest selection pass: 42 passed in 9.86s.
1 parent e2201f9 commit ffea84b

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

‎git/_backend.py‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,63 @@ def history(command: Any, rev: str, paths: Any, options: Dict[str, Any], *, coun
320320
return result
321321

322322

323+
def _date(signature: Any) -> bytes:
324+
offset = signature.time.offset
325+
hours, minutes = divmod(abs(offset) // 60, 60)
326+
return b"%d %s%02d%02d" % (signature.time.seconds, b"-" if offset < 0 else b"+", hours, minutes)
327+
328+
329+
def _reflog(repo: Any, args: List[str], kwargs: Dict[str, Any]) -> bytes:
330+
if len(args) == 3 and args[:2] == ["exists", "--"]:
331+
reference = repo.try_find_reference(args[-1])
332+
if reference is None:
333+
raise _Unsupported("orphan reflog lookup")
334+
if not reference.log_exists():
335+
raise GitCommandError(["git", "reflog", "exists"], 1)
336+
return b""
337+
if (
338+
len(args) != 10
339+
or args[:8]
340+
!= [
341+
"show",
342+
"--format=%H%x00%gn%x00%ge%x00%gD%x00%gs",
343+
"--date=raw",
344+
"-z",
345+
"--no-abbrev",
346+
"--no-decorate",
347+
"--no-notes",
348+
"--no-color",
349+
]
350+
or args[-1] != "--"
351+
):
352+
raise _Unsupported("reflog writing or format")
353+
reference = repo.try_find_reference(args[-2])
354+
if reference is None:
355+
raise _Unsupported("orphan reflog lookup")
356+
cursor = reference.log_iter().rev()
357+
if cursor is None:
358+
return b""
359+
output = []
360+
with cursor:
361+
for line in cursor:
362+
if not repo.has_object(line.new_oid) or repo.find_header(line.new_oid).kind() != "commit":
363+
continue
364+
signature = line.signature
365+
output.append(
366+
b"\0".join(
367+
[
368+
str(line.new_oid).encode("ascii"),
369+
signature.name,
370+
signature.email,
371+
os.fsencode(args[-2]) + b"@{" + _date(signature) + b"}",
372+
line.message,
373+
]
374+
)
375+
+ b"\0"
376+
)
377+
return b"".join(output)
378+
379+
323380
def _index(repo: Any, kwargs: Dict[str, Any]) -> Any:
324381
if not hasattr(repo, "index_or_empty"):
325382
raise _Unsupported("index feature disabled")
@@ -613,6 +670,7 @@ def _commit_tree(repo: Any, args: List[str], kwargs: Dict[str, Any]) -> bytes:
613670
"mktree": _mktree,
614671
"read_tree": _read_tree,
615672
"commit_tree": _commit_tree,
673+
"reflog": _reflog,
616674
"config": _config,
617675
"worktree": _worktree,
618676
}

0 commit comments

Comments
 (0)