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 ofansible-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 DocumentationSee 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 specifyrefspec:
- 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 Practices • Ansible git Module: Clone & Pull Git Repositories (ansible.builtin.git Guide)Category: installation