Skip to content

New blog post: Trunk-Based Development + GitLab + GitOps as the default workflow#105

Draft
Copilot wants to merge 13 commits into
gh-pagesfrom
copilot/create-new-blog-post-trunk-based-development
Draft

New blog post: Trunk-Based Development + GitLab + GitOps as the default workflow#105
Copilot wants to merge 13 commits into
gh-pagesfrom
copilot/create-new-blog-post-trunk-based-development

Conversation

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Follow-up to Why I Think Git Flow Doesn't Fit Most Projects Anymore — this post provides the concrete replacement workflow.

New post (2026-04-16-trunk-based-development-gitlab-gitops.md)

Covers the full opinionated stack: single main branch, ephemeral per-MR environments, GitLab-owned releases (RC → val → preprod → prod), GitOps via ArgoCD/Helm/Kubernetes, cherry-pick-based maintenance branches, and Jira/conventional-commits traceability alignment.

All git diagrams use Conventional Commits Option B style with Jira refs: feat(ABC-123): description, fix(ABC-456): description, release: v1.x.y.

Includes 8 Mermaid diagrams:

  • Git branching model (feature → main) — uses Option B commit style
  • Ephemeral env lifecycle (sequence: CI → deploy → seed → test → destroy)
  • Release promotion flow (RC → environments → GA)
  • GitOps pipeline (CI build → GitOps repo update → ArgoCD → k8s rollout)
  • Maintenance branching (release/vX.Y.Z + cherry-pick) — vertical gitGraph TB with 🍒 cherry-pick prefix, parallelCommits: true, and Option B commit style
  • Jira version ↔ GitLab release alignment
  • Full Picture flowchart — end-to-end developer workflow with yes/no validation gates: after promoting to val (Run tests on valVal OK? → preprod or back to dev) and after promoting to preprod (e2e tests on preprodPreprod OK? → release to production or restore prod version and back to dev)
  • Complete git timeline (vertical gitGraph TB): feature MRs with Option B conventional commits + Jira refs (feat(ABC-101): ..., fix(ABC-105): ...), a blocked MR with dev test failures (type: REVERSE), RC1→RC2→RC3 with per-environment 🟢/🔴 validation indicators in commit and tag labels, final release tag (v1.4.0), a release/v1.4.x maintenance branch with a cherry-picked hotfix promoted through preprod to v1.4.1, and a trailing v1.5.0-rc.1 with a failing val. Styled via a Mermaid %%{init}%% theme config (git1: #ffbe28, git2: #ff0000, parallelCommits: true).

Mermaid.js support (templates/layouts/main.html)

Added Mermaid v11 via CDN (ESM). Since the Roq/Qute Markdown renderer emits <pre><code class="language-mermaid"> rather than <div class="mermaid">, a small synchronous DOM pre-pass converts them before mermaid.initialize runs:

<script type="module">
  import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
  // Convert markdown-rendered code blocks to mermaid divs (synchronous, completes before initialize)
  const codeBlocks = Array.from(document.querySelectorAll('pre > code.language-mermaid'));
  codeBlocks.forEach(el => {
    const div = document.createElement('div');
    div.className = 'mermaid';
    div.textContent = el.textContent;
    el.parentElement.replaceWith(div);
  });
  mermaid.initialize({ startOnLoad: true, theme: 'default' });
</script>

Bug fix

Mermaid decision-node syntax ({...}) and %%{init}%% configuration directives inside Mermaid code blocks were being interpreted as Qute template expressions, causing a 500 error on page render. Fixed by escaping all curly braces in Mermaid content with \{ / \} so Qute outputs them as literals.

Copilot AI changed the title [WIP] Create blog post on trunk-based development with GitLab and GitOps New blog post: Trunk-Based Development + GitLab + GitOps as the default workflow Apr 16, 2026
@sunix

sunix commented Apr 16, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown

Preview build failed.

🔗 View workflow run

Copilot AI requested a review from sunix April 16, 2026 16:43
@sunix

sunix commented Apr 16, 2026

Copy link
Copy Markdown
Owner

@copilot
there is a error could you fix it

2026-04-16 16:34:58,470 ERROR [io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler] (executor-thread-3) Error occurred while rendering the template [posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.md]: io.quarkus.qute.TemplateException: Rendering error in template [roq-templates/full/posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.html:103]: Key "Ready" not found in the template data map with keys [site, now, roqVersion, page, locale] in expression {Ready.to(release?)}
2026-04-16 16:34:58,475 ERROR [io.quarkus.vertx.http.runtime.QuarkusErrorHandler] (vert.x-eventloop-thread-0) HTTP Request to /posts/why-trunk-based-development-gitlab-gitops-is-probably-the-best-default-for-most-teams/ failed, error id: 6ebdf46a-a196-4892-8025-89c928b13fa3-1: io.quarkus.qute.TemplateException: Rendering error in template [roq-templates/full/posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.html:103]: Key "Ready" not found in the template data map with keys [site, now, roqVersion, page, locale] in expression {Ready.to(release?)}
	at io.quarkus.qute.TemplateException$Builder.build(TemplateException.java:173)
	at io.quarkus.qute.EvaluatorImpl.propertyNotFound(EvaluatorImpl.java:234)
	at io.quarkus.qute.EvaluatorImpl.resolve(EvaluatorImpl.java:204)
	at io.quarkus.qute.EvaluatorImpl.resolveReference(EvaluatorImpl.java:131)
	at io.quarkus.qute.EvaluatorImpl.lambda$resolveReference$2(EvaluatorImpl.java:135)
	at io.quarkus.qute.CompletedStage.thenCompose(CompletedStage.java:252)
	at io.quarkus.qute.EvaluatorImpl.resolveReference(EvaluatorImpl.java:135)
	at io.quarkus.qute.EvaluatorImpl.evaluate(EvaluatorImpl.java:85)
	at io.quarkus.qute.ResolutionContextImpl$ChildResolutionContext.evaluate(ResolutionContextImpl.java:100)
	at io.quarkus.qute.ExpressionNode.resolve(ExpressionNode.java:36)
	at io.quarkus.qute.Results.doResolveWith(Results.java:133)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkiverse.qute.web.markdown.runtime.MarkdownSectionHelperFactory$MarkdownSectionHelper.resolve(MarkdownSectionHelperFactory.java:65)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.InsertSectionHelper.resolve(InsertSectionHelper.java:28)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.InsertSectionHelper.resolve(InsertSectionHelper.java:28)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.IncludeSectionHelper.resolve(IncludeSectionHelper.java:51)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.IncludeSectionHelper.resolve(IncludeSectionHelper.java:51)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderData(TemplateImpl.java:292)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderAsyncNoTimeout(TemplateImpl.java:254)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderAsync(TemplateImpl.java:227)
	at io.quarkus.qute.runtime.TemplateProducer$InjectableTemplate$InjectableTemplateInstanceImpl.renderAsync(TemplateProducer.java:381)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handlePage(RoqRouteHandler.java:160)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handle(RoqRouteHandler.java:98)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handle(RoqRouteHandler.java:42)
	at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$5(ContextImpl.java:205)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
	at io.vertx.core.impl.ContextImpl$1.execute(ContextImpl.java:221)
	at io.vertx.core.impl.WorkerTask.run(WorkerTask.java:56)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:645)
	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
	at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)
2026-04-16 16:34:58,477 ERROR [io.quarkiverse.roq.generator.runtime.RoqGenerator] (vert.x-eventloop-thread-1) Roq request failed /posts/why-trunk-based-development-gitlab-gitops-is-probably-the-best-default-for-most-teams/: io.vertx.core.VertxException: Response status code 500 is not equal to 200
2026-04-16 16:34:58,482 ERROR [io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler] (executor-thread-3) Error occurred while rendering the template [posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.md]: io.quarkus.qute.TemplateException: Rendering error in template [roq-templates/full/posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.html:103]: Key "Ready" not found in the template data map with keys [site, now, roqVersion, page, locale] in expression {Ready.to(release?)}
2026-04-16 16:34:58,482 ERROR [io.quarkus.vertx.http.runtime.QuarkusErrorHandler] (vert.x-eventloop-thread-2) HTTP Request to /posts/why-trunk-based-development-gitlab-gitops-is-probably-the-best-default-for-most-teams/ failed, error id: 6ebdf46a-a196-4892-8025-89c928b13fa3-2: io.quarkus.qute.TemplateException: Rendering error in template [roq-templates/full/posts/2026-04-16-trunk-based-development-gitlab-gitops.md/index.html:103]: Key "Ready" not found in the template data map with keys [site, now, roqVersion, page, locale] in expression {Ready.to(release?)}
	at io.quarkus.qute.TemplateException$Builder.build(TemplateException.java:173)
	at io.quarkus.qute.EvaluatorImpl.propertyNotFound(EvaluatorImpl.java:234)
	at io.quarkus.qute.EvaluatorImpl.resolve(EvaluatorImpl.java:204)
	at io.quarkus.qute.EvaluatorImpl.resolveReference(EvaluatorImpl.java:131)
	at io.quarkus.qute.EvaluatorImpl.lambda$resolveReference$2(EvaluatorImpl.java:135)
	at io.quarkus.qute.CompletedStage.thenCompose(CompletedStage.java:252)
	at io.quarkus.qute.EvaluatorImpl.resolveReference(EvaluatorImpl.java:135)
	at io.quarkus.qute.EvaluatorImpl.evaluate(EvaluatorImpl.java:85)
	at io.quarkus.qute.ResolutionContextImpl$ChildResolutionContext.evaluate(ResolutionContextImpl.java:100)
	at io.quarkus.qute.ExpressionNode.resolve(ExpressionNode.java:36)
	at io.quarkus.qute.Results.doResolveWith(Results.java:133)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkiverse.qute.web.markdown.runtime.MarkdownSectionHelperFactory$MarkdownSectionHelper.resolve(MarkdownSectionHelperFactory.java:65)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.InsertSectionHelper.resolve(InsertSectionHelper.java:28)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.InsertSectionHelper.resolve(InsertSectionHelper.java:28)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:61)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.IncludeSectionHelper.resolve(IncludeSectionHelper.java:51)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.IncludeSectionHelper.resolve(IncludeSectionHelper.java:51)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.Results.doResolveWith(Results.java:136)
	at io.quarkus.qute.Results.resolveWith(Results.java:110)
	at io.quarkus.qute.Results.resolveAndProcess(Results.java:54)
	at io.quarkus.qute.SectionNode$SectionResolutionContextImpl.execute(SectionNode.java:254)
	at io.quarkus.qute.SectionHelper$SectionResolutionContext.execute(SectionHelper.java:66)
	at io.quarkus.qute.Parser$1.resolve(Parser.java:1340)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:57)
	at io.quarkus.qute.SectionNode.resolve(SectionNode.java:68)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderData(TemplateImpl.java:292)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderAsyncNoTimeout(TemplateImpl.java:254)
	at io.quarkus.qute.TemplateImpl$TemplateInstanceImpl.renderAsync(TemplateImpl.java:227)
	at io.quarkus.qute.runtime.TemplateProducer$InjectableTemplate$InjectableTemplateInstanceImpl.renderAsync(TemplateProducer.java:381)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handlePage(RoqRouteHandler.java:160)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handle(RoqRouteHandler.java:98)
	at io.quarkiverse.roq.frontmatter.runtime.RoqRouteHandler.handle(RoqRouteHandler.java:42)
	at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$5(ContextImpl.java:205)
	at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
	at io.vertx.core.impl.ContextImpl$1.execute(ContextImpl.java:221)
	at io.vertx.core.impl.WorkerTask.run(WorkerTask.java:56)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:645)
	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
	at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot
there is a error could you fix it

...

Fixed in commit f381214.

The Qute template engine was interpreting the Mermaid decision-node syntax like C{Ready to release?} as template expressions. Escaped all three occurrences with \{...\} so Qute outputs them as literal curly braces while Mermaid still renders the diamond shapes correctly.

@sunix

sunix commented Apr 16, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown

🚀 Preview deployed successfully!

🌐 Preview: https://pr-105-sunix-blog-preview.surge.sh

@sunix

sunix commented Apr 16, 2026

Copy link
Copy Markdown
Owner

@copilot could you add a final git tree (vertical) that will summarize everything:

  • some MR branch with several commit but rebased and merged in main with conventional commit + jira-ref. Indicate that it had been validated in dev
  • a MR with several commit that can not be merged because tests on dev failed
  • some MR commit that had been squashed and rebased following conventional commit + jira ref.
  • some commit tagged RC in the tree: RC1, RC2, RC3, indicates in which env it had been deployed, and in each env if validation succeeded or failed (maybe name green/red),
  • and for the last RC, preprod green and a new tag for the final Release
  • for this releases a maintenance branch for hot fixed cherry picked from other commit in main, release a minor version RC deployed in preprod and if ok released final minor version.

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot could you add a final git tree (vertical) that will summarize everything:

  • some MR branch with several commit but rebased and merged in main with conventional commit + jira-ref. Indicate th...

Added in commit 4871c22 — new section "The Complete Git Timeline" with a vertical gitGraph TB diagram covering:

  • feature/ABC-101 → 3-commit branch rebased and merged to main as a conventional commit + Jira ref (🟡 highlighted = dev validated ✅)
  • feature/ABC-102 → MR with a 🔴 red commit (dev test failure ❌), never merged to main
  • squash+rebase commit → multi-commit MR collapsed to a single clean conventional commit on main
  • RC1 (dev-OK val-FAIL) → fix → RC2 (dev-OK val-OK preprod-FAIL) → fix → RC3 (dev-OK val-OK preprod-OK) → v1.4.0
  • release/v1.4.x maintenance branch: hotfix committed first to main, cherry-picked to the release branch, RC validated in preprod → v1.4.1

A short legend below the diagram explains the highlighted/red commit types.

@sunix

sunix commented Apr 16, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown

🚀 Preview deployed successfully!

🌐 Preview: https://pr-105-sunix-blog-preview.surge.sh

@sunix

sunix commented Apr 17, 2026

Copy link
Copy Markdown
Owner

@copilot ok for the final schema could you replaced with

gitGraph TB:
    commit id: "feat: bootstrap 🟢dev"

    branch feature/ABC-101
    checkout feature/ABC-101
    commit id: "wip: auth service 🟢dev"
    commit id: "wip: refresh .. 🟢dev"
    commit id: "test: unit tests 🟢dev"
    checkout main
    merge feature/ABC-101 id: "feat: user auth - 🟢dev"

    checkout main
    commit id: "feat: dashboard - 🟢dev"

    branch feature/ABC-102
    checkout feature/ABC-102
    commit id: "wip: billing module 🔴dev"
    commit id: "fix: tests 🔴dev" type: REVERSE

    checkout main
    commit id: "feat: settings 🟢dev"

    commit id: "release: v1.4.0-rc.1 🟢dev" tag: "v1.4.0-rc.1 🔴val"
    commit id: "fix: token expiry 🟢dev"
    commit id: "release: v1.4.0-rc.2 🟢dev" tag: "v1.4.0-rc.2 🟢val 🔴preprod"
    commit id: "fix: memory leak 🟢dev"
    commit id: "release: v1.4.0-rc.3 🟢dev" tag: "v1.4.0-rc.3 🟢val 🟢preprod"
    commit id: "release: v1.4.0 🟢dev" tag: "v1.4.0  🟢val 🟢preprod 🟢prod"

    branch release/v1.4.x

    checkout main
    commit id: "feat: admin backend 🟢dev"
    
    commit id: "fix: SQL injection"

    checkout release/v1.4.x
    cherry-pick id: "fix: SQL injection"
    commit id: "patch-rc-1" tag: "v1.4.1-rc.1 🟢preprod"
    commit id: "v1.4.1-release" tag: "v1.4.1 🟢preprod 🟢prod"

    checkout main
    commit id: "feat: billing 🟢dev"
    commit id: "release: v1.5.0-rc.1 🟢dev" tag: "v1.5.0-rc.1 🔴val"


and the configuration ( i don't know how to add this)

{
  "theme": "default",
   "themeVariables":
     {
     "git1": "#ffbe28",
     "git2": "#ff0000"
     }
}

…and Mermaid theme config

Agent-Logs-Url: https://github.com/sunix/blog.sunix.org/sessions/adbc310e-4ec0-4bee-9c43-bcee7be83222

Co-authored-by: sunix <650571+sunix@users.noreply.github.com>

Copilot AI commented Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

@copilot ok for the final schema could you replaced with

gitGraph TB:

...

Done in commit 1cde0b2. Replaced the diagram with your version and added the %%{init}%% theme config (with git1: #ffbe28 / git2: #ff0000). The {...} braces in the init directive are escaped as \{...\} so Qute doesn't interpret them as template expressions.

@sunix

sunix commented Apr 17, 2026

Copy link
Copy Markdown
Owner

@copilot last changes
in the diagram to illustrate maintenance branch, use these:

gitGraph TB:
   commit id: "release: v1.4.0"
   branch release/v1.4.0
   checkout release/v1.4.0
   commit id: "🍒 fix(ABC-789): critical bug"
   commit id: "release: v1.4.1"
   checkout main
   commit id: "fix(ABC-789): critical bug"
   commit id: "feat(ABC-790): new feature"

and

{
  "theme": "default",
  "gitGraph": {
    "parallelCommits": true
  }
}

… parallelCommits config

Agent-Logs-Url: https://github.com/sunix/blog.sunix.org/sessions/7952de9e-afba-463b-b16d-3c5283a764c6

Co-authored-by: sunix <650571+sunix@users.noreply.github.com>

Copilot AI commented Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

@copilot last changes
in the diagram to illustrate maintenance branch, use these:

...

Done in commit 1b8bfbe. Updated the maintenance branch diagram with:

  • 🍒 prefix on the cherry-picked commit
  • %%{init}%% config with theme: default and gitGraph: { parallelCommits: true }
  • gitGraph TB: vertical layout
  • fix(ABC-789): critical bug on main (without the (orig) suffix)

@sunix

sunix commented Apr 17, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 17, 2026

Copy link
Copy Markdown

🚀 Preview deployed successfully!

🌐 Preview: https://pr-105-sunix-blog-preview.surge.sh

Updated sections on releases, maintenance, and Git hygiene for clarity and emphasis on best practices.
@sunix

sunix commented Apr 18, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 18, 2026

Copy link
Copy Markdown

🚀 Preview deployed successfully!

🌐 Preview: https://pr-105-sunix-blog-preview.surge.sh

Removed unnecessary lines and adjusted formatting in the markdown file.
@sunix

sunix commented Apr 18, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 18, 2026

Copy link
Copy Markdown

🚀 Preview deployed successfully!

🌐 Preview: https://pr-105-sunix-blog-preview.surge.sh

@sunix

sunix commented Apr 28, 2026

Copy link
Copy Markdown
Owner

@copilot In the The Full Picture Flowchart , i would like to add yes/no steps after, Promote to val (Running on test on Val, yes --> promote to val, no --> go back to developer,
same after Promote to Preprod, maybe add "e2e test to validate in preprod" preprod should then release the final version and promoted to prod, or restore the prod version and go back to dev.

Copilot AI commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot In the The Full Picture Flowchart , i would like to add yes/no steps after, Promote to val (Running on test on Val, yes --> promote to val, no --> go back to developer,
same after Promote t...

Done in commit b38539d. The Full Picture flowchart now includes:

  • After Promote to valRun tests on valVal OK? diamond: Yes → Promote to preprod, No → back to Developer
  • After Promote to preprode2e tests on preprodPreprod OK? diamond: Yes → Release final version to production, No → Restore prod version → back to Developer

@sunix

sunix commented Apr 28, 2026

Copy link
Copy Markdown
Owner

/preview

@github-actions

github-actions Bot commented Apr 28, 2026

Copy link
Copy Markdown

Preview build failed.

🔗 View workflow run

@sunix

sunix commented Apr 28, 2026

Copy link
Copy Markdown
Owner

@copilot

The Full Picture flowchart after the release final version, should be promoted to preprod and prod
(preprod and prod should be aligned as much as possible)

…ide) in Full Picture flowchart

Agent-Logs-Url: https://github.com/sunix/blog.sunix.org/sessions/490aea65-1618-4aa0-be6c-c94ce0bc002e

Co-authored-by: sunix <650571+sunix@users.noreply.github.com>

Copilot AI commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot

The Full Picture flowchart after the release final version, should be promoted to preprod and prod
...

Done in commit 79a6e5c. After "Create final release tag", the diagram now branches into two parallel nodes: Deploy to preprod and Deploy to prod — both appear side by side and are highlighted in the same blue colour.

@sunix

sunix commented Apr 28, 2026

Copy link
Copy Markdown
Owner

@copilot for the Full Picture flowchart,
be precise with the version being deployed, promoted or restored in the applicable steps.
I can see RC tag is v1.4.0-rc.1 it means the final release is v1.4.0 and the current prod version should be something like 1.3.2.

Copilot AI commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

@copilot for the Full Picture flowchart,
be precise with the version being deployed, promoted or restored in the applicable steps.
I can see RC tag is v1.4.0-rc.1 it means the final release is v1.4...

Done in commit f9ec25b. The flowchart now shows precise versions in every applicable step:

  • Promote v1.4.0-rc.1 to val
  • Promote v1.4.0-rc.1 to preprod
  • Create final release tag v1.4.0
  • Restore prod version v1.3.2 (the previously running prod version)
  • Deploy v1.4.0 to preprod / Deploy v1.4.0 to prod

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New blog post : Why Trunk-Based Development + GitLab + GitOps Is (Probably) the Best Default for Most Teams

2 participants