You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8596f2e
Browse filesBrowse the repository at this point in the historyBrowse files
fix(refs): keep missing references from resolving to lookalike tags
<!-- agent -->
Fetching a valid tag named `refs/heads/unborn` stores it under
`refs/tags/refs/heads/unborn`. When `HEAD` names the absent
`refs/heads/unborn`, the CLI reference reader used `git rev-parse --verify`
and guessed that tag instead. `head.is_valid()` became true and
`IndexFile.commit()` gave the local initial commit a foreign parent. A tag
named `REBASE_HEAD` also made `Repo.currently_rebasing_on()` report a rebase.
Read direct references with `git show-ref --verify --hash` instead of
revision parsing. Probe `REBASE_HEAD` with `git show-ref --exists` to
distinguish absence from lookup errors, then use
`SymbolicReference.dereference_recursive()` and `Repo.commit()` so the rebase
reader shares exact lookup and symbolic-reference validation while retaining
recursive annotated-tag peeling.
Revision APIs intentionally retain Git's name guessing. Existing native Gix
reference reads are unchanged; root-reference existence and reftable retain
documented CLI fallbacks.
Independently written regressions fetch the misleading tags into an unborn
repository and cover SHA-1/SHA-256, files/reftable, forced CLI fallback,
parentless initial commits, and absent/present/deleted `REBASE_HEAD`.
Positive cases compare existing root refs, packed annotated tags, and detached
`HEAD` against Git. All 16 original regressions failed on the CLI baseline;
14 failed under Gix, whose files-based initial commits were already protected.
All 26 final reference regression cases pass on each backend. Post-commit
review found that `SymbolicReference.commit` peels only one annotated tag;
four new regressions failed with `TypeError` before switching to the existing
recursive commit resolver.
Broader validation exposed the existing GIX-17 grammar bug for this work
branch: Gix reads `2313-supersede` as blob
`23136a1d1dd1f02de7cde0f7b55f49d76ac77d55`, while Git reads the branch's
commit. Extend the existing conservative CLI grammar guard to hexadecimal
prefixes followed by a dash. A deterministic fixture verifies existing
`<blob-prefix>-topic` and missing `<blob-prefix>-missing` names; its test
fails before the guard and passes afterward. The GIX-17 ledger retains the
upstream bug as open and records the evidence and adapter fallback.
An additional exact-name check exposed GIX-33: when the root `REBASE_HEAD`
is absent and `refs/tags/REBASE_HEAD` is symbolic, Gix's partial lookup
returns that tag and native `symbolic_ref` dispatch follows its target.
Git's equivalent `symbolic-ref --quiet --no-recurse` exits 1. Compare the
returned native reference name with the requested bytes and retain CLI for
a lookalike. Two new SHA-1/SHA-256 regressions fail before the guard and
pass afterward, including forced CLI fallback. The ledger keeps this
compatibility bug open until Gix exposes a verified exact-name mode.
Final caller validation passes 98 CLI reference tests and 200 Gix
reference/backend tests, with 24 passing subtests each. The preceding
intermediate commit `9ddf778` also passed the full local suites: 1,969 CLI
tests and 2,072 Gix tests, with 85 passing subtests each. Earlier targeted
revision/installation checks passed 48 CLI tests and 50 Gix tests. Ruff
check/format, mypy, basedpyright, ShellCheck, and `git diff --check` pass.
Behavioral comparisons use `git version 2.54.0 (Apple Git-157)` and
`GixPython 0.3.0`. The Git reference checkout at
`6de20f6092dcf9bdb1c8efe03db4b70c82b423dd` documents exact lookup in
`Documentation/git-show-ref.adoc`, name guessing in
`Documentation/revisions.adoc`, and parentless root commits in
`Documentation/git-commit-tree.adoc`.
Source report and investigation: Keerthana-64's PR
#2313.
The replacement does not incorporate that PR's implementation or tests.
Assisted-by: GPT 6.1 Sol
Co-authored-by: GPT 6.1 Sol <codex@openai.com>
`Repository.rev_parse_single`, `Repository.rev_parse` and `RefEdit` APIs.
@@ -935,7 +949,7 @@ identify the historical fixture where needed.
935
949
| GIX-14 | Bug; missing API | For a linked worktree of a bare main repository, `is_bare()` returns true while `git rev-parse --is-bare-repository` returns false; `workdir()` does expose the worktree. Initial gitfile opening can retain a noncanonical target and use an arbitrary gitfile's location as the worktree, unlike Git. Discovery accepts undecodable HEADs until explicit `head()` decoding and ignores dangling `commondir` symlinks that Git rejects. Bindings flatten failure kinds into `gix.Error`. Windows also exposes adapter path-formatting differences and a worker panic on an undecodable `commondir`; see the Windows reproduction below. | Provide Git-compatible classification, canonical gitfile locations and layout validation, plus typed errors instead of panics. Format native locations compatibly with Git's command output. The adapter combines Gix metadata, reopens through Gix and forces HEAD decoding, retaining CLI for remaining validation/diagnostic gaps. Those workarounds do not close these compatibility bugs. A Git-strict mode must cover these cases; strict config and trust settings alone do not. |
936
950
| GIX-15 | Bug | Native blame disagrees with Git even with Myers and rewrite tracking selected. In the fixture's `README.md`, lines 150 and 158 are attributed to the opposite commits. Incremental order also differs. | Attribution and incremental-output parity before replacing `Repo.blame` / `blame_incremental`. |
937
951
| GIX-16 | Bug; missing API | Native archive streaming takes a tree rather than a commit. Its TAR omits Git's global PAX commit comment, leaves `export-subst` placeholders literal, and writes ordinary modes as `0644` where Git uses `0664`. | Commit-aware export substitution, metadata and permission parity. Both engines respected `export-ignore` in the probe. |
938
-
| GIX-17 | Bug | Revision parsing accepts abbreviated IDs with `-dirty`, prefers the OID suffix over an exact describe-shaped tag, and treats escaped braces in message searches differently. |Git-compatible revision grammar and regex semantics. Existing `test_rev_parse.py`cases reproduce all three. |
952
+
| GIX-17 | Bug (open) | Revision parsing accepts abbreviated IDs with `-dirty`, prefers the OID suffix over an exact describe-shaped tag, and treats escaped braces in message searches differently. With GixPython 0.3.0 and Git 2.54.0, `2313-supersede` resolves to blob `23136a1d1dd1f02de7cde0f7b55f49d76ac77d55` through Gix while Git resolves the existing branch's commit. The deterministic `rev-parse.sh hex-prefix-collision` fixture creates a branch named `<blob-prefix>-topic`: Gix returns the blob and also accepts `<blob-prefix>-missing`, which Git rejects. | Provide Git-compatible revision grammar and regex semantics. `_check_revision_grammar()` retains CLI for hexadecimal prefixes followed by a dash, as well as the existing guarded forms; this adapter workaround does not close the upstream bug. `test_rev_parse.py`reproduces these differences, including `test_rev_parse_hex_prefix_with_arbitrary_suffix`. |
939
953
| GIX-18 | Bug; missing API | The tree-diff resource cache reads attributes from the index; Git also consults worktree attributes. Native binary classification with textconv configured can also differ even in `to_git` mode. | Independent attribute-source control and `--no-textconv` parity. Statistics currently fall back for any effective `diff` attribute. |
940
954
| GIX-19 | Unverified | GixPython opens repositories with `extensions.compatObjectFormat`, but translation and object-write compatibility have not been validated. The installed Git reports `compatibility hash algorithm support requires Rust` when asked to translate an ID. This is an unvalidated capability guard, not evidence of missing native object mappings. | Verify compatibility-format reads, writes and OID translation against a Git build that supports them. All operations use CLI in the meantime. |
941
955
| GIX-20 | Bug; missing API |`Target.Symbolic(name)` validates full names but rejects standalone names accepted by `git check-ref-format --allow-onelevel`. Four of 430 audited calls differed: `refs` twice, `hellothere`, and `valid_one_level_refname`. Further probes include digits, punctuation and Unicode (`1`, `A1`, `HEAD_1`, `A-B`, `A.B`, `Ä`). | Expose Git-compatible partial/one-level name validation, or correct the native restriction where appropriate. This is a binding/behavior shortcoming to revisit upstream; standalone names rejected natively retain CLI validation. |
@@ -951,6 +965,7 @@ identify the historical fixture where needed.
951
965
| GIX-30 | Bug (open) | GixPython 0.2.0 `Commit.decode()` reports `encoding=None` when `encoding ISO-8859-1` follows `x-extra value`; Git 2.54.0 selects `ISO-8859-1` and renders Latin-1 identity/message bytes correctly. Gix retains `(b"encoding", b"ISO-8859-1")` in `extra_headers`, but its encoding field disagrees with Git. The `late-latin1` read-only `commit.sh` fixture in `test_deserialization_declared_encoding` reproduces this and asserts the fallback. | Recognize encoding headers in Git-compatible order. `object_metadata()` conservatively retains CLI when an encoding appears in `extra_headers`; it does not select the header in Python. Keep this bug open until an upstream fix or compatible mode is verified. |
952
966
| GIX-31 | Bug (open) | GixPython 0.2.0 `Commit.decode()` rejects commit headers containing a CR-only or tab-only line with `object parsing failed, at gix-object/src/commit/decode.rs:20`. Git 2.54.0 accepts both objects with `fsck --strict`, continues through their header block and renders the later Latin-1 declaration and message correctly. A space-only continuation line decodes natively but retains the late encoding declaration in `extra_headers` (GIX-30). `test_deserialization_headers_end_at_empty_line` reproduces all three using the `commit.sh whitespace-headers` fixtures and checks Git's projection. | Accept Git-compatible header lines and end headers only at an empty line. The existing `object_metadata()` native decoder diagnostics fallback retains Git for CR/tab inputs; the existing GIX-30 fallback covers the space input. Neither fallback closes these bugs. |
953
967
| GIX-32 | Missing capability (open); no demonstrated Git compatibility mismatch | Windows CI on GixPython 0.3.0, Git 2.56.0.windows.2 and CPython 3.12.10 enumerates the non-UTF-8 packed names in `legacy-refs.sh`, but exact byte-name lookup selects `Reference.read: CLI: native read diagnostics`; the no-CLI guard fails for SHA-1 and SHA-256. POSIX lookup succeeds. Git's Windows CLI likewise cannot address those original bytes through UTF-16 arguments, so there is no demonstrated equivalent Windows CLI operand. Git enumeration does preserve both names. | Provide native Windows packed-reference lookup for byte names without first converting the name to a loose-reference filesystem path. Keep `reference_info()`'s existing diagnostic fallback; `test_non_utf8_tag_names_preserve_bytes` checks it on Windows. Resolution coverage and native claims remain POSIX-only. The upstream lookup source attempts loose-path conversion before consulting packed refs; CI demonstrates the fallback, but does not capture the underlying Gix error text. |
968
+
| GIX-33 | Bug (open); missing exact-name mode | With Git 2.54.0 and GixPython 0.3.0, `exact-refs.sh sha1 files symbolic` makes `refs/tags/REBASE_HEAD` a symbolic ref to another tag while the root `REBASE_HEAD` is absent. `Repository.try_find_reference("REBASE_HEAD")` returns that tag; native `_symbolic_ref` formerly returned its target, whereas `git symbolic-ref --quiet --no-recurse -- REBASE_HEAD` exits 1. GitPython's root-reference object read consequently returned a commit through Gix and raised `ValueError` through CLI. SHA-256 reproduces the same mismatch. | Expose an exact-name lookup mode, including root references, whose absence and error behavior matches Git. `_symbolic_ref()` compares the native reference's name with the requested bytes and selects CLI for a lookalike. `test_missing_root_reference_does_not_follow_symbolic_lookalike_tag` verifies parity and forced CLI fallback. This adapter guard does not close the upstream compatibility bug. |
954
969
955
970
The PR #2306 regression exposed an adapter ownership-check bypass in both
956
971
backends: `Repo`'s automatic `GIT_DIR` made Git 2.54.0 treat hook execution as
0 commit comments