Git
Git is the most common source Terragrunt fetches and has the richest support in the CAS.
Overview
Section titled “Overview”A Git source is identified by a remote URL and a ref (a branch, tag, or commit). Terragrunt resolves that ref to a commit hash, which serves as both the cache key and the Git object name it fetches. Content keeps Git’s native content addressing, so identical objects are shared across repositories and refs.
Source URL parameters
Section titled “Source URL parameters”A Git source URL may carry go-getter query parameters that Terragrunt consumes to resolve the source rather than passing them through to git.
-
refselects the revision to resolve and check out, which can be a branch, tag, or commit. For example,...vpc.git?ref=v5.21.0. -
depthis accepted for go-getter compatibility, for example...vpc.git?ref=v5.21.0&depth=1. Likeref, it is a go-getter parameter rather than a native Git URL parameter, so the CAS strips it from the URL before invokinggit. Left in place,gittreats the trailing?depth=1as part of the repository name and rejects the clone. The value itself is never applied. Clone depth comes solely from the--cas-clone-depthflag, whose default of1applies whether or not you pass it.
The cheap probe
Section titled “The cheap probe”The probe Terragrunt uses to attempt to avoid fetching Git sources is git ls-remote. This asks the remote what commit a branch or tag currently points at without transferring any repository objects. The resolved commit hash becomes the cache key.
Two special cases bypass or extend the probe:
- Pinned commit SHA already cached. If you pin to a full commit SHA and that commit is already in the local store, Terragrunt answers from the store and skips
ls-remoteentirely, so the resolution stays offline. This is especially useful if you plan to use Terragrunt in an air-gapped environment. - Commit SHA.
ls-remoteonly lists named refs. If it returns no match (you supplied a commit SHA directly), Terragrunt defers resolution to the fetch step, which canonicalizes the ref withgit rev-parseagainst the local store once the objects have arrived.
Shared probes and reads. Units in one run that resolve the same URL and ref at the same time share a single ls-remote, and units that need the same commit share a single read of it into the store. The first unit to ask does the work and the others wait for its answer. A unit that starts after that answer has arrived probes again unless a recorded answer covers it (see the probe cache below), so a run --all over hundreds of units that point at one branch costs one probe for each group of units that start together, and at most one fetch. A unit that is cancelled while waiting stops waiting; the shared work carries on for the units still depending on it.
The probe cache. With the offline-cas experiment enabled, each ls-remote answer is recorded under probes/ in the store, keyed by URL and ref. Recorded probes covers the rules every source follows and the flags that change them; two things are specific to Git:
- A semantic version tag (
v1.2.3or1.2.3, with an optional pre-release or build suffix) is the pinned case, trusted for 24 hours. Only a tag qualifies.ls-remotelists a branch of a given name ahead of the tag, so a branch named like a version resolves as a branch and keeps being probed. - Under
--cas-offline, a pinned commit SHA is looked up in the local bare repository before the recorded answers are consulted, so a commit already fetched resolves without either.
Entries are filed under the repository with credentials stripped, so a token rotated between runs still finds the answer recorded for the repository it addresses.
Cache key & deduplication
Section titled “Cache key & deduplication”The cache key for the root tree is the commit hash itself, content-addressed by Git’s native scheme. Both SHA-1 and SHA-256 repositories are supported, with the algorithm detected per repository. Because the commit hash is content-addressed, the same commit reached through two repositories or two refs resolves to the same stored tree, and identical file blobs are shared across every repository that contains them.
Cache miss
Section titled “Cache miss”On a miss, Terragrunt fetches into a central bare repository kept per remote URL under git/ in the store (initialized on first use), holding a per-URL lock for the duration:
- Branch and tag refs use a shallow fetch. A full commit SHA is asked for on its own, one commit deep, which transfers that commit rather than every branch and tag. Remotes that will not serve a commit by name, such as an older or locked-down server, fall back to the full-history fetch, so a pinned SHA resolves either way.
- The blobs and trees reachable from the commit are extracted and stored, partitioned by hash prefix.
- The tree is read back from the store and hard linked into the target directory.
Cache hit
Section titled “Cache hit”When the commit hash is already keyed in the store, Terragrunt reads the tree and hard links its blobs into the target without fetching again from the remote. For a pinned commit SHA that is already cached, even the ref-resolution step stays offline.
With the offline-cas experiment enabled, a semantic version tag probed within the last 24 hours also skips the remote, since its recorded answer is served instead of a fresh ls-remote. See Recorded probes for which sources are cached and for how long.
Submodules
Section titled “Submodules”A submodule is recorded in the parent repository as a pointer to a commit in another repository. During a fetch, Terragrunt reads the submodule URL from .gitmodules, fetches the pinned commit from that URL into the same central store layout, and materializes the submodule contents in place. Nested submodules are handled the same way, and relative URLs (such as ../sibling.git) are resolved against the parent repository URL.
Each submodule tree is keyed by its pinned commit hash, so submodule contents are deduplicated like any other content: two repositories pinning the same submodule commit share one stored tree, and a submodule that does not change between parent commits is never fetched again.
A committed submodule path with no .gitmodules entry (typically an accidentally committed nested repository) becomes an empty directory, the same result a plain git clone produces.
Fallback behavior
Section titled “Fallback behavior”Units in one run that need the same commit share one read of it into the store; the rest wait for the first to finish. Separate Terragrunt processes coordinate through a per-URL lock on the central repository: a process that takes the lock after another has already fetched the commit finds it present and does not fetch it again. If the central repository cannot be used, because the lock is held for more than five minutes or the fetch fails, Terragrunt logs a warning and falls back to a plain clone in a temporary directory. With --cas-offline, a commit the store lacks is an error and no clone is attempted. If the host cannot hard link from the store (for example across a filesystem boundary), Terragrunt copies the content instead.