Resolving conflicts in large rebases, large binary files (Git LFS), enforcing code quality in Git workflows, triggering builds on PRs, Jenkins secrets and parallel stages, rolling deployments from Jenkins, GitHub Actions vs Jenkins, reusable workflows, conditional jobs, dependency caching, coverage and SonarQube in Actions, release gating, infrastructure as code, GitOps, verifying production deployments, and fast, safe rollbacks.
Published September 25, 2026
Senior CI/CD answers are about flow, safety and feedback:
Tools change; the principles don't.
Short answer:
main), keep branches short-lived, and split big refactors from feature work.git rebase main stops at each conflicting commit;git add, then git rebase --continue;git rebase --abort to bail out safely.git rerere (reuse recorded resolutions: git config rerere.enabled true), which replays your earlier resolutions when the same conflict recurs;git mergetool);git log -p --merge and git diff --diff-filter=U to understand both sides;-X ours|theirs strategy options for bulk, mechanical conflicts (with care).main into the branch instead of rebasing (it keeps the history, with one conflict resolution).git push --force-with-lease (never a plain --force) for shared branches, after coordinating with the teammates.Learn it in depth → CI/CD Pipeline System
Short answer: Git stores every version of every file in full history, so large binaries (models, media, datasets, JARs) bloat the repository, and slow clones forever. Options:
git lfs track "*.psd" (committed in .gitattributes).git filter-repo (or BFG). This rewrites the history, so coordinate a force-push, and ask everyone to re-clone.Short answer: Automate the gates, and make the path to merge the only path to production:
main:
Short answer:
on: pull_request: { branches: [main], paths: ['orders/**'] } (plus push to main). Required checks are configured in branch protection. For forks, understand the difference between pull_request and pull_request_target (the latter has secrets, so don't check out untrusted code with it).rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" (merge request pipelines), and merged-results pipelines.Short answer:
Jenkinsfile (pipeline { agent … stages { stage { steps } } post { … } }) is structured, validated and readable, and it's the recommended option. Scripted (Groovy node {}) is flexible, but harder to maintain. Put the pipeline in the repository (pipeline as code), and share logic through shared libraries.withCredentials([...]) or environment { TOKEN = credentials('id') }, so they're masked in the logs;echo secrets, and avoid them in the Groovy string interpolation that ends up in the logs;stage('Checks') {
parallel {
stage('Unit tests') { steps { sh './mvnw -B test' } }
stage('Static analysis') { steps { sh './mvnw -B spotbugs:check checkstyle:check' } }
stage('Dependency scan') { steps { sh './mvnw -B org.owasp:dependency-check-maven:check' } }
}
}
Use failFast true to stop the siblings on failure, and separate agents to spread the load.
Short answer: Don't script the rollout in Jenkins itself. Let the platform do rolling updates, and have the pipeline trigger and verify them:
kubectl set image, helm upgrade, or better, a GitOps commit to the environment repository);RollingUpdate strategy (maxUnavailable: 0, maxSurge: 25%) plus readiness probes roll the pods gradually;kubectl rollout status, runs smoke tests, and checks metrics. On failure, it runs kubectl rollout undo (or reverts the GitOps commit).Short answer:
.github/workflows, triggered by repository events (push, PR, release, schedule, workflow_dispatch), running jobs on GitHub-hosted or self-hosted runners, composed from reusable actions in the marketplace. It integrates natively with PRs, checks, OIDC to cloud providers (no stored cloud keys), environments with approval rules, and secrets.Short answer: Define a workflow with on: workflow_call, declaring inputs, secrets and outputs, then call it from other workflows (in the same or other repositories) with uses: org/repo/.github/workflows/java-ci.yml@v1. For step-level reuse, write composite actions (action.yml, with runs.using: composite). Version them with tags, and keep them in a central "platform" repository.
# .github/workflows/java-ci.yml (reusable)
on:
workflow_call:
inputs:
java-version: { type: string, default: '21' }
secrets:
SONAR_TOKEN: { required: true }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: ${{ inputs.java-version }}, cache: maven }
- run: ./mvnw -B verify
# Caller:
# jobs:
# ci:
# uses: shop/platform/.github/workflows/java-ci.yml@v1
# secrets: inherit
Short answer:
on.push.branches, paths/paths-ignore (monorepos), tags.if: github.ref == 'refs/heads/main', if: contains(github.event.pull_request.labels.*.name, 'deploy-preview'), if: failure()/always()/success().needs:, with outputs from earlier jobs (for example, a change-detection job using dorny/paths-filter, which sets outputs that other jobs check).environment: production, with required reviewers and wait timers as a manual approval gate.workflow_dispatch inputs for manual runs.Short answer:
actions/setup-java with cache: maven or cache: gradle caches ~/.m2/repository or ~/.gradle/caches, keyed by the hash of pom.xml/*.gradle* files.actions/cache, for custom paths, with explicit key and restore-keys (a fallback prefix).gradle/actions/setup-gradle (it caches smartly, and supports the remote build cache and configuration cache).docker/build-push-action with cache-from/cache-to: type=gha (or a registry cache).Short answer:
- run: ./mvnw -B verify jacoco:report # tests + JaCoCo XML
- name: SonarQube / SonarCloud scan
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # PR decoration
run: ./mvnw -B sonar:sonar -Dsonar.projectKey=shop_orders -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
actions/checkout with fetch-depth: 0 gives accurate new-code detection and blame.-Dsonar.qualitygate.wait=true fails the job if the gate fails, and branch protection requires the check.check goal with minimum ratios.Short answer: Automated or manual checkpoints that a release must pass before it progresses to the next environment or to more traffic:
Good gates are fast, objective and automated. Manual approvals are kept for the genuinely risky or regulated steps.
Short answer:
Infrastructure as code: infrastructure (networks, clusters, databases, IAM, DNS) is defined in version-controlled files, and provisioned by tools: Terraform/OpenTofu, Pulumi, AWS CloudFormation/CDK, Bicep, Crossplane. The benefits:
Practices:
GitOps: Git is the single source of truth for the desired state of deployments and configuration. An agent in the cluster (Argo CD, Flux) continuously reconciles the live state with Git: it pulls changes, applies them, and reverts drift. Deployments become Git commits (pull requests to an environment repository), rollback is git revert, and there's a full audit history. CI builds images, and updates the image tags in the GitOps repository (Argo CD Image Updater or Renovate). The cluster credentials stay inside the cluster (a pull model), which improves security.
Learn it in depth → Infrastructure as Code Awareness
Short answer:
Short answer: Be prepared before the incident:
kubectl rollout undo, helm rollback, a GitOps git revert, blue-green traffic switched back, or an automated canary abort. Target minutes.The process:
Learn it in depth → Deployment Strategies
Q: Trunk-based development or Git Flow? A: Trunk-based development (short-lived branches, and merging to main at least daily, with feature flags) enables continuous delivery, and reduces merge pain. Git Flow's long-lived develop and release branches suit scheduled, versioned releases (packaged software, mobile) better than continuously deployed services.
Q: What is a merge queue? A: A system (GitHub merge queue, GitLab merge trains, Bors) that tests each PR combined with the PRs ahead of it before merging, so main never breaks because of two individually green PRs that conflict semantically.
Q: How do you keep CI fast as the codebase grows? A: Parallelise jobs, cache dependencies and builds (Gradle remote cache), build only what changed (affected modules), split slow integration or e2e suites into separate or nightly jobs, quarantine flaky tests, and use bigger runners where it pays off.
Q: What's the difference between continuous delivery and continuous deployment? A: Continuous delivery means every change is deployable (automated pipeline to production-ready, with a manual release decision). Continuous deployment automatically deploys every change that passes the pipeline to production.