Introduction
The ansible.builtin.git module clones and updates Git repositories on remote hosts. Combined with SSH key authentication, it's the standard way to deploy application code, configuration repos, and infrastructure-as-code across server fleets.
For HTTPS checkout, see Checkout git repository via HTTPS.
Module Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | Yes | Repository URL (SSH or HTTPS) |
dest | path | Yes | Destination directory on remote |
version | string | No | Branch, tag, or commit SHA (default: HEAD) |
key_file | path | No | Path to SSH private key on remote host |
accept_hostkey | bool | No | Auto-accept unknown SSH host keys |
update | bool | No | Pull new revisions if repo exists (default: true) |
force | bool | No | Discard local changes before updating |
depth | int | No | Shallow clone depth (saves bandwidth) |
recursive | bool | No | Initialize submodules (default: true) |
single_branch | bool | No | Clone only the specified branch |
clone | bool | No | If false, only update existing repo |
bare | bool | No | Create a bare repository |
Basic Clone via SSH
---
- name: Deploy application code
hosts: app_servers
become: false
vars:
repo: "git@github.com:myorg/myapp.git"
dest: "/home/deploy/myapp"
tasks:
- name: Ensure git is installed
ansible.builtin.yum:
name: git
state: present
become: true
- name: Clone repository
ansible.builtin.git:
repo: "{{ repo }}"
dest: "{{ dest }}"
key_file: "~/.ssh/id_ed25519"
accept_hostkey: true
SSH Key Setup
Prerequisites
The SSH private key must exist on the remote host (not the controller). The corresponding public key must be added to your Git server.
Deploy SSH Key with Ansible
- name: Deploy SSH key for Git access
ansible.builtin.copy:
content: "{{ vault_git_deploy_key }}"
dest: /home/deploy/.ssh/id_ed25519
owner: deploy
group: deploy
mode: '0600'
no_log: true
- name: Add GitHub to known_hosts
ansible.builtin.known_hosts:
name: github.com
key: "{{ lookup('pipe', 'ssh-keyscan github.com 2>/dev/null') }}"
path: /home/deploy/.ssh/known_hosts
state: present
Use Agent Forwarding (Alternative)
Instead of deploying keys to every host, forward your local SSH agent:
# ansible.cfg
[ssh_connection]
ssh_args = -o ForwardAgent=yes
- name: Clone using forwarded agent
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
# No key_file needed — uses forwarded agent
Practical Patterns
Deploy Specific Branch or Tag
- name: Deploy release v2.1.0
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
version: "v2.1.0"
key_file: ~/.ssh/deploy_key
Deploy Specific Commit
- name: Pin to exact commit
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
version: "a1b2c3d4e5f6"
key_file: ~/.ssh/deploy_key
Shallow Clone (Save Bandwidth)
- name: Shallow clone (latest only)
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
depth: 1
single_branch: true
version: main
key_file: ~/.ssh/deploy_key
Force Update (Discard Local Changes)
- name: Force clean checkout
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
force: true
key_file: ~/.ssh/deploy_key
Clone with Submodules
- name: Clone with submodules
ansible.builtin.git:
repo: "git@github.com:myorg/myapp.git"
dest: /opt/myapp
recursive: true
key_file: ~/.ssh/deploy_key
Complete Deployment Playbook
---
- name: Deploy application from Git
hosts: app_servers
become: true
vars:
app_repo: "git@github.com:myorg/myapp.git"
app_version: "main"
app_dir: "/opt/myapp"
app_user: "myapp"
tasks:
- name: Ensure dependencies installed
ansible.builtin.yum:
name: [git, python3, python3-pip]
state: present
- name: Create app user
ansible.builtin.user:
name: "{{ app_user }}"
system: true
home: "{{ app_dir }}"
shell: /bin/bash
- name: Deploy SSH key
ansible.builtin.copy:
content: "{{ vault_deploy_key }}"
dest: "/home/{{ app_user }}/.ssh/id_ed25519"
owner: "{{ app_user }}"
mode: '0600'
no_log: true
- name: Clone application
ansible.builtin.git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
version: "{{ app_version }}"
key_file: "/home/{{ app_user }}/.ssh/id_ed25519"
accept_hostkey: true
force: true
become_user: "{{ app_user }}"
register: git_result
notify: restart app
- name: Install Python dependencies
ansible.builtin.pip:
requirements: "{{ app_dir }}/requirements.txt"
virtualenv: "{{ app_dir }}/venv"
become_user: "{{ app_user }}"
when: git_result.changed
- name: Show deployed version
ansible.builtin.debug:
msg: "Deployed commit: {{ git_result.after }}"
handlers:
- name: restart app
ansible.builtin.systemd:
name: myapp
state: restarted
Return Values
| Value | Description |
|---|---|
after | Commit SHA after the operation |
before | Commit SHA before the operation |
remote_url_changed | Whether the remote URL changed |
warnings | List of warnings during operation |
Common Errors
"Permission denied (publickey)"
fatal: Could not read from remote repository.
Please make sure you have the correct access rights.
Fix: Verify key_file path exists on the remote host, has 0600 permissions, and the public key is added to the Git server.
"Host key verification failed"
Fix: Add accept_hostkey: true or pre-populate known_hosts.
"Destination directory not empty"
Fix: Use force: true to overwrite, or ensure dest is either empty or a valid git repo.
Related Articles
- Clone Git via HTTPS
- Copy Files to Remote: copy Module
- Ansible Vault Guide
- Ansible Best Practices Guide
Conclusion
Use ansible.builtin.git with key_file for SSH clones, depth: 1 for faster deploys, version for pinning branches/tags/commits, and force: true when local changes should be discarded. Deploy SSH keys with copy + no_log: true, or use agent forwarding. The after return value gives you the deployed commit SHA for tracking.