Repository navigation
Description
Summary
ansible.builtin.git with depth and a tag as version clones fine on the first run. On every later run against the same dest, the module crashes with an unhandled AttributeError instead of reporting ok.
Note that this issue was mostly copied from #87879 because that one was closed and I am having the same issue. The issue seems to be caused by 5186cff.
In my case, is_not_a_branch() returns True which means headfile would be <path to .git>/refs/remotes/origin/HEAD, but my refs directory doesn't have a remotes subdirectory, so head_splitter() returns None. I haven't spent a super lot of time trying to track down why the changes in that commit caused this to fail suddenly, but it seems as though they did.
Issue Type
Bug Report
Component Name
git
Ansible Version
$ ansible --version
ansible [core 2.21.6]
config file = /home/ryan/Ansible/Homelab/ansible.cfg
configured module search path = ['/home/ryan/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ryan/.local/share/pipx/venvs/ansible/lib/python3.13/site-packages/ansible
ansible collection location = /home/ryan/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ryan/.local/bin/ansible
python version = 3.13.5 (main, Aug 10 2026, 12:06:59) [GCC 14.2.0] (/home/ryan/.local/share/pipx/venvs/ansible/bin/python)
jinja version = 3.1.6
pyyaml version = 6.0.3 (with libyaml v0.2.5)Configuration
# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t allOS / Environment
Linux ansible 6.12.115+deb13.1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.115-2 (2026-11-01) x86_64 GNU/Linux
Steps to Reproduce
python3 -m venv /tmp/repro/venv
/tmp/repro/venv/bin/pip install ansible-core==2.21.6
git init --bare --initial-branch=main /tmp/repro/upstream.git
git clone /tmp/repro/upstream.git /tmp/repro/seed
git -C /tmp/repro/seed commit --allow-empty -m one
git -C /tmp/repro/seed tag -a v1 -m v1
git -C /tmp/repro/seed commit --allow-empty -m two
git -C /tmp/repro/seed push origin HEAD:main --tags
/tmp/repro/venv/bin/ansible localhost -m git \
-a "repo=/tmp/repro/upstream.git dest=/tmp/repro/checkout version=v1 depth=1 force=true"
/tmp/repro/venv/bin/ansible localhost -m git \
-a "repo=/tmp/repro/upstream.git dest=/tmp/repro/checkout version=v1 depth=1 force=true"Expected Results
The second call reports SUCCESS with "changed": false and before == after, as ansible-core 2.21.4 does:
localhost | SUCCESS => {
"after": "13fc42f91aff0ccf316a57149e34ee9069e4b084",
"before": "13fc42f91aff0ccf316a57149e34ee9069e4b084",
"changed": false,
"remote_url_changed": false
}
Actual Results
[ERROR]: Task failed: Module failed: 'NoneType' object has no attribute 'startswith'
File ".../ansible/modules/git.py", line 1428, in main
fetch(git_path, module, repo, dest, version, remote, depth, bare, refspec, git_version_used, force=force)
File ".../ansible/modules/git.py", line 925, in fetch
currenthead = get_head_branch(git_path, module, dest, remote)
File ".../ansible/modules/git.py", line 877, in get_head_branch
if branch.startswith('-'):
^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'startswith'Code of Conduct
- I agree to follow the Ansible Code of Conduct
Activity
ansibot commentedon Nov 5, 2026
Files identified in the description:
lib/ansible/modules/git.pyIf these files are incorrect, please update the
component namesection of the description or use the component bot command.timewasted commentedon Nov 5, 2026
Simply updating the check from
if branch.startswith('-'):toif branch is not None and branch.startswith('-'):fixes the issue, but I haven't dug in to see if that has any other effects or if something similar needs to be applied elsewhere.bunnysayzz commentedon Nov 5, 2026
root cause is in get_head_branch (git.py:877). on a shallow tag checkout there is no refs/remotes/origin/HEAD, so head_splitter returns None and branch.startswith('-') blows up. that check came in with the CVE-2026-84503 cleanup in 5186cff, which never handled the None case.
fix guards the None and returns it like 2.21.4 did, dash names still get rejected. added a regression test covering the exact layout from the repro plus a changelog fragment. fix is in #87883.
git module - fix crash updating a shallow tag checkout
git module - fix crash updating a shallow tag checkout
git module - fix crash updating a shallow tag checkout
git module - fix crash updating a shallow tag checkout
git module - fix crash updating a shallow tag checkout