Repository navigation
Commit 6702912
committed
fix(refs): read references by exact name instead of revision guessing
`SymbolicReference._get_ref_info_helper` resolved a reference that is not a
symbolic ref with `git rev-parse --verify --end-of-options <path>`, and
`Repo.currently_rebasing_on()` read `REBASE_HEAD` the same way. `rev-parse`
applies the revision-guessing rules from `gitrevisions(7)`: when `<path>`
itself does not exist it also tries `refs/<path>`, `refs/tags/<path>`,
`refs/heads/<path>` and `refs/remotes/<path>`. A reference that does not
exist was therefore reported as existing whenever a look-alike name did.
`refs/heads/main` is a valid tag name, and any fetch or clone delivers it as
`refs/tags/refs/heads/main`. In a repository whose `HEAD` points at the
unborn `refs/heads/main`, Git reports an unborn branch (`git rev-parse
--verify HEAD` exits 1 and `git show-ref --verify refs/heads/main` fails),
while GitPython's CLI backend reported `head.is_valid()` as `True`,
`head.commit` as the tag's commit, and `repo.index.commit()` created the
first commit with that foreign commit as its parent and then wrote
`refs/heads/main` on top of the tag's history. The same lookup through the
Gix backend already answered "does not exist", so the two backends
disagreed. A tag named `REBASE_HEAD` likewise made
`currently_rebasing_on()` return a commit while no rebase was in progress.
Read the exact name instead. `git show-ref --verify --hash -- <path>` reads
only the named reference and fails for a missing one; it resolves `HEAD`,
`ORIG_HEAD`, `FETCH_HEAD`, `MERGE_HEAD`, `refs/stash`, nested tags and a
linked worktree's `HEAD` the same way `rev-parse --verify` did, on both
files and reftable storage. `currently_rebasing_on()` first runs
`git show-ref --exists -- REBASE_HEAD`, which exits 2 for a missing
reference, so an absent rebase is still reported as `None` without matching
diagnostic text. The `ValueError` raised for a missing reference is
unchanged, and the Gix backend's native lookup is unaffected.
The `lookalike` case in `tests/fixtures/reference-security.sh` tags the
initial commit as `refs/heads/missing` and `REBASE_HEAD` and points `HEAD`
at the unborn branch. `test_missing_references_do_not_resolve_to_look_alike_names`
checks the lookup, `is_valid()`, tag access and `currently_rebasing_on()`
through the native and the CLI reader, and
`test_commit_on_unborn_head_ignores_look_alike_tag` checks that the first
commit has no parent. Both fail before this change on each backend and pass
after it.
Validation: the full test suite with Git 2.52.0 on the CLI and Gix backends
(a bootstrapped clone, `init-tests-after-clone.sh`), Ruff check and format,
mypy, and ShellCheck on the fixture script.1 parent 4debc51 commit 6702912
5 files changed
Lines changed: 45 additions & 6 deletions
File tree
- doc/source
- git
- refs
- repo
- tests/fixtures
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
53 | 58 | | |
54 | 59 | | |
55 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
200 | 203 | | |
201 | | - | |
| 204 | + | |
202 | 205 | | |
203 | 206 | | |
204 | 207 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1964 | 1964 | | |
1965 | 1965 | | |
1966 | 1966 | | |
1967 | | - | |
1968 | | - | |
| 1967 | + | |
| 1968 | + | |
| 1969 | + | |
| 1970 | + | |
1969 | 1971 | | |
1970 | | - | |
| 1972 | + | |
1971 | 1973 | | |
1972 | 1974 | | |
1973 | | - | |
1974 | | - | |
| 1975 | + | |
| 1976 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1134 | 1134 | | |
1135 | 1135 | | |
1136 | 1136 | | |
| 1137 | + | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
1137 | 1160 | | |
1138 | 1161 | | |
1139 | 1162 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
43 | 49 | | |
44 | 50 | | |
45 | 51 | | |
| |||
0 commit comments