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

ParameterDescriptionDefault
repoRepository URL (required)
destTarget directory (required)
versionBranch, tag, or commit hashHEAD
forceDiscard local changesfalse
depthShallow clone depth— (full)
single_branchOnly clone one branchfalse
recursiveInit submodulestrue
updatePull if dest existstrue
key_fileSSH private key path
accept_hostkeyAccept unknown SSH host keysfalse
bareCreate bare repositoryfalse
cloneAllow 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

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

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

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

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home