Inline Pipeline versus Pipeline from SCM
Scenario: A production fix typed into the UI succeeds once but has no application review or rollback history.
Where should the Jenkinsfile actually live?
Jenkins technically allows you to paste your entire Pipeline script directly into a text box in the job's configuration UI. It works, and beginners often start there - but it quietly recreates the exact same "no review, no history" problem that Freestyle jobs had, just with Groovy instead of checkboxes.
Analogy: An inline Pipeline typed into the Jenkins UI is like writing an important recipe directly on a sticky note stuck to the fridge - anyone can edit it on the spot, with no record of what it said yesterday, and it vanishes completely if the fridge (the Jenkins controller) is ever replaced. A Jenkinsfile stored in the same Git repository as the application, reviewed through a pull request, is the recipe printed in the actual cookbook that ships with the kitchen - version-controlled, reviewable by a second person before anyone cooks from it, and it survives independently of any one particular kitchen.
This is why "Pipeline script from SCM" - pointing Jenkins at a Jenkinsfile stored in your Git repository - is the standard, recommended approach for any real project, rather than the inline text-box option.
Pipeline example
// Jenkinsfile stored with application source
pipeline { agent any; stages { stage('Revision') { steps { sh 'git rev-parse HEAD' } } } }
A Jenkinsfile belongs to a specific revision
An inline Pipeline lives directly in job configuration on the controller. It can be useful to bootstrap a very small administrative job, but application delivery logic edited in a text box lacks the application's own pull-request review history entirely - there's no diff, no reviewer, no "who approved this change and why." Pipeline from SCM instead points Jenkins to a repository, a credential to access it, a branch specification, and a script path (usually just Jenkinsfile). The Jenkinsfile is then reviewed and version-controlled right alongside the application source, so a build of commit abc123 genuinely uses the exact delivery contract that was reviewed for commit abc123 - not whatever happens to currently be sitting in the job's UI configuration.
The order of operations matters here
Jenkins first fetches just enough SCM data to load and parse the Jenkinsfile script itself, and then the Pipeline may separately perform a full workspace checkout as one of its own steps. Declarative Pipeline also performs a default checkout automatically unless skipDefaultCheckout is explicitly set - which means it's easy to accidentally trigger two checkouts of the same repository if you're not paying attention to this default. Avoid that accidental double checkout, and make sure the actual resolved commit SHA and repository URL get recorded somewhere visible in the build. Pin shared-library revisions (covered in a later module) separately from the Jenkinsfile itself - otherwise, an application repository's Jenkinsfile can stay completely unchanged while a shared library it references quietly starts executing new, privileged code underneath it.
[Pipeline] Start of Pipeline
[Pipeline] checkout
Selected Git installation does not exist. Using Default
Fetching changes from the remote Git repository
Checking out Revision a1b2c3d4 (refs/remotes/origin/main)
Commit message: "Fix flaky checkout test"
[Pipeline] { (Revision)
[Pipeline] sh
+ git rev-parse HEAD
a1b2c3d4e5f6...
This log fragment shows exactly what "Pipeline from SCM" gives you for free: the resolved commit SHA and its commit message appear directly in the build log, before any application-defined stage even starts - durable, automatic provenance you don't have to write yourself.
Replay is for diagnosis, not for shipping a fix
Jenkins' Replay feature reruns a past Pipeline with Groovy edits made live, right before re-execution - genuinely valuable for quickly diagnosing a problem without committing a dozen exploratory commits. But that replayed program is not a reviewed, version-controlled application revision - it exists only inside that one build's replay history. Once you've found the actual fix through Replay, commit that proven correction to the repository and let it run normally through the real pipeline before treating it as fixed. Protect who can modify the Jenkinsfile and the default branch, since changing CI instructions can effectively grant artifact-publication or deployment authority to whoever can merge that change.
A pitfall: chasing checkout failures in the wrong place
For checkout failures, separate the possible causes methodically: repository authentication, ref/branch resolution, webhook delivery, general network access, workspace corruption from a previous run, or simply a missing Jenkinsfile at the expected path. Preserve the checkout logs and the resolved SHA from before you start debugging, since re-running the job might change what you're looking at. A build's URL and its recorded commit together should be enough to reconstruct exactly which program ran and against which source - a one-off UI edit that "fixed it" but disappears after the next controller restart or config reload has failed this traceability standard, even if it made the immediate symptom go away.
Goal: Practice the concrete behavior in jenkins-scm-trigger-recovery. Learn sections have no Jenkins terminal; the Jenkins lab opens the real shared service in a new full-screen tab inside your private folder.