[{"data":1,"prerenderedAt":1987},["ShallowReactive",2],{"navigation:en":3,"\u002Fblog\u002Fgit-branching-stage-production-first-release":311},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Nuxfire Docs","\u002Fdocs","docs\u002F0.index",[9,11,152],{"title":5,"path":6,"stem":7,"icon":10},"i-lucide-layout-grid",{"title":12,"path":13,"stem":14,"children":15,"icon":151},"SaaS Starter Kit","\u002Fdocs\u002Fsaas-starter-kit","docs\u002F1.saas-starter-kit\u002F0.index",[16,19,63,129],{"title":17,"path":13,"stem":14,"icon":18},"What is the SaaS Starter Kit?","i-lucide-info",{"title":20,"icon":21,"hide":22,"path":23,"stem":24,"children":25,"page":62},"Getting Started","i-lucide-play",true,"\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started","docs\u002F1.saas-starter-kit\u002F1.getting-started",[26,30,34,38,42,46,50,54,58],{"title":27,"path":28,"stem":29},"Quick Start","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fquick-start","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F0.quick-start",{"title":31,"path":32,"stem":33},"Installation","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Finstallation","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F1.installation",{"title":35,"path":36,"stem":37},"Cloudflare Access","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fcloudflare-access","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F2.cloudflare-access",{"title":39,"path":40,"stem":41},"Configuration","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fconfiguration","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F3.configuration",{"title":43,"path":44,"stem":45},"Secrets","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fsecrets","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F4.secrets",{"title":47,"path":48,"stem":49},"Environment Variables","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fenvironment-variables","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F5.environment-variables",{"title":51,"path":52,"stem":53},"Deploy","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fdeploy","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F6.deploy",{"title":55,"path":56,"stem":57},"Local Development","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Flocal-development","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F7.local-development",{"title":59,"path":60,"stem":61},"Project Structure","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fproject-structure","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F8.project-structure",false,{"title":64,"icon":65,"hide":22,"path":66,"stem":67,"children":68,"page":62},"Features","i-lucide-box","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures","docs\u002F1.saas-starter-kit\u002F2.features",[69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":70,"path":71,"stem":72},"Authentication","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fauth","docs\u002F1.saas-starter-kit\u002F2.features\u002F1.auth",{"title":74,"path":75,"stem":76},"Rate Limiting","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frate-limiting","docs\u002F1.saas-starter-kit\u002F2.features\u002F10.rate-limiting",{"title":78,"path":79,"stem":80},"WebSockets","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fwebsockets","docs\u002F1.saas-starter-kit\u002F2.features\u002F11.websockets",{"title":82,"path":83,"stem":84},"Blog","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fblog","docs\u002F1.saas-starter-kit\u002F2.features\u002F14.blog",{"title":86,"path":87,"stem":88},"Documentation","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdocumentation","docs\u002F1.saas-starter-kit\u002F2.features\u002F15.documentation",{"title":90,"path":91,"stem":92},"Analytics","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fanalytics","docs\u002F1.saas-starter-kit\u002F2.features\u002F16.analytics",{"title":94,"path":95,"stem":96},"Platform Admin Console","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fplatform-admin","docs\u002F1.saas-starter-kit\u002F2.features\u002F17.platform-admin",{"title":98,"path":99,"stem":100},"Database","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdatabase","docs\u002F1.saas-starter-kit\u002F2.features\u002F2.database",{"title":102,"path":103,"stem":104},"Payments & Billing","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fpayments","docs\u002F1.saas-starter-kit\u002F2.features\u002F3.payments",{"title":106,"path":107,"stem":108},"Emails","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Femails","docs\u002F1.saas-starter-kit\u002F2.features\u002F4.emails",{"title":110,"path":111,"stem":112},"Notifications","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fnotifications","docs\u002F1.saas-starter-kit\u002F2.features\u002F5.notifications",{"title":114,"path":115,"stem":116},"Role-Based Access Control","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frbac","docs\u002F1.saas-starter-kit\u002F2.features\u002F6.rbac",{"title":118,"path":119,"stem":120},"Async Jobs","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fasync-jobs","docs\u002F1.saas-starter-kit\u002F2.features\u002F7.async-jobs",{"title":122,"path":123,"stem":124},"Storage","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fstorage","docs\u002F1.saas-starter-kit\u002F2.features\u002F8.storage",{"title":126,"path":127,"stem":128},"Internationalization","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Finternationalization","docs\u002F1.saas-starter-kit\u002F2.features\u002F9.internationalization",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":62},"Concepts","i-lucide-graduation-cap","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts","docs\u002F1.saas-starter-kit\u002F3.concepts",[135,139,143,147],{"title":136,"path":137,"stem":138},"Technology Stack","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Ftech-stack","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F0.tech-stack",{"title":140,"path":141,"stem":142},"SST.dev","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fsst","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F1.sst",{"title":144,"path":145,"stem":146},"NuxtHub","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fnuxt-hub","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F2.nuxt-hub",{"title":148,"path":149,"stem":150},"Design System & Branding","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fdesign-system","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F3.design-system","i-lucide-zap",{"title":153,"path":154,"stem":155,"children":156,"icon":159},"Fireskills","\u002Fdocs\u002Ffireskills","docs\u002F2.fireskills\u002F0.index",[157,160,219,249,275,293],{"title":158,"path":154,"stem":155,"icon":159},"What is Fireskills?","i-lucide-flame",{"title":20,"icon":21,"hide":22,"path":161,"stem":162,"children":163,"page":62},"\u002Fdocs\u002Ffireskills\u002Fgetting-started","docs\u002F2.fireskills\u002F1.getting-started",[164,167,171,175,179,183,187,191,195,199,203,207,211,215],{"title":27,"path":165,"stem":166},"\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fquick-start","docs\u002F2.fireskills\u002F1.getting-started\u002F00.quick-start",{"title":168,"path":169,"stem":170},"Workflow & Governance","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fworkflow","docs\u002F2.fireskills\u002F1.getting-started\u002F01.workflow",{"title":172,"path":173,"stem":174},"Project Context","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fproject-context","docs\u002F2.fireskills\u002F1.getting-started\u002F02.project-context",{"title":176,"path":177,"stem":178},"Step 0: Setup","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-setup","docs\u002F2.fireskills\u002F1.getting-started\u002F03.step-setup",{"title":180,"path":181,"stem":182},"Step 1: Inbox","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-inbox","docs\u002F2.fireskills\u002F1.getting-started\u002F04.step-inbox",{"title":184,"path":185,"stem":186},"Step 2: Backlog","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-backlog","docs\u002F2.fireskills\u002F1.getting-started\u002F05.step-backlog",{"title":188,"path":189,"stem":190},"Step 3: Specify","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-specify","docs\u002F2.fireskills\u002F1.getting-started\u002F06.step-specify",{"title":192,"path":193,"stem":194},"Step 4: Validate","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-validate","docs\u002F2.fireskills\u002F1.getting-started\u002F07.step-validate",{"title":196,"path":197,"stem":198},"Step 5: Tasks","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tasks","docs\u002F2.fireskills\u002F1.getting-started\u002F08.step-tasks",{"title":200,"path":201,"stem":202},"Step 6: TDD\u002FBDD","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tdd-bdd","docs\u002F2.fireskills\u002F1.getting-started\u002F09.step-tdd-bdd",{"title":204,"path":205,"stem":206},"Step 7: Implement","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-implement","docs\u002F2.fireskills\u002F1.getting-started\u002F10.step-implement",{"title":208,"path":209,"stem":210},"Step 8: Documentator","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-documentator","docs\u002F2.fireskills\u002F1.getting-started\u002F11.step-documentator",{"title":212,"path":213,"stem":214},"Late Changes","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Flate-changes","docs\u002F2.fireskills\u002F1.getting-started\u002F12.late-changes",{"title":216,"path":217,"stem":218},"Other Entry Points","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fother-entry-points","docs\u002F2.fireskills\u002F1.getting-started\u002F13.other-entry-points",{"title":220,"icon":221,"hide":22,"path":222,"stem":223,"children":224,"page":62},"Methodology","i-lucide-git-branch","\u002Fdocs\u002Ffireskills\u002Fmethodology","docs\u002F2.fireskills\u002F2.methodology",[225,229,233,237,241,245],{"title":226,"path":227,"stem":228},"The Three Acts","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-acts","docs\u002F2.fireskills\u002F2.methodology\u002F0.three-acts",{"title":230,"path":231,"stem":232},"The Three Gates","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-gates","docs\u002F2.fireskills\u002F2.methodology\u002F1.three-gates",{"title":234,"path":235,"stem":236},"The Canonical Spec","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fcanonical-spec","docs\u002F2.fireskills\u002F2.methodology\u002F2.canonical-spec",{"title":238,"path":239,"stem":240},"Lifecycle States","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Flifecycle-states","docs\u002F2.fireskills\u002F2.methodology\u002F3.lifecycle-states",{"title":242,"path":243,"stem":244},"Effort Scale","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Feffort-scale","docs\u002F2.fireskills\u002F2.methodology\u002F4.effort-scale",{"title":246,"path":247,"stem":248},"Milestones & Governance","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fgovernance-and-milestones","docs\u002F2.fireskills\u002F2.methodology\u002F5.governance-and-milestones",{"title":250,"icon":251,"hide":22,"path":252,"stem":253,"children":254,"page":62},"Skills","i-lucide-layers","\u002Fdocs\u002Ffireskills\u002Fskills","docs\u002F2.fireskills\u002F3.skills",[255,259,263,267,271],{"title":256,"path":257,"stem":258},"Catalog","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fcatalog","docs\u002F2.fireskills\u002F3.skills\u002F0.catalog",{"title":260,"path":261,"stem":262},"Act I: Define","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-1-define","docs\u002F2.fireskills\u002F3.skills\u002F1.act-1-define",{"title":264,"path":265,"stem":266},"Act II: Design & Prove","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-2-design-prove","docs\u002F2.fireskills\u002F3.skills\u002F2.act-2-design-prove",{"title":268,"path":269,"stem":270},"Act III: Deliver","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-3-deliver","docs\u002F2.fireskills\u002F3.skills\u002F3.act-3-deliver",{"title":272,"path":273,"stem":274},"Governance & Decisions","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fgovernance-and-decisions","docs\u002F2.fireskills\u002F3.skills\u002F4.governance-and-decisions",{"title":276,"icon":277,"hide":22,"path":278,"stem":279,"children":280,"page":62},"Specialists","i-lucide-sparkles","\u002Fdocs\u002Ffireskills\u002Fspecialists","docs\u002F2.fireskills\u002F4.specialists",[281,285,289],{"title":282,"path":283,"stem":284},"Overview","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Foverview","docs\u002F2.fireskills\u002F4.specialists\u002F0.overview",{"title":286,"path":287,"stem":288},"Nuxfire Stack","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fnuxfire-stack","docs\u002F2.fireskills\u002F4.specialists\u002F1.nuxfire-stack",{"title":290,"path":291,"stem":292},"Engineering Specialists","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fengineering-specialists","docs\u002F2.fireskills\u002F4.specialists\u002F2.engineering-specialists",{"title":294,"icon":295,"hide":22,"path":296,"stem":297,"children":298,"page":62},"CLI & Tooling","i-lucide-terminal","\u002Fdocs\u002Ffireskills\u002Fcli","docs\u002F2.fireskills\u002F5.cli",[299,303,307],{"title":300,"path":301,"stem":302},"CLI Overview","\u002Fdocs\u002Ffireskills\u002Fcli\u002Foverview","docs\u002F2.fireskills\u002F5.cli\u002F0.overview",{"title":304,"path":305,"stem":306},"Commands","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fcommands","docs\u002F2.fireskills\u002F5.cli\u002F1.commands",{"title":308,"path":309,"stem":310},"Safety Scripts","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fgovernance-scripts","docs\u002F2.fireskills\u002F5.cli\u002F2.governance-scripts",{"id":312,"title":313,"author":314,"authorType":315,"body":316,"category":1964,"date":1965,"description":1966,"extension":1967,"image":1968,"lang":1969,"meta":1970,"navigation":22,"ogImage":1971,"path":1972,"readTime":1973,"seo":1974,"stem":1975,"tags":1976,"translations":1982,"updated":315,"__hash__":1986},"blog\u002Fblog\u002Fgit-branching-stage-production-first-release.md","Git for Your First Release: stage and production Branches, from Empty Repository to Live","Nuxfire Team",null,{"type":317,"value":318,"toc":1944},"minimark",[319,333,336,341,351,354,405,418,422,456,460,539,551,556,562,566,588,594,600,676,698,720,726,730,736,742,760,787,794,814,820,839,843,849,855,861,899,905,922,926,932,941,954,968,987,997,1015,1034,1037,1056,1065,1069,1075,1079,1089,1093,1099,1142,1148,1176,1198,1202,1208,1248,1258,1268,1288,1313,1317,1323,1327,1333,1355,1366,1382,1388,1434,1440,1473,1476,1522,1531,1535,1541,1545,1554,1580,1589,1631,1638,1642,1648,1652,1658,1705,1714,1718,1724,1728,1847,1851,1930,1940],[320,321,322,323,327,328,332],"p",{},"You extracted the Nuxfire source and you are about to deploy your first product. Before you run a single ",[324,325,326],"code",{},"sst"," command, spend twenty minutes on the thing that decides whether the next hundred deploys are boring or stressful: ",[329,330,331],"strong",{},"how your Git branches map to what is live",".",[320,334,335],{},"This manual builds a small, strict model. Every Git command in it was run end to end in a scratch repository before publishing; the GitHub CLI flags come from its official manual. Each step has the manual commands and a short prompt you can paste into an AI agent in your IDE (Cursor, Claude Code, Copilot and similar).",[337,338,340],"h2",{"id":339},"the-model-in-one-minute","The model in one minute",[342,343,349],"pre",{"className":344,"code":346,"language":347,"meta":348},[345],"language-text","feature\u002Fx ──▶ stage ──(validated)──▶ production\n              default branch          moves ONLY by fast-forward\n              you work here           = what you approved for live\n","text","",[324,350,346],{"__ignoreMap":348},[320,352,353],{},"Two long-lived branches, five rules:",[355,356,357,367,378,386,395],"ol",{},[358,359,360,366],"li",{},[329,361,362,363,332],{},"All work happens on ",[324,364,365],{},"stage"," It is the default branch, so pull requests and clones land there.",[358,368,369,377],{},[329,370,371,374,375,332],{},[324,372,373],{},"production"," only moves by fast-forward from ",[324,376,365],{}," No merge commits, no direct commits.",[358,379,380,385],{},[329,381,382,383,332],{},"Never force-push ",[324,384,373],{}," If a push is rejected, that is the safety net working.",[358,387,388,394],{},[329,389,390,391,393],{},"Deploy production from the ",[324,392,373],{}," branch."," A deploy ships whatever is checked out on your machine, so the branch you are on is the truth.",[358,396,397,400,401,404],{},[329,398,399],{},"Tag every release that went live"," (",[324,402,403],{},"v1.0.0","). The branch says \"approved\", the tag says \"confirmed live\".",[320,406,407,408,411,412,414,415,417],{},"Why not keep ",[324,409,410],{},"main"," too? A third long-lived branch is a third answer to \"what is the latest code?\". Nuxfire already names its deployment stages ",[324,413,365],{}," and ",[324,416,373],{},", so the branch names mirror them and there is nothing to translate in your head.",[337,419,421],{"id":420},"what-you-need","What you need",[423,424,425,439,446],"ul",{},[358,426,427,428,431,432,435,436,332],{},"Git ",[329,429,430],{},"2.28 or newer"," (for ",[324,433,434],{},"git init -b","). Check with ",[324,437,438],{},"git --version",[358,440,441,442,445],{},"A GitHub account (personal or organization). The GitHub CLI (",[324,443,444],{},"gh",") is optional; every step also shows the web-UI path.",[358,447,448,449,452,453,332],{},"The Nuxfire folder extracted and ",[324,450,451],{},"bun install"," done, as in ",[454,455,31],"a",{"href":32},[337,457,459],{"id":458},"step-1-tell-git-who-you-are","Step 1: tell Git who you are",[342,461,465],{"className":462,"code":463,"language":464,"meta":348,"style":348},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark monokai","git --version\ngit config --global user.name \"Your Name\"\ngit config --global user.email \"you@example.com\"\ngit config --global init.defaultBranch stage\n","bash",[324,466,467,480,505,524],{"__ignoreMap":348},[468,469,472,476],"span",{"class":470,"line":471},"line",1,[468,473,475],{"class":474},"sR7ES","git",[468,477,479],{"class":478},"sFhLe"," --version\n",[468,481,483,485,489,492,495,499,502],{"class":470,"line":482},2,[468,484,475],{"class":474},[468,486,488],{"class":487},"sLACW"," config",[468,490,491],{"class":478}," --global",[468,493,494],{"class":487}," user.name",[468,496,498],{"class":497},"siCPE"," \"",[468,500,501],{"class":487},"Your Name",[468,503,504],{"class":497},"\"\n",[468,506,508,510,512,514,517,519,522],{"class":470,"line":507},3,[468,509,475],{"class":474},[468,511,488],{"class":487},[468,513,491],{"class":478},[468,515,516],{"class":487}," user.email",[468,518,498],{"class":497},[468,520,521],{"class":487},"you@example.com",[468,523,504],{"class":497},[468,525,527,529,531,533,536],{"class":470,"line":526},4,[468,528,475],{"class":474},[468,530,488],{"class":487},[468,532,491],{"class":478},[468,534,535],{"class":487}," init.defaultBranch",[468,537,538],{"class":487}," stage\n",[320,540,541,542,544,545,548,549,332],{},"The last line makes every new repository you create start on ",[324,543,365],{}," instead of ",[324,546,547],{},"master"," or ",[324,550,410],{},[320,552,553],{},[329,554,555],{},"Prompt for AI agents:",[342,557,560],{"className":558,"code":559,"language":347,"meta":348},[345],"Check `git --version` (2.28 or newer is required). Show my global git\nuser.name and user.email. If either is empty, ask me for the values\nbefore setting them. Do not change anything else.\n",[324,561,559],{"__ignoreMap":348},[337,563,565],{"id":564},"step-2-protect-your-secrets-then-make-the-first-commit","Step 2: protect your secrets, then make the first commit",[320,567,568,569,572,573,414,576,579,580,583,584,587],{},"Your folder already contains files that must ",[329,570,571],{},"never"," reach Git: ",[324,574,575],{},".env.production",[324,577,578],{},".env.stage"," hold real credentials (the deploy preflight even checks that the database values are filled in), and ",[324,581,582],{},".sst"," is local deploy state. Nuxfire's ",[324,585,586],{},".gitignore"," covers them:",[342,589,592],{"className":590,"code":591,"language":347,"meta":348},[345],".env\n.env.*\n!.env.example\n.sst\n",[324,593,591],{"__ignoreMap":348},[320,595,596,597,599],{},"Create the repository on ",[324,598,365],{},", prove the rules work, and only then stage everything:",[342,601,603],{"className":462,"code":602,"language":464,"meta":348,"style":348},"git init -b stage\ngit check-ignore -v .env.production .env.stage .sst\ngit add -A\ngit diff --cached --name-only | grep -E \"(^|\u002F)\\.env\"\n",[324,604,605,617,636,646],{"__ignoreMap":348},[468,606,607,609,612,615],{"class":470,"line":471},[468,608,475],{"class":474},[468,610,611],{"class":487}," init",[468,613,614],{"class":478}," -b",[468,616,538],{"class":487},[468,618,619,621,624,627,630,633],{"class":470,"line":482},[468,620,475],{"class":474},[468,622,623],{"class":487}," check-ignore",[468,625,626],{"class":478}," -v",[468,628,629],{"class":487}," .env.production",[468,631,632],{"class":487}," .env.stage",[468,634,635],{"class":487}," .sst\n",[468,637,638,640,643],{"class":470,"line":507},[468,639,475],{"class":474},[468,641,642],{"class":487}," add",[468,644,645],{"class":478}," -A\n",[468,647,648,650,653,656,659,663,666,669,671,674],{"class":470,"line":526},[468,649,475],{"class":474},[468,651,652],{"class":487}," diff",[468,654,655],{"class":478}," --cached",[468,657,658],{"class":478}," --name-only",[468,660,662],{"class":661},"sGXK2"," |",[468,664,665],{"class":474}," grep",[468,667,668],{"class":478}," -E",[468,670,498],{"class":497},[468,672,673],{"class":487},"(^|\u002F)\\.env",[468,675,504],{"class":497},[320,677,678,679,682,683,686,687,690,691,694,695,697],{},"The ",[324,680,681],{},"check-ignore"," command must print the rule that matches each file. The last command must print ",[329,684,685],{},"only"," ",[324,688,689],{},".env.example",". If any other ",[324,692,693],{},".env*"," file shows up, stop and fix ",[324,696,586],{}," before committing.",[342,699,701],{"className":462,"code":700,"language":464,"meta":348,"style":348},"git commit -m \"chore: initial commit from Nuxfire\"\n",[324,702,703],{"__ignoreMap":348},[468,704,705,707,710,713,715,718],{"class":470,"line":471},[468,706,475],{"class":474},[468,708,709],{"class":487}," commit",[468,711,712],{"class":478}," -m",[468,714,498],{"class":497},[468,716,717],{"class":487},"chore: initial commit from Nuxfire",[468,719,504],{"class":497},[721,722,723],"blockquote",{},[320,724,725],{},"If a secret ever gets committed, deleting the file is not enough: it stays in history. Treat the credential as compromised, rotate it first, then clean the history.",[320,727,728],{},[329,729,555],{},[342,731,734],{"className":732,"code":733,"language":347,"meta":348},[345],"In the project root, run `git init -b stage` only if there is no .git\nfolder. With `git check-ignore -v`, verify that .env.production,\n.env.stage and .sst are ignored and that .env.example is not. Run\n`git add -A` and print `git diff --cached --name-only`. STOP and warn me\nif any .env* file other than .env.example is listed. If it is clean,\ncommit with the message \"chore: initial commit from Nuxfire\".\n",[324,735,733],{"__ignoreMap":348},[337,737,739,740],{"id":738},"step-3-create-the-github-repository-and-push-stage","Step 3: create the GitHub repository and push ",[324,741,365],{},[320,743,744,745,748,749,751,752,755,756,759],{},"Create a ",[329,746,747],{},"private, empty"," repository: no README, no ",[324,750,586],{},", no license. In the browser, use ",[329,753,754],{},"New repository",", choose ",[329,757,758],{},"Private"," and leave the initialization options unchecked. Or with the CLI, from the project folder:",[342,761,763],{"className":462,"code":762,"language":464,"meta":348,"style":348},"gh repo create my-product --private --source=. --remote=origin\n",[324,764,765],{"__ignoreMap":348},[468,766,767,769,772,775,778,781,784],{"class":470,"line":471},[468,768,444],{"class":474},[468,770,771],{"class":487}," repo",[468,773,774],{"class":487}," create",[468,776,777],{"class":487}," my-product",[468,779,780],{"class":478}," --private",[468,782,783],{"class":478}," --source=.",[468,785,786],{"class":478}," --remote=origin\n",[320,788,789,790,793],{},"The CLI adds the ",[324,791,792],{},"origin"," remote for you. Without it, add the remote yourself, using the URL GitHub shows you:",[342,795,797],{"className":462,"code":796,"language":464,"meta":348,"style":348},"git remote add origin git@github.com:YOUR-USER\u002Fmy-product.git\n",[324,798,799],{"__ignoreMap":348},[468,800,801,803,806,808,811],{"class":470,"line":471},[468,802,475],{"class":474},[468,804,805],{"class":487}," remote",[468,807,642],{"class":487},[468,809,810],{"class":487}," origin",[468,812,813],{"class":487}," git@github.com:YOUR-USER\u002Fmy-product.git\n",[320,815,816,817,819],{},"In both cases, publish ",[324,818,365],{}," and set it to track the remote:",[342,821,823],{"className":462,"code":822,"language":464,"meta":348,"style":348},"git push -u origin stage\n",[324,824,825],{"__ignoreMap":348},[468,826,827,829,832,835,837],{"class":470,"line":471},[468,828,475],{"class":474},[468,830,831],{"class":487}," push",[468,833,834],{"class":478}," -u",[468,836,810],{"class":487},[468,838,538],{"class":487},[320,840,841],{},[329,842,555],{},[342,844,847],{"className":845,"code":846,"language":347,"meta":348},[345],"Create a PRIVATE, empty GitHub repository named \u003Cname> under \u003Cowner>\n(no README, no .gitignore, no license), add it as `origin`, and push the\n`stage` branch with upstream tracking. Use `gh` if it is installed;\notherwise print the exact commands for me to run. Never use --force.\n",[324,848,846],{"__ignoreMap":348},[337,850,852,853],{"id":851},"step-4-create-production","Step 4: create ",[324,854,373],{},[320,856,857,858,860],{},"Branch it from ",[324,859,365],{}," at the same commit, publish it, and go back:",[342,862,864],{"className":462,"code":863,"language":464,"meta":348,"style":348},"git switch -c production\ngit push -u origin production\ngit switch stage\n",[324,865,866,879,891],{"__ignoreMap":348},[468,867,868,870,873,876],{"class":470,"line":471},[468,869,475],{"class":474},[468,871,872],{"class":487}," switch",[468,874,875],{"class":478}," -c",[468,877,878],{"class":487}," production\n",[468,880,881,883,885,887,889],{"class":470,"line":482},[468,882,475],{"class":474},[468,884,831],{"class":487},[468,886,834],{"class":478},[468,888,810],{"class":487},[468,890,878],{"class":487},[468,892,893,895,897],{"class":470,"line":507},[468,894,475],{"class":474},[468,896,872],{"class":487},[468,898,538],{"class":487},[320,900,901,902,904],{},"Now add a local guard so that ",[324,903,373],{}," can only ever fast-forward. Git will refuse any merge that is not a fast-forward:",[342,906,908],{"className":462,"code":907,"language":464,"meta":348,"style":348},"git config branch.production.mergeOptions --ff-only\n",[324,909,910],{"__ignoreMap":348},[468,911,912,914,916,919],{"class":470,"line":471},[468,913,475],{"class":474},[468,915,488],{"class":487},[468,917,918],{"class":487}," branch.production.mergeOptions",[468,920,921],{"class":478}," --ff-only\n",[320,923,924],{},[329,925,555],{},[342,927,930],{"className":928,"code":929,"language":347,"meta":348},[345],"Create branch `production` from `stage`, push it with upstream tracking,\nswitch back to `stage`, then run\n`git config branch.production.mergeOptions --ff-only`.\nConfirm the result with `git branch -vv`.\n",[324,931,929],{"__ignoreMap":348},[337,933,935,936,938,939],{"id":934},"step-5-make-stage-the-default-branch-and-remove-main","Step 5: make ",[324,937,365],{}," the default branch and remove ",[324,940,410],{},[320,942,943,944,946,947,950,951,953],{},"GitHub decides the default branch, not your local Git. Even in an empty repository the default may stay ",[324,945,410],{},", so check it explicitly. GitHub requires ",[329,948,949],{},"more than one branch"," to change the default, which is why ",[324,952,373],{}," had to exist first.",[320,955,956,957,960,961,963,964,967],{},"In the browser: ",[329,958,959],{},"Settings → Branches → Default branch",", click the switch icon, pick ",[324,962,365],{},", ",[329,965,966],{},"Update",", and confirm. With the CLI:",[342,969,971],{"className":462,"code":970,"language":464,"meta":348,"style":348},"gh repo edit --default-branch stage\n",[324,972,973],{"__ignoreMap":348},[468,974,975,977,979,982,985],{"class":470,"line":471},[468,976,444],{"class":474},[468,978,771],{"class":487},[468,980,981],{"class":487}," edit",[468,983,984],{"class":478}," --default-branch",[468,986,538],{"class":487},[320,988,989,990,992,993,996],{},"Then look at what exists on the remote and, if ",[324,991,410],{}," is there (for example because the repository was created with a README), delete it. Do it ",[329,994,995],{},"after"," switching the default, never before:",[342,998,1000],{"className":462,"code":999,"language":464,"meta":348,"style":348},"git ls-remote --heads origin\n",[324,1001,1002],{"__ignoreMap":348},[468,1003,1004,1006,1009,1012],{"class":470,"line":471},[468,1005,475],{"class":474},[468,1007,1008],{"class":487}," ls-remote",[468,1010,1011],{"class":478}," --heads",[468,1013,1014],{"class":487}," origin\n",[342,1016,1018],{"className":462,"code":1017,"language":464,"meta":348,"style":348},"git push origin --delete main\n",[324,1019,1020],{"__ignoreMap":348},[468,1021,1022,1024,1026,1028,1031],{"class":470,"line":471},[468,1023,475],{"class":474},[468,1025,831],{"class":487},[468,1027,810],{"class":487},[468,1029,1030],{"class":478}," --delete",[468,1032,1033],{"class":487}," main\n",[320,1035,1036],{},"Finally refresh your local pointer to the remote default:",[342,1038,1040],{"className":462,"code":1039,"language":464,"meta":348,"style":348},"git remote set-head origin --auto\n",[324,1041,1042],{"__ignoreMap":348},[468,1043,1044,1046,1048,1051,1053],{"class":470,"line":471},[468,1045,475],{"class":474},[468,1047,805],{"class":487},[468,1049,1050],{"class":487}," set-head",[468,1052,810],{"class":487},[468,1054,1055],{"class":478}," --auto\n",[320,1057,1058,1059,1061,1062,1064],{},"If ",[324,1060,410],{}," was created with a README it has an unrelated history. Do not merge it into ",[324,1063,365],{},"; just delete it.",[320,1066,1067],{},[329,1068,555],{},[342,1070,1073],{"className":1071,"code":1072,"language":347,"meta":348},[345],"Check which branch is the GitHub default with\n`gh repo view --json defaultBranchRef`. If it is not `stage`, run\n`gh repo edit --default-branch stage`. Then run\n`git ls-remote --heads origin`. If `main` exists, tell me and WAIT for my\nconfirmation before running `git push origin --delete main`. Finish with\n`git remote set-head origin --auto`.\n",[324,1074,1072],{"__ignoreMap":348},[337,1076,1078],{"id":1077},"step-6-guard-rails-on-github-if-your-plan-has-them","Step 6: guard rails on GitHub (if your plan has them)",[320,1080,1081,1082,1085,1086,1088],{},"The local ",[324,1083,1084],{},"--ff-only"," guard costs nothing and needs no plan. On GitHub, branch protection and rulesets depend on your plan and on the repository visibility (rulesets are documented for GitHub Team and GitHub Enterprise). If yours offers them, protect ",[324,1087,373],{}," with: block force pushes and restrict deletions. If not, the process and the local guard are enough as long as you never force-push.",[337,1090,1092],{"id":1091},"step-7-the-day-to-day-loop","Step 7: the day-to-day loop",[320,1094,1095,1096,1098],{},"Working alone, commit to ",[324,1097,365],{}," and push:",[342,1100,1102],{"className":462,"code":1101,"language":464,"meta":348,"style":348},"git switch stage\ngit add -A\ngit commit -m \"feat: describe the change\"\ngit push\n",[324,1103,1104,1112,1120,1135],{"__ignoreMap":348},[468,1105,1106,1108,1110],{"class":470,"line":471},[468,1107,475],{"class":474},[468,1109,872],{"class":487},[468,1111,538],{"class":487},[468,1113,1114,1116,1118],{"class":470,"line":482},[468,1115,475],{"class":474},[468,1117,642],{"class":487},[468,1119,645],{"class":478},[468,1121,1122,1124,1126,1128,1130,1133],{"class":470,"line":507},[468,1123,475],{"class":474},[468,1125,709],{"class":487},[468,1127,712],{"class":478},[468,1129,498],{"class":497},[468,1131,1132],{"class":487},"feat: describe the change",[468,1134,504],{"class":497},[468,1136,1137,1139],{"class":470,"line":526},[468,1138,475],{"class":474},[468,1140,1141],{"class":487}," push\n",[320,1143,1144,1145,1147],{},"Working with others, use short-lived branches and pull requests into ",[324,1146,365],{},":",[342,1149,1151],{"className":462,"code":1150,"language":464,"meta":348,"style":348},"git switch -c feat\u002Fbilling-copy\ngit push -u origin feat\u002Fbilling-copy\n",[324,1152,1153,1164],{"__ignoreMap":348},[468,1154,1155,1157,1159,1161],{"class":470,"line":471},[468,1156,475],{"class":474},[468,1158,872],{"class":487},[468,1160,875],{"class":478},[468,1162,1163],{"class":487}," feat\u002Fbilling-copy\n",[468,1165,1166,1168,1170,1172,1174],{"class":470,"line":482},[468,1167,475],{"class":474},[468,1169,831],{"class":487},[468,1171,834],{"class":478},[468,1173,810],{"class":487},[468,1175,1163],{"class":487},[320,1177,1178,1179,400,1185,963,1188,963,1191,963,1194,1197],{},"Use ",[454,1180,1184],{"href":1181,"rel":1182},"https:\u002F\u002Fwww.conventionalcommits.org\u002F",[1183],"nofollow","Conventional Commits",[324,1186,1187],{},"feat:",[324,1189,1190],{},"fix:",[324,1192,1193],{},"docs:",[324,1195,1196],{},"chore:","). Nuxfire's own history follows them, which keeps release notes almost free.",[337,1199,1201],{"id":1200},"step-8-the-gate-before-your-first-release","Step 8: the gate before your first release",[320,1203,1204,1205,1207],{},"Nothing reaches ",[324,1206,373],{}," until it passes the same checks every time:",[342,1209,1211],{"className":462,"code":1210,"language":464,"meta":348,"style":348},"bun install\nbun run test\nbun run doctor -- --stage production\n",[324,1212,1213,1221,1231],{"__ignoreMap":348},[468,1214,1215,1218],{"class":470,"line":471},[468,1216,1217],{"class":474},"bun",[468,1219,1220],{"class":487}," install\n",[468,1222,1223,1225,1228],{"class":470,"line":482},[468,1224,1217],{"class":474},[468,1226,1227],{"class":487}," run",[468,1229,1230],{"class":487}," test\n",[468,1232,1233,1235,1237,1240,1243,1246],{"class":470,"line":507},[468,1234,1217],{"class":474},[468,1236,1227],{"class":487},[468,1238,1239],{"class":487}," doctor",[468,1241,1242],{"class":478}," --",[468,1244,1245],{"class":478}," --stage",[468,1247,878],{"class":487},[320,1249,1250,1253,1254,1257],{},[324,1251,1252],{},"doctor"," is the deploy preflight: it validates your Cloudflare token, your ",[324,1255,1256],{},"BRAND_*"," values, your database secrets and the domain zone, and tells you the exact fix for each problem before you spend minutes on a failing deploy.",[320,1259,1260,1261,1264,1265,1147],{},"For a first product, deploy a ",[329,1262,1263],{},"validation stage"," before production. A non-production stage gets its own Workers, database connection and secrets, and answers on ",[324,1266,1267],{},"\u003Cstage>.dev.\u003Cyour-domain>",[342,1269,1271],{"className":462,"code":1270,"language":464,"meta":348,"style":348},"bun run deploy -- --stage stage\n",[324,1272,1273],{"__ignoreMap":348},[468,1274,1275,1277,1279,1282,1284,1286],{"class":470,"line":471},[468,1276,1217],{"class":474},[468,1278,1227],{"class":487},[468,1280,1281],{"class":487}," deploy",[468,1283,1242],{"class":478},[468,1285,1245],{"class":478},[468,1287,538],{"class":487},[320,1289,678,1290,1293,1294,963,1296,414,1298,1300,1301,1304,1305,1308,1309,1312],{},[324,1291,1292],{},"--"," is required for the flag to reach the script. Secrets and the Cloudflare token are covered in ",[454,1295,35],{"href":36},[454,1297,43],{"href":44},[454,1299,51],{"href":52},". One production-only prerequisite is worth knowing now: the apex domain and ",[324,1302,1303],{},"www"," must have ",[329,1306,1307],{},"no"," A, AAAA or CNAME record in your DNS, otherwise Cloudflare rejects the custom domain (error ",[324,1310,1311],{},"100117",").",[320,1314,1315],{},[329,1316,555],{},[342,1318,1321],{"className":1319,"code":1320,"language":347,"meta":348},[345],"Run `bun install`, `bun run test` and\n`bun run doctor -- --stage production`. Report every failure with its\nexact message and the fix. Do NOT deploy anything.\n",[324,1322,1320],{"__ignoreMap":348},[337,1324,1326],{"id":1325},"step-9-the-first-release","Step 9: the first release",[320,1328,1329,1330,1332],{},"Everything is green on ",[324,1331,365],{},". Promote it:",[342,1334,1336],{"className":462,"code":1335,"language":464,"meta":348,"style":348},"git status\ngit push origin stage\n",[324,1337,1338,1345],{"__ignoreMap":348},[468,1339,1340,1342],{"class":470,"line":471},[468,1341,475],{"class":474},[468,1343,1344],{"class":487}," status\n",[468,1346,1347,1349,1351,1353],{"class":470,"line":482},[468,1348,475],{"class":474},[468,1350,831],{"class":487},[468,1352,810],{"class":487},[468,1354,538],{"class":487},[320,1356,1357,1360,1361,1363,1364,1147],{},[324,1358,1359],{},"git status"," must say the working tree is clean. Now fast-forward ",[324,1362,373],{}," to the exact same commit, without leaving ",[324,1365,365],{},[342,1367,1369],{"className":462,"code":1368,"language":464,"meta":348,"style":348},"git push origin stage:production\n",[324,1370,1371],{"__ignoreMap":348},[468,1372,1373,1375,1377,1379],{"class":470,"line":471},[468,1374,475],{"class":474},[468,1376,831],{"class":487},[468,1378,810],{"class":487},[468,1380,1381],{"class":487}," stage:production\n",[320,1383,1384,1385,1387],{},"That push only succeeds if it is a pure fast-forward. Verify both branches are identical, then switch to ",[324,1386,373],{},", because that is the branch you deploy from:",[342,1389,1391],{"className":462,"code":1390,"language":464,"meta":348,"style":348},"git fetch origin\ngit diff --stat stage origin\u002Fproduction\ngit switch production\ngit pull --ff-only\n",[324,1392,1393,1402,1417,1425],{"__ignoreMap":348},[468,1394,1395,1397,1400],{"class":470,"line":471},[468,1396,475],{"class":474},[468,1398,1399],{"class":487}," fetch",[468,1401,1014],{"class":487},[468,1403,1404,1406,1408,1411,1414],{"class":470,"line":482},[468,1405,475],{"class":474},[468,1407,652],{"class":487},[468,1409,1410],{"class":478}," --stat",[468,1412,1413],{"class":487}," stage",[468,1415,1416],{"class":487}," origin\u002Fproduction\n",[468,1418,1419,1421,1423],{"class":470,"line":507},[468,1420,475],{"class":474},[468,1422,872],{"class":487},[468,1424,878],{"class":487},[468,1426,1427,1429,1432],{"class":470,"line":526},[468,1428,475],{"class":474},[468,1430,1431],{"class":487}," pull",[468,1433,921],{"class":478},[320,1435,678,1436,1439],{},[324,1437,1438],{},"diff"," must print nothing. Run the preflight once more and deploy:",[342,1441,1443],{"className":462,"code":1442,"language":464,"meta":348,"style":348},"bun run doctor -- --stage production\nbun run deploy -- --stage production\n",[324,1444,1445,1459],{"__ignoreMap":348},[468,1446,1447,1449,1451,1453,1455,1457],{"class":470,"line":471},[468,1448,1217],{"class":474},[468,1450,1227],{"class":487},[468,1452,1239],{"class":487},[468,1454,1242],{"class":478},[468,1456,1245],{"class":478},[468,1458,878],{"class":487},[468,1460,1461,1463,1465,1467,1469,1471],{"class":470,"line":482},[468,1462,1217],{"class":474},[468,1464,1227],{"class":487},[468,1466,1281],{"class":487},[468,1468,1242],{"class":478},[468,1470,1245],{"class":478},[468,1472,878],{"class":487},[320,1474,1475],{},"Only after the deploy succeeds, tag the release and go back to work:",[342,1477,1479],{"className":462,"code":1478,"language":464,"meta":348,"style":348},"git tag -a v1.0.0 -m \"First production release\"\ngit push origin v1.0.0\ngit switch stage\n",[324,1480,1481,1503,1514],{"__ignoreMap":348},[468,1482,1483,1485,1488,1491,1494,1496,1498,1501],{"class":470,"line":471},[468,1484,475],{"class":474},[468,1486,1487],{"class":487}," tag",[468,1489,1490],{"class":478}," -a",[468,1492,1493],{"class":487}," v1.0.0",[468,1495,712],{"class":478},[468,1497,498],{"class":497},[468,1499,1500],{"class":487},"First production release",[468,1502,504],{"class":497},[468,1504,1505,1507,1509,1511],{"class":470,"line":482},[468,1506,475],{"class":474},[468,1508,831],{"class":487},[468,1510,810],{"class":487},[468,1512,1513],{"class":487}," v1.0.0\n",[468,1515,1516,1518,1520],{"class":470,"line":507},[468,1517,475],{"class":474},[468,1519,872],{"class":487},[468,1521,538],{"class":487},[320,1523,1524,1525,1527,1528,1530],{},"If the deploy fails, do not edit ",[324,1526,373],{},". Fix forward on ",[324,1529,365],{},", run the gate again and repeat the fast-forward. The branch can be briefly ahead of what is live, and the missing tag tells you exactly that.",[320,1532,1533],{},[329,1534,555],{},[342,1536,1539],{"className":1537,"code":1538,"language":347,"meta":348},[345],"Release checklist for the first release. Stop at the first failure:\n1. `git status` must be clean and on `stage`.\n2. `git push origin stage`.\n3. `git push origin stage:production`. If it is rejected, STOP and show\n   me `git log --oneline stage..production`. Never force.\n4. `git switch production && git pull --ff-only`.\n5. `bun run doctor -- --stage production`.\n6. Ask me for explicit confirmation, then run\n   `bun run deploy -- --stage production`.\n7. Only after a successful deploy: `git tag -a v1.0.0 -m \"First\n   production release\"` and `git push origin v1.0.0`.\n8. `git switch stage`.\n",[324,1540,1538],{"__ignoreMap":348},[337,1542,1544],{"id":1543},"step-10-keep-the-two-branches-from-drifting","Step 10: keep the two branches from drifting",[320,1546,1547,1548,1550,1551,1553],{},"The failure mode that bites everyone once: a fix lands on ",[324,1549,373],{}," (or gets deployed from ",[324,1552,365],{},") and the branches quietly stop describing the same code. The check is one line and it should always print nothing:",[342,1555,1557],{"className":462,"code":1556,"language":464,"meta":348,"style":348},"git fetch origin\ngit log --oneline stage..origin\u002Fproduction\n",[324,1558,1559,1567],{"__ignoreMap":348},[468,1560,1561,1563,1565],{"class":470,"line":471},[468,1562,475],{"class":474},[468,1564,1399],{"class":487},[468,1566,1014],{"class":487},[468,1568,1569,1571,1574,1577],{"class":470,"line":482},[468,1570,475],{"class":474},[468,1572,1573],{"class":487}," log",[468,1575,1576],{"class":478}," --oneline",[468,1578,1579],{"class":487}," stage..origin\u002Fproduction\n",[320,1581,1582,1583,1585,1586,1588],{},"If it prints commits, ",[324,1584,373],{}," has work ",[324,1587,365],{}," does not. A promotion will be rejected, and that is correct. Bring the work back, publish, and fast-forward again:",[342,1590,1592],{"className":462,"code":1591,"language":464,"meta":348,"style":348},"git switch stage\ngit merge origin\u002Fproduction\ngit push origin stage\ngit push origin stage:production\n",[324,1593,1594,1602,1611,1621],{"__ignoreMap":348},[468,1595,1596,1598,1600],{"class":470,"line":471},[468,1597,475],{"class":474},[468,1599,872],{"class":487},[468,1601,538],{"class":487},[468,1603,1604,1606,1609],{"class":470,"line":482},[468,1605,475],{"class":474},[468,1607,1608],{"class":487}," merge",[468,1610,1416],{"class":487},[468,1612,1613,1615,1617,1619],{"class":470,"line":507},[468,1614,475],{"class":474},[468,1616,831],{"class":487},[468,1618,810],{"class":487},[468,1620,538],{"class":487},[468,1622,1623,1625,1627,1629],{"class":470,"line":526},[468,1624,475],{"class":474},[468,1626,831],{"class":487},[468,1628,810],{"class":487},[468,1630,1381],{"class":487},[320,1632,1633,1634,1637],{},"If the merge reports conflicts, resolve them, run the gate again and commit before pushing. Never resolve this with ",[324,1635,1636],{},"--force",": it would erase exactly the commits you are trying to keep.",[320,1639,1640],{},[329,1641,555],{},[342,1643,1646],{"className":1644,"code":1645,"language":347,"meta":348},[345],"Run `git fetch origin`, then `git log --oneline stage..origin\u002Fproduction`.\nIf it prints anything: merge origin\u002Fproduction into stage, resolve any\nconflicts together with me, run `bun run test`, push stage, then\nfast-forward production with `git push origin stage:production`.\nNever use --force.\n",[324,1647,1645],{"__ignoreMap":348},[337,1649,1651],{"id":1650},"rolling-back","Rolling back",[320,1653,1654,1655,1657],{},"Do not rewrite ",[324,1656,373],{},". Redeploy the code of an earlier tag instead:",[342,1659,1661],{"className":462,"code":1660,"language":464,"meta":348,"style":348},"git tag --sort=-creatordate\ngit switch --detach v1.0.0\nbun run deploy -- --stage production\ngit switch stage\n",[324,1662,1663,1672,1683,1697],{"__ignoreMap":348},[468,1664,1665,1667,1669],{"class":470,"line":471},[468,1666,475],{"class":474},[468,1668,1487],{"class":487},[468,1670,1671],{"class":478}," --sort=-creatordate\n",[468,1673,1674,1676,1678,1681],{"class":470,"line":482},[468,1675,475],{"class":474},[468,1677,872],{"class":487},[468,1679,1680],{"class":478}," --detach",[468,1682,1513],{"class":487},[468,1684,1685,1687,1689,1691,1693,1695],{"class":470,"line":507},[468,1686,1217],{"class":474},[468,1688,1227],{"class":487},[468,1690,1281],{"class":487},[468,1692,1242],{"class":478},[468,1694,1245],{"class":478},[468,1696,878],{"class":487},[468,1698,1699,1701,1703],{"class":470,"line":526},[468,1700,475],{"class":474},[468,1702,872],{"class":487},[468,1704,538],{"class":487},[320,1706,1707,1708,1710,1711,1713],{},"This restores the ",[329,1709,324],{},". Database migrations are applied by every deploy and are not rolled back, so plan schema changes as additive first (add a column, ship code that uses it, remove the old one later). Then fix forward on ",[324,1712,365],{}," and promote a new release.",[320,1715,1716],{},[329,1717,555],{},[342,1719,1722],{"className":1720,"code":1721,"language":347,"meta":348},[345],"Do NOT touch the `production` branch. Show me\n`git tag --sort=-creatordate | head`, ask which tag to restore, run\n`git switch --detach \u003Ctag>`, and ask for my explicit confirmation before\n`bun run deploy -- --stage production`. Afterwards run `git switch stage`.\n",[324,1723,1721],{"__ignoreMap":348},[337,1725,1727],{"id":1726},"when-something-goes-wrong","When something goes wrong",[1729,1730,1731,1747],"table",{},[1732,1733,1734],"thead",{},[1735,1736,1737,1741,1744],"tr",{},[1738,1739,1740],"th",{},"What you see",[1738,1742,1743],{},"What it means",[1738,1745,1746],{},"What to do",[1748,1749,1750,1769,1784,1800,1819,1833],"tbody",{},[1735,1751,1752,1758,1766],{},[1753,1754,1755],"td",{},[324,1756,1757],{},"[rejected] stage -> production (non-fast-forward)",[1753,1759,1760,1762,1763,1765],{},[324,1761,373],{}," has commits ",[324,1764,365],{}," lacks",[1753,1767,1768],{},"Step 10. Never force.",[1735,1770,1771,1776,1781],{},[1753,1772,1773],{},[324,1774,1775],{},"fatal: Not possible to fast-forward, aborting.",[1753,1777,1778,1779],{},"The local guard stopped a merge on ",[324,1780,373],{},[1753,1782,1783],{},"Same cause and fix as above",[1735,1785,1786,1791,1794],{},[1753,1787,1788,1789],{},"GitHub will not let you delete ",[324,1790,410],{},[1753,1792,1793],{},"Usually because it is still the default branch",[1753,1795,1796,1797,1799],{},"Switch the default to ",[324,1798,365],{}," first (Step 5)",[1735,1801,1802,1811,1816],{},[1753,1803,1804,1805,1807,1808],{},"A ",[324,1806,693],{}," file shows in ",[324,1809,1810],{},"git diff --cached",[1753,1812,1813,1815],{},[324,1814,586],{}," is missing a rule",[1753,1817,1818],{},"Fix it before the commit, never after",[1735,1820,1821,1824,1827],{},[1753,1822,1823],{},"You deployed from the wrong branch",[1753,1825,1826],{},"The deploy ships the checked-out tree",[1753,1828,1829,1832],{},[324,1830,1831],{},"git branch --show-current"," before every deploy",[1735,1834,1835,1841,1844],{},[1753,1836,1837,1838,1840],{},"Domain error ",[324,1839,1311],{}," on the first production deploy",[1753,1842,1843],{},"The hostname already has a DNS record",[1753,1845,1846],{},"Delete the A, AAAA or CNAME record and deploy again",[337,1848,1850],{"id":1849},"checklist","Checklist",[423,1852,1855,1869,1880,1891,1903,1915,1924],{"className":1853},[1854],"contains-task-list",[358,1856,1859,1863,1864,414,1866,1868],{"className":1857},[1858],"task-list-item",[1860,1861],"input",{"disabled":22,"type":1862},"checkbox"," Repository is private and only ",[324,1865,365],{},[324,1867,373],{}," exist on the remote",[358,1870,1872,686,1874,1876,1877,1879],{"className":1871},[1858],[1860,1873],{"disabled":22,"type":1862},[324,1875,365],{}," is the default branch and ",[324,1878,410],{}," is gone",[358,1881,1883,686,1885,1888,1889],{"className":1882},[1858],[1860,1884],{"disabled":22,"type":1862},[324,1886,1887],{},"git config branch.production.mergeOptions"," prints ",[324,1890,1084],{},[358,1892,1894,1896,1897,1899,1900,1902],{"className":1893},[1858],[1860,1895],{"disabled":22,"type":1862}," No ",[324,1898,693],{}," file except ",[324,1901,689],{}," is tracked",[358,1904,1906,686,1908,414,1911,1914],{"className":1905},[1858],[1860,1907],{"disabled":22,"type":1862},[324,1909,1910],{},"bun run test",[324,1912,1913],{},"bun run doctor -- --stage production"," are green",[358,1916,1918,686,1920,1923],{"className":1917},[1858],[1860,1919],{"disabled":22,"type":1862},[324,1921,1922],{},"git diff --stat stage origin\u002Fproduction"," prints nothing before you deploy",[358,1925,1927,1929],{"className":1926},[1858],[1860,1928],{"disabled":22,"type":1862}," The release is tagged only after the deploy succeeded",[320,1931,1932,1933,1935,1936,414,1938,332],{},"Back to the setup: continue with ",[454,1934,35],{"href":36}," to create the API token, then ",[454,1937,43],{"href":44},[454,1939,51],{"href":52},[1941,1942,1943],"style",{},"html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}",{"title":348,"searchDepth":482,"depth":482,"links":1945},[1946,1947,1948,1949,1950,1952,1954,1956,1957,1958,1959,1960,1961,1962,1963],{"id":339,"depth":482,"text":340},{"id":420,"depth":482,"text":421},{"id":458,"depth":482,"text":459},{"id":564,"depth":482,"text":565},{"id":738,"depth":482,"text":1951},"Step 3: create the GitHub repository and push stage",{"id":851,"depth":482,"text":1953},"Step 4: create production",{"id":934,"depth":482,"text":1955},"Step 5: make stage the default branch and remove main",{"id":1077,"depth":482,"text":1078},{"id":1091,"depth":482,"text":1092},{"id":1200,"depth":482,"text":1201},{"id":1325,"depth":482,"text":1326},{"id":1543,"depth":482,"text":1544},{"id":1650,"depth":482,"text":1651},{"id":1726,"depth":482,"text":1727},{"id":1849,"depth":482,"text":1850},"DevOps","2026-09-25","A senior-level manual for new Nuxfire owners: create the repository, make stage the default branch, remove main, promote to production by fast-forward and ship your first release safely.","md","\u002Fimages\u002Fblog\u002Fgit-branching-stage-production.svg","en",{},"\u002Fimages\u002Fblog\u002Fgit-branching-stage-production.png","\u002Fblog\u002Fgit-branching-stage-production-first-release","14 min",{"title":313,"description":1966},"blog\u002Fgit-branching-stage-production-first-release",[1977,1978,1979,1980,51,1981],"Git","GitHub","Branching","Release","SST",{"en":1983,"pt-br":1984,"es":1985},"git-branching-stage-production-first-release","git-branches-stage-production-primeiro-lancamento","git-ramas-stage-production-primer-lanzamiento","i0oJ4QAxOd1y67ziCUWahffPGYSpl8Opp2GSW_YSuD8",1790707502286]