Sometimes a skel-included pipeline needs a fresh run — e.g. after fixing
something in skel itself — without any actual code change in the
project that includes it. include: files are resolved once, when the
pipeline is created; retrying a failed job/pipeline reuses that
already-resolved config, so it won't pick up a fix pushed to skel after
the fact. You need a new pipeline, not a retry.
Option 1: Run pipeline from the UI (preferred)¶
CI/CD → Pipelines → Run pipeline, on the branch you want (usually
main). Creates a new pipeline against the current tip, re-resolving
every include: fresh. No commit, no code change.
Option 2: Empty commit¶
If you need a push-triggered pipeline specifically (e.g. scripting this,
or a rule that only fires on push events):
git commit --allow-empty -m "chore: trigger rebuild (no code changes)"
git push
--allow-empty commits with no working-tree changes — git just creates a
new commit object pointing at the same tree as its parent. Pushing it
triggers a normal push pipeline, resolving include: against the current
state of whatever it references.
Option 3: Pipeline trigger token (for automation)¶
For scripted/automated reruns with no git operation at all, create a pipeline trigger token (Settings → CI/CD → Pipeline triggers) and:
curl -X POST \
-F token=<trigger-token> \
-F ref=main \
https://gitlab.com/api/v4/projects/<project-id>/trigger/pipeline
Why "Run pipeline" works but "Retry" doesn't¶
Whenever a pipeline is created — by a push, a schedule, the API, or clicking "Run pipeline" — GitLab does two things once, at that exact moment, and then freezes them for the lifetime of that pipeline:
-
Resolves the ref to a specific commit SHA. Telling it to run on
mainlocks the pipeline to whatever commitmainpoints to right now. Visible in the job log asChecking out <sha> as detached HEAD (ref is main). -
Resolves and merges every
include:. For an include with noref:pinned, GitLab fetches whatever's currently on the included project's default branch at that same moment, and bakes the result into this pipeline's final, merged configuration.
Once both are resolved, the pipeline is fully defined and nothing about
it changes afterward — even if new commits land on main in either repo
while it's queued, running, or sitting there finished.
Retry is the snapshot. Retrying a job or pipeline reruns the exact
same job against the exact same already-resolved commit SHA and the exact
same already-resolved include: content from whenever that pipeline was
originally created. It has no mechanism to re-fetch anything — which is
why retrying after fixing skel didn't help: the pipeline being retried
had already frozen in the old, broken version of the included file before
the fix existed.
"Run pipeline" (and any newly created pipeline) is the opposite — a
request to do the whole resolution process over again, from scratch,
right now. main gets re-resolved to its current tip, and every
include: gets re-fetched fresh.
Caveat: this depends on includes not pinning a ref:¶
The "always fetches current" behavior only holds because an include like
include:
- project: 'andrewmercer/skel'
file: '/release/.gitlab-ci-auto-release.yml'
has no ref:, so it defaults to the included project's default branch.
If an include is ever pinned instead —
include:
- project: 'andrewmercer/skel'
file: '/release/.gitlab-ci-auto-release.yml'
ref: v1.2.0 # or a specific commit SHA
— then even a brand-new "Run pipeline" keeps resolving to that pinned version forever, until the pin itself is bumped in the including project. That's a deliberate tradeoff some teams make for stability (nothing upstream can silently break your pipeline), but it means "just click Run pipeline to pick up the fix" stops working — the pin has to be bumped explicitly instead.