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 Repos & Checkout Commits (ansible.builtin.git Guide)

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

Complete guide to ansible.builtin.git module. Clone repositories, checkout specific commits, branches, and tags with practical playbook examples.

How to Checkout a Specific Commit Using Ansible?

Managing code versions effectively is crucial in automation workflows. With Ansible’s ansible.builtin.git module, you can checkout a specific commit from a Git repository, ensuring your infrastructure or deployments use the exact version you need.

I'm Luca Berton, and in this tutorial, I’ll guide you through checking out a specific commit of a Git repository using Ansible.

See also: ansible.builtin.git Module: Clone & Checkout Git Repositories (Guide)

ansible.builtin.git

• Part of ansible-core • Manages Git checkouts • Supports branches, tags, and commit hashes

The ansible.builtin.git module enables automated repository management in Ansible playbooks. You can use it to clone repositories, checkout branches, pull changes, and, importantly, checkout a specific commit by using its SHA-1 hash.

Links

Ansible Git Module Documentation

See also: Ansible git Clone via SSH: Deploy Keys & Repository Guide

Playbook

I’ll show you how to checkout a specific commit from a Git repository using an Ansible playbook.

Execution

$ ansible-playbook git_checkout_commit.yml

Playbook Code

- name: Checkout a specific commit from a Git repository
  hosts: localhost
  tasks:
    - name: Clone the repo and checkout a specific commit
      ansible.builtin.git:
        repo: "https://github.com/example/repo.git"
        dest: "/path/to/clone"
        version: "abc123def4567890"  # Replace with your commit hash

Explanation:

repo: Defines the Git repository URL. • dest: Specifies where to clone the repository. • version: Points to the exact commit hash to checkout.

Additional Options

Force Checkout a Specific Commit

If the repository is already cloned, but you want to force-checkout a commit:
- name: Force checkout a specific commit
  ansible.builtin.git:
    repo: "https://github.com/example/repo.git"
    dest: "/path/to/clone"
    version: "abc123def4567890"
    force: yes  # Discards any local changes

Checkout a Commit Not Part of a Branch

If the commit isn't part of any branch or tag, you might need to specify refspec:
- name: Checkout a commit not part of a branch
  ansible.builtin.git:
    repo: "https://github.com/example/repo.git"
    dest: "/path/to/clone"
    version: "abc123def4567890"
    refspec: "+refs/heads/*:refs/remotes/origin/*"

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

Before Execution

$ ls /path/to/clone
(no repository exists)

After Execution

$ git log --oneline
abc123d (HEAD) Fix critical bug in deployment
456789a Add feature X
7890bcd Initial commit

Handling Detached HEAD State

Since checking out a commit directly places Git in a detached HEAD state, you may want to switch back to a branch after checking out:

    - name: Checkout a branch after commit
      command: git checkout -b feature-branch
      args:
        chdir: "/path/to/clone"

Checkout by Commit Hash

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

Checkout by Tag

- name: Deploy release tag
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "v2.5.0"

Checkout by Branch

- name: Deploy feature branch
  ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "feature/new-ui"

Version-Pinned Deployment

---
- name: Deploy at specific version
  hosts: webservers
  become: true
  vars:
    app_version: "v2.5.0"  # Override with -e
  tasks:
    - name: Clone at version
      ansible.builtin.git:
        repo: https://github.com/myorg/myapp.git
        dest: /opt/myapp
        version: "{{ app_version }}"
        force: true
      register: git_deploy

- name: Record version ansible.builtin.copy: content: | version: {{ app_version }} commit: {{ git_deploy.after }} date: {{ ansible_date_time.iso8601 }} dest: /opt/myapp/DEPLOYED_VERSION when: git_deploy.changed

Rollback Pattern

- name: Get previous commit
  ansible.builtin.command:
    cmd: git rev-parse HEAD~1
    chdir: /opt/myapp
  register: previous_commit
  changed_when: false

- name: Rollback ansible.builtin.git: repo: https://github.com/myorg/myapp.git dest: /opt/myapp version: "{{ previous_commit.stdout }}" force: true notify: restart app

Get Latest Tag

- name: Find latest tag
  ansible.builtin.shell: |
    git ls-remote --tags https://github.com/myorg/myapp.git |
    awk '{print $2}' | grep -oP 'v\d+\.\d+\.\d+$' | sort -V | tail -1
  register: latest_tag
  delegate_to: localhost
  changed_when: false

- name: Deploy latest ansible.builtin.git: repo: https://github.com/myorg/myapp.git dest: /opt/myapp version: "{{ latest_tag.stdout }}"

FAQ

What does version accept?

Any valid Git ref: branch name, tag, full/short commit SHA, or HEAD.

How do I prevent accidental updates?

Use update: false to skip pulling if repo exists:

- ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "v2.5.0"
    update: false

What does force: true do?

Discards local changes and resets to the specified version. Without it, the task fails if there are uncommitted local changes.

Checkout Specific Commit

- name: Deploy exact commit
  ansible.builtin.git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    version: abc123def456789
  become_user: deploy

Checkout Branch

- git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    version: develop

- git: repo: git@github.com:myorg/myapp.git dest: /opt/myapp version: feature/new-api

Checkout Tag

- git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    version: v2.5.0

Deployment with Rollback

---
- name: Deploy with rollback support
  hosts: webservers
  vars:
    repo: git@github.com:myorg/myapp.git
    deploy_dir: /opt/myapp
    deploy_version: "{{ version | default('main') }}"
  tasks:
    - name: Get current commit
      command:
        cmd: git rev-parse HEAD
        chdir: "{{ deploy_dir }}"
      register: current_commit
      changed_when: false
      ignore_errors: true

- name: Save rollback point set_fact: rollback_commit: "{{ current_commit.stdout | default('') }}"

- name: Deploy new version git: repo: "{{ repo }}" dest: "{{ deploy_dir }}" version: "{{ deploy_version }}" force: true register: deploy notify: restart app

- name: Verify deployment uri: url: http://localhost:8080/health status_code: 200 register: health retries: 5 delay: 10 until: health.status == 200 ignore_errors: true

- name: Rollback on failure git: repo: "{{ repo }}" dest: "{{ deploy_dir }}" version: "{{ rollback_commit }}" force: true when: health is failed and rollback_commit != '' notify: restart app

Pin Version in Variables

# group_vars/production.yml
app_version: v2.5.0  # Tag
# app_version: abc123  # Commit
# app_version: main    # Branch

# Playbook - git: repo: "{{ app_repo }}" dest: "{{ app_dir }}" version: "{{ app_version }}"

Shallow Clone with Specific Version

- git:
    repo: git@github.com:myorg/myapp.git
    dest: /opt/myapp
    version: v2.5.0
    depth: 1           # Only latest commit
    single_branch: true # Only specified branch/tag

Get Deployed Version

- command:
    cmd: git describe --tags --always
    chdir: /opt/myapp
  register: deployed_version
  changed_when: false

- debug: msg: "Deployed: {{ deployed_version.stdout }}"

FAQ

What happens if the commit doesn't exist?

The task fails with a git error. Always verify the commit/tag exists before deploying.

force: true — will it lose local changes?

Yes — force: true runs git checkout --force and git clean -fd, discarding all local modifications.

How do I deploy from a private repo?

Use SSH with a deploy key:

- git:
    repo: git@github.com:myorg/private-app.git
    dest: /opt/myapp
    key_file: /home/deploy/.ssh/deploy_key
    accept_hostkey: true

Clone Repository

- ansible.builtin.git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: main
  become: true

Checkout Specific Commit

- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "abc123def456"
  become: true

Checkout Tag

- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "v2.5.0"
  become: true

Checkout Branch

- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    version: "feature/new-api"
    force: true
  become: true

SSH Authentication

- git:
    repo: git@github.com:myorg/private-repo.git
    dest: /opt/myapp
    version: main
    key_file: /home/deploy/.ssh/deploy_key
    accept_hostkey: true
  become: true
  become_user: deploy

Deploy Pattern

- git:
    repo: "{{ app_repo }}"
    dest: "/opt/releases/{{ app_version }}"
    version: "{{ app_version }}"
  become: true
  register: git_result

- file: src: "/opt/releases/{{ app_version }}" dest: /opt/myapp/current state: link when: git_result.changed become: true

- command: /opt/myapp/current/install.sh when: git_result.changed notify: restart app

Shallow Clone

# Only fetch latest commit (faster, less disk)
- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    depth: 1
    version: main

Force Update (Discard Local Changes)

- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
    force: true  # Discards local modifications
    version: main

Check If Updated

- git:
    repo: https://github.com/myorg/myapp.git
    dest: /opt/myapp
  register: git_result

- name: Run migrations only if code changed command: /opt/myapp/migrate.sh when: git_result.changed

FAQ

How to use HTTPS with credentials?

repo: "https://{{ git_user }}:{{ git_token }}@github.com/myorg/repo.git"
# Better: use SSH keys or credential helper

force: true vs update: true?

force: true discards local changes. update: true (default) pulls changes but fails if local modifications conflict.

How to clone to a specific user's home?

Use become_user to clone as that user, ensuring proper file ownership.

Conclusion

Now you know how to checkout a specific commit of a Git repository using Ansible. This ensures your automation pipelines deploy and test against exact versions.

Related Articles

ansible.builtin.git Module: Clone & Checkout Git Repositories (Guide)Ansible builtin command Module: Complete Guide with Examples and Best PracticesAnsible git Module: Clone & Pull Git Repositories (ansible.builtin.git Guide)

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home