Sync A Git Repo On A Target
on this page
Use this guide when a target needs to clone or update a Git repository
as part of a playbook run — for example, a museum kiosk pulling the
latest exhibit content before it opens for the day. On Windows targets,
the embedded preflight/git-sync action wraps the fetch, checkout,
reset, and clean steps in a single idempotent task; on POSIX targets,
run git through the shell module (see
Sync On A POSIX Target).
Prerequisites
- A working playbook and a Windows target connection
gitinstalled on the target (usewinget_packageorpackage; see the built-in module reference)- If the repository is private, credentials configured as described in Configure Git Credentials For A Target
1. Sync A Repository
preflight/git-sync clones the repository into dest if it does not
exist yet, or fetches and checks out ref if it does:
tasks:
- name: Sync exhibit content
uses: preflight/git-sync
with:
repo: https://github.com/example/content.git
dest: C:\Exhibits\Content
ref: mainRe-running the task leaves an up-to-date working tree at dest with
ref checked out. Set create_parent: true if the parent of dest
does not exist yet, and set_remote_url: true if repo may change
between runs and the existing remote should be updated to match.
2. Pin To A Ref
ref accepts a branch, tag, or commit. Pin exhibit content to a tag so
that a kiosk never picks up unreviewed commits on main:
tasks:
- name: Sync exhibit content at a known-good tag
uses: preflight/git-sync
with:
repo: https://github.com/example/content.git
dest: C:\Exhibits\Content
ref: v2026.03.01
detach: truedetach: true checks out ref directly instead of creating or moving
a local branch. Use local_branch to name the branch that tracks ref
when you do want a branch checked out.
3. Reset And Clean The Working Tree
Exhibit content trees accumulate stray files over time: a kiosk
application may write cache files, logs, or scratch state into the
content directory, and a previous sync may leave behind files that no
longer exist upstream. Set reset and clean so every sync starts
from a pristine copy of ref:
tasks:
- name: Sync and reset exhibit content
uses: preflight/git-sync
with:
repo: https://github.com/example/content.git
dest: C:\Exhibits\Content
ref: main
reset: true
clean: true
clean_ignored: truereset: true hard-resets the working tree to the resolved ref,
discarding local modifications. clean: true removes untracked files
after checkout; add clean_ignored: true to also remove files that
match .gitignore patterns, such as cached thumbnails an exhibit
viewer generates locally.
Set fetch: true (the default when the repository already exists) to
fetch remote updates before resolving ref, and prune: true alongside
it to drop local references to branches deleted upstream. Use depth
to limit fetch/clone to a shallow history when the full commit history
of an exhibit content repository is not needed.
4. Run As The Exhibit Account
By default, preflight/git-sync runs as whichever account executes
the task. If exhibit content should be owned by a dedicated kiosk
account rather than the transport account, add become to the task.
See Run Tasks As Another User for the
full pattern; preflight/git-sync does not need any special handling
beyond the standard become fields.
5. Understand Safe Directory Handling
preflight/git-sync adds dest to Git’s global safe.directory list
before running sync checks, because safe_directory defaults to
true. This avoids Git for Windows “dubious ownership” failures when
the checkout is owned by a different Windows account than the one
running the sync — a common situation when provisioning runs as an
administrator but the exhibit app runs under a kiosk account. Set
safe_directory: false only if your environment already manages the
safe.directory list another way.
Sync On A POSIX Target
preflight/git-sync targets Windows. On a POSIX target over SSH, run
git directly with the shell module, using creates: to make the
clone idempotent:
tasks:
- name: Clone content repository
shell:
cmd: git
args:
- clone
- https://github.com/example/content.git
- /opt/exhibits/content
creates: /opt/exhibits/content/.git
- name: Pull latest content
shell:
cmd: git
args: ["-C", "/opt/exhibits/content", "pull", "--ff-only"]The pull task runs on every apply; that is a stated tradeoff of the
manual pattern, not a bug. Wrap it in when: or a powershell
check_script if the extra network call matters.
Troubleshooting
Sync fails with a “dubious ownership” error even though
safe_directory is enabled. Confirm you did not explicitly set
safe_directory: false on the task, and that dest matches the exact
path git reports as unsafe — a trailing slash or a different casing of
a drive letter can produce a path git treats as distinct.
reset/clean removed content the kiosk generated at runtime.
This is expected: reset and clean return the working tree to
exactly what ref contains upstream. Store any state the kiosk
application needs to keep across syncs outside of dest, such as in a
sibling directory the action does not manage.
Task reports success but the target is still on the old commit.
Check that fetch is not disabled and that ref resolves to the
commit you expect on the remote; preflight/git-sync only fetches
remote updates when fetch is enabled for an existing repository.
Related Docs
- Configure Git Credentials For A Target —
authenticating
preflight/git-syncagainst private repositories - Embedded Stdlib Action Reference —
full
preflight/git-syncinput table - Run Tasks As Another User — using
becomeso synced content is owned by the right account - Built-in module reference —
winget_package,packagefor installinggititself