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 d03d3d7
Browse filesBrowse the repository at this point in the historyBrowse files
fix: read reference arguments by exact name in revision APIs
<!-- agent -->
`Reference.__str__` returns the short name, so `refs/heads/main` becomes
`main` and `refs/remotes/origin/main` becomes `origin/main`. The revision
APIs turned reference objects into revisions with `str(ref)` or
`Git._check_operand(ref, "revision")`, and Git's revision lookup
(gitrevisions(7)) tries `refs/tags/<name>` before `refs/heads/<name>` and
`refs/remotes/<name>`, only warning about the ambiguity on stderr. A tag
that shares a branch's short name therefore took the branch's place.
Whoever controls a remote can supply such tags: `git fetch` auto-follows
tags that point into fetched history, and a clone brings in every tag.
With a branch `main` and fetched tags `main` and `origin/main` on another
commit, `repo.heads.main.commit` still reported the branch, but these APIs
used the tag's commit on both backends:
- `Repo.commit()`, `Repo.tree()`, `Object.new()`, `Repo.iter_commits()`
- `Repo.merge_base()`, `Repo.is_ancestor()`, `Diffable.diff()`
- `Repo.blame()`, `Repo.blame_incremental()`, `Repo.archive()`
- `IndexFile.from_tree()`, `IndexFile.merge_tree()`, `IndexFile.reset()`
- `HEAD.reset()`, `Repo.create_head()`, `Repo.create_tag()`
In the documented merge workflow, `merge_base(new_branch, original_branch)`
followed by `index.merge_tree(original_branch, base=...)`, the merge commit
received the tag's tree while its parents named the branch commits.
`repo.head.reset(repo.heads.main, working_tree=True)` and
`repo.index.reset(ref, head=True)` moved the current branch to the tag's
commit and wrote its files into the working tree.
Add `Git._check_revision()`. For a `SymbolicReference` it reads the exact
reference through `dereference_recursive()`, the `show-ref`/Gix read behind
`ref.object`, and passes on the object ID, which is how
`SymbolicReference.set_object()` already resolves reference arguments.
Strings keep Git's name guessing, as the changelog already documents.
`merge_base()` resolves its top-level arguments before
`_unpack_args()` flattens them. A reference that does not exist now raises
`ValueError`, as `ref.object` does, instead of resolving to whatever Git
guesses for its short name. On the CLI backend each reference argument
costs one or two extra short Git calls; the Gix backend reads references
natively, and `doc/gix-backend.md` is unchanged.
Validation: the new `shadowed` case in `tests/fixtures/exact-refs.sh` backs
`test_reference_arguments_do_not_resolve_same_named_tags` in
`test/test_refs.py`, which checks the APIs above for a branch and a
remote-tracking branch. It fails before the change and passes after it with
`GIT_PYTHON_BACKEND=cli` and `GIT_PYTHON_BACKEND=gix` for SHA-1/SHA-256 and
files/reftable (Git 2.52.0, GixPython 0.3.0, Python 3.11, macOS). Full
suites with the change: CLI 1,915 passed and Gix 2,018 passed. Each run
also had 116 failures, and the same 116 tests fail on the unpatched tree;
they need history and tags such as `0.1.5`, which this shallow clone lacks.
`ruff check`, `ruff format --check`, ShellCheck, `mypy --python-version=3.11`
and `basedpyright --warnings` pass.
Agent-Model: claude-opus-5-5
0 commit comments