Introduction
ansible.builtin.git clones and manages Git repositories on remote hosts. Deploy code, checkout specific branches or tags, pull updates, and handle SSH authentication — all idempotently.
Basic Usage
# Clone a repository
- name: Clone application code
ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: main
# Clone with SSH
- name: Clone private repo
ansible.builtin.git:
repo: git@github.com:myorg/myapp.git
dest: /opt/myapp
version: main
key_file: /home/deploy/.ssh/deploy_key
accept_hostkey: true
Parameters
| Parameter | Default | Description |
|---|---|---|
repo | (required) | Repository URL (HTTPS or SSH) |
dest | (required) | Local path to clone into |
version | HEAD | Branch, tag, or commit hash |
clone | true | Clone if dest doesn't exist |
update | true | Pull updates if already cloned |
force | false | Discard local changes |
depth | — | Shallow clone depth |
single_branch | false | Only fetch the specified branch |
key_file | — | SSH private key path |
accept_hostkey | false | Accept unknown SSH host keys |
bare | false | Create bare repository |
recursive | true | Initialize submodules |
track_submodules | false | Track latest submodule commits |
refspec | — | Custom refspec |
ssh_opts | — | Extra SSH options |
Checkout Branches and Tags
# Specific branch
- ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: develop
# Specific tag
- ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: v2.1.0
# Specific commit
- ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: a1b2c3d4
Practical Patterns
Code Deployment
---
- name: Deploy application
hosts: webservers
become: true
vars:
app_version: "v2.1.0"
app_repo: "git@github.com:myorg/myapp.git"
app_dest: /opt/myapp
tasks:
- name: Pull latest code
ansible.builtin.git:
repo: "{{ app_repo }}"
dest: "{{ app_dest }}"
version: "{{ app_version }}"
key_file: /home/deploy/.ssh/deploy_key
accept_hostkey: true
force: true
register: git_result
notify: Restart application
- name: Show deployed version
ansible.builtin.debug:
msg: "Deployed {{ git_result.after[:8] }} (was {{ git_result.before[:8] }})"
when: git_result.changed
- name: Install dependencies
ansible.builtin.pip:
requirements: "{{ app_dest }}/requirements.txt"
when: git_result.changed
handlers:
- name: Restart application
ansible.builtin.service:
name: myapp
state: restarted
Shallow Clone (Faster)
# Only clone recent history
- name: Shallow clone for deployment
ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: main
depth: 1
single_branch: true
Release-Based Deployment
- name: Clone to release directory
ansible.builtin.git:
repo: "{{ app_repo }}"
dest: "/opt/releases/{{ app_version }}"
version: "{{ app_version }}"
depth: 1
register: deploy
- name: Install dependencies
ansible.builtin.command:
cmd: pip install -r requirements.txt
chdir: "/opt/releases/{{ app_version }}"
when: deploy.changed
- name: Switch symlink
ansible.builtin.file:
src: "/opt/releases/{{ app_version }}"
dest: /opt/myapp/current
state: link
force: true
notify: Restart app
SSH Agent Forwarding
# In ansible.cfg
# [ssh_connection]
# ssh_args = -o ForwardAgent=yes
- name: Clone with forwarded SSH agent
ansible.builtin.git:
repo: git@github.com:myorg/private-repo.git
dest: /opt/myapp
accept_hostkey: true
Deploy Key Setup
- name: Copy deploy key
ansible.builtin.copy:
src: deploy_key
dest: /home/deploy/.ssh/deploy_key
owner: deploy
mode: "0600"
- name: Add GitHub to known hosts
ansible.builtin.known_hosts:
name: github.com
key: "{{ lookup('pipe', 'ssh-keyscan github.com 2>/dev/null') }}"
state: present
- name: Clone repo
ansible.builtin.git:
repo: git@github.com:myorg/myapp.git
dest: /opt/myapp
key_file: /home/deploy/.ssh/deploy_key
become_user: deploy
Configuration Repository
# Clone config repo and deploy specific files
- name: Clone config repo
ansible.builtin.git:
repo: git@github.com:myorg/server-configs.git
dest: /opt/configs
version: main
- name: Deploy nginx config
ansible.builtin.copy:
src: "/opt/configs/nginx/{{ inventory_hostname }}.conf"
dest: /etc/nginx/nginx.conf
remote_src: true
notify: Reload nginx
Register Output
- ansible.builtin.git:
repo: https://github.com/myorg/myapp.git
dest: /opt/myapp
version: main
register: git_result
# Available fields:
# git_result.changed — true if repo was updated
# git_result.before — previous commit hash
# git_result.after — current commit hash
# git_result.remote_url_changed — URL changed
- debug:
msg: "Updated from {{ git_result.before[:8] }} to {{ git_result.after[:8] }}"
when: git_result.changed
Troubleshooting
"Permission denied (publickey)"
SSH key issues:
# Use key_file
- git:
repo: git@github.com:myorg/app.git
dest: /opt/app
key_file: /home/deploy/.ssh/id_ed25519
accept_hostkey: true
# Or use HTTPS with token
- git:
repo: "https://{{ github_token }}@github.com/myorg/app.git"
dest: /opt/app
"Local modifications exist"
Use force: true to discard local changes:
- git:
repo: https://github.com/myorg/app.git
dest: /opt/app
force: true # Discard local changes
"Git not installed"
- name: Install git
ansible.builtin.package:
name: git
state: present
- name: Clone repo
ansible.builtin.git:
repo: https://github.com/myorg/app.git
dest: /opt/app
Related Articles
Conclusion
ansible.builtin.git deploys code from Git repositories idempotently. Use version for branches, tags, or commits. Use depth: 1 for faster shallow clones in deployment. Use key_file or SSH agent forwarding for private repos. The module tracks changes — register gives you before/after commit hashes for conditional logic. Combine with symlinks for zero-downtime release-based deployments.