AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible git Module: Clone & Pull Git Repositories (ansible.builtin.git Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to clone and pull git repositories with Ansible git module (ansible.builtin.git). Clone repos, checkout branches, tags, manage deployments.

The ansible.builtin.git module clones and manages Git repositories on remote hosts. It's the foundation of Git-based deployment workflows — pull code, checkout specific versions, and manage repository state declaratively.

Basic Operations

Clone a Repository

- name: Clone repository
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp

Clone a Specific Branch

- name: Clone develop branch
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: develop

Clone a Specific Tag

- name: Deploy version 2.1.0
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: v2.1.0

Clone a Specific Commit

- name: Deploy exact commit
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: a1b2c3d4e5f6

Pull Latest Changes

# If dest already exists, git module does a pull/checkout
- name: Update to latest
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: main
    force: true    # Discard local changes

See also: Git Large File Storage (LFS) Tutorial: Versioning Big Binaries with Ansible

SSH Key Authentication

Using SSH URL

- name: Clone via SSH
  ansible.builtin.git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    key_file: /home/deploy/.ssh/id_ed25519
    accept_hostkey: true

Deploy Key Pattern

- name: Install deploy key
  ansible.builtin.copy:
    content: "{{ vault_deploy_key }}"
    dest: /home/deploy/.ssh/deploy_key
    owner: deploy
    group: deploy
    mode: '0600'

- name: Clone with deploy key ansible.builtin.git: repo: git@github.com:myorg/myapp.git dest: /opt/myapp key_file: /home/deploy/.ssh/deploy_key accept_hostkey: true become: true become_user: deploy

SSH Agent Forwarding

# ansible.cfg
[ssh_connection]
ssh_args = -o ForwardAgent=yes
# Playbook — uses forwarded agent
- name: Clone using forwarded SSH agent
  ansible.builtin.git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    accept_hostkey: true

HTTPS Authentication

# Token-based (GitHub, GitLab)
- name: Clone with token
  ansible.builtin.git:
    repo: "https://{{ git_token }}@github.com/myorg/myapp.git"
    dest: /opt/myapp

# Username/password - name: Clone with credentials ansible.builtin.git: repo: "https://{{ git_user }}:{{ git_password }}@gitlab.example.com/myorg/myapp.git" dest: /opt/myapp

See also: Ansible GitOps: Infrastructure as Code with Git Workflows and AAP

Common Parameters

| Parameter | Description | Default | |-----------|-------------|---------| | repo | Repository URL (required) | — | | dest | Target directory (required) | — | | version | Branch, tag, or commit hash | HEAD | | force | Discard local changes | false | | depth | Shallow clone depth | — (full) | | single_branch | Only clone one branch | false | | recursive | Init submodules | true | | update | Pull if dest exists | true | | key_file | SSH private key path | — | | accept_hostkey | Accept unknown SSH host keys | false | | bare | Create bare repository | false | | clone | Allow clone (false = update only) | true |

Shallow Clones (Faster Deploys)

- name: Shallow clone (faster, less disk)
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    depth: 1
    single_branch: true
    version: main

See also: Ansible git Module: Clone Repos & Checkout Commits (ansible.builtin.git Guide)

Submodules

# Clone with submodules (default behavior)
- name: Clone with submodules
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    recursive: true

# Skip submodules - name: Clone without submodules ansible.builtin.git: repo: https://github.com/myorg/myapp.git dest: /opt/myapp recursive: false

Deployment Workflows

Basic Git Deploy

---
- name: Deploy application from Git
  hosts: webservers
  become: true
  vars:
    app_version: main
    app_dir: /opt/myapp
    app_user: deploy

tasks: - name: Pull latest code ansible.builtin.git: repo: "{{ app_repo }}" dest: "{{ app_dir }}" version: "{{ app_version }}" force: true become_user: "{{ app_user }}" register: git_result notify: restart app

- name: Install dependencies ansible.builtin.command: npm install --production args: chdir: "{{ app_dir }}" when: git_result is changed

- name: Run build ansible.builtin.command: npm run build args: chdir: "{{ app_dir }}" when: git_result is changed

handlers: - name: restart app ansible.builtin.systemd: name: myapp state: restarted

Git Deploy with Rollback

- name: Deploy with rollback support
  hosts: webservers
  vars:
    releases_dir: /opt/releases
    current_link: /opt/myapp
    keep_releases: 5

tasks: - name: Create release directory ansible.builtin.file: path: "{{ releases_dir }}/{{ deploy_version }}" state: directory

- name: Clone release ansible.builtin.git: repo: "{{ app_repo }}" dest: "{{ releases_dir }}/{{ deploy_version }}" version: "{{ deploy_version }}" depth: 1

- name: Install dependencies ansible.builtin.command: npm install --production args: chdir: "{{ releases_dir }}/{{ deploy_version }}"

- name: Update symlink to new release ansible.builtin.file: src: "{{ releases_dir }}/{{ deploy_version }}" dest: "{{ current_link }}" state: link notify: restart app

- name: Cleanup old releases ansible.builtin.shell: | ls -dt {{ releases_dir }}/*/ | tail -n +{{ keep_releases + 1 }} | xargs rm -rf changed_when: false

handlers: - name: restart app ansible.builtin.systemd: name: myapp state: restarted

Check for Changes Before Deploying

- name: Check current version
  ansible.builtin.command: git rev-parse HEAD
  args:
    chdir: /opt/myapp
  register: current_commit
  changed_when: false
  failed_when: false

- name: Pull latest ansible.builtin.git: repo: "{{ app_repo }}" dest: /opt/myapp version: main register: git_result

- name: Show what changed ansible.builtin.debug: msg: | Before: {{ current_commit.stdout | default('fresh clone') }} After: {{ git_result.after }} Changed: {{ git_result is changed }}

FAQ

How do I clone a Git repository with Ansible?

Use the git module with repo (URL) and dest (target directory): ansible.builtin.git: repo=https://github.com/org/repo.git dest=/opt/app. For private repos, add key_file (SSH) or embed a token in the HTTPS URL.

How do I deploy a specific Git tag with Ansible?

Set version to the tag name: version: v2.1.0. The module checks out that exact tag. Works with branches, tags, and commit hashes.

How do I handle local changes when pulling?

Use force: true to discard local changes and force checkout. Without it, the task fails if there are uncommitted changes that conflict with the pull.

Should I use shallow clones for deployment?

Yes, depth: 1 with single_branch: true is recommended for deployments. It's faster and uses less disk space. Only use full clones when you need full history (e.g., for git log or git blame).

How do I use a GitHub deploy key?

Store the private key in Ansible Vault, copy it to the target host with mode: '0600', then reference it with key_file in the git module. Set accept_hostkey: true for first-time connections.

Conclusion

version: — Branch, tag, or commit hash for exact deployments • depth: 1 — Shallow clones for faster deploys • force: true — Discard local changes on pull • key_file: — SSH key for private repo authentication • Register resultgit_result is changed tells you if code actually updated • Use handlers to restart services only when code changes

Related Articles

Ansible CI/CD Pipeline IntegrationAnsible uri Module: HTTP/REST API CallsAnsible Playbook Structure & Best Practices

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home