[{"data":1,"prerenderedAt":1990},["ShallowReactive",2],{"navigation:en":3,"\u002Fblog\u002Fgit-branches-stage-production-primeiro-lancamento":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":1967,"date":1968,"description":1969,"extension":1970,"image":1971,"lang":1972,"meta":1973,"navigation":22,"ogImage":1974,"path":1975,"readTime":1976,"seo":1977,"stem":1978,"tags":1979,"translations":1985,"updated":315,"__hash__":1989},"blog\u002Fblog\u002Fgit-branches-stage-production-primeiro-lancamento.md","Git para o Primeiro Lançamento: Branches stage e production, do Repositório Vazio ao Ar","Equipe Nuxfire",null,{"type":317,"value":318,"toc":1947},"minimark",[319,333,336,341,351,354,405,418,422,457,461,540,552,557,563,567,589,595,601,677,699,721,727,731,737,743,761,788,795,815,821,840,844,850,856,862,900,906,923,927,933,942,955,969,988,998,1016,1035,1038,1057,1066,1070,1076,1080,1090,1094,1100,1143,1149,1177,1199,1203,1209,1249,1259,1269,1289,1314,1318,1324,1328,1334,1356,1367,1383,1389,1435,1441,1474,1477,1523,1532,1536,1542,1546,1555,1581,1590,1632,1639,1643,1649,1653,1659,1706,1716,1720,1726,1730,1849,1853,1933,1943],[320,321,322,323,327,328,332],"p",{},"Você extraiu o código-fonte do Nuxfire e está prestes a publicar seu primeiro produto. Antes de rodar qualquer comando ",[324,325,326],"code",{},"sst",", dedique vinte minutos ao que decide se os próximos cem deploys serão tranquilos ou estressantes: ",[329,330,331],"strong",{},"como as suas branches do Git se relacionam com o que está no ar",".",[320,334,335],{},"Este manual constrói um modelo pequeno e rigoroso. Todo comando Git aqui foi executado de ponta a ponta em um repositório de teste antes da publicação; as opções do GitHub CLI vêm do manual oficial. Cada etapa traz os comandos manuais e um prompt curto para colar em um agente de IA na sua IDE (Cursor, Claude Code, Copilot e similares).",[337,338,340],"h2",{"id":339},"o-modelo-em-um-minuto","O modelo em um minuto",[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],{},"Duas branches de longa duração e cinco regras:",[355,356,357,367,379,387,395],"ol",{},[358,359,360,366],"li",{},[329,361,362,363,332],{},"Todo o trabalho acontece na ",[324,364,365],{},"stage"," Ela é a branch padrão, então pull requests e clones caem nela.",[358,368,369,378],{},[329,370,371,372,375,376,332],{},"A ",[324,373,374],{},"production"," só avança por fast-forward a partir da ",[324,377,365],{}," Sem commits de merge e sem commits diretos.",[358,380,381,386],{},[329,382,383,384,332],{},"Nunca faça force-push na ",[324,385,374],{}," Se um push for rejeitado, é a rede de segurança funcionando.",[358,388,389,394],{},[329,390,391,392,332],{},"Faça o deploy de produção a partir da branch ",[324,393,374],{}," Um deploy publica o que estiver em checkout na sua máquina, então a branch em que você está é a verdade.",[358,396,397,400,401,404],{},[329,398,399],{},"Marque com uma tag cada release que foi ao ar"," (",[324,402,403],{},"v1.0.0","). A branch diz \"aprovado\", a tag diz \"confirmado no ar\".",[320,406,407,408,411,412,414,415,417],{},"Por que não manter a ",[324,409,410],{},"main"," também? Uma terceira branch de longa duração é uma terceira resposta para \"qual é o código mais recente?\". O Nuxfire já chama seus estágios de deploy de ",[324,413,365],{}," e ",[324,416,374],{},", então as branches espelham esses nomes e não há nada para traduzir na sua cabeça.",[337,419,421],{"id":420},"o-que-você-precisa","O que você precisa",[423,424,425,439,446],"ul",{},[358,426,427,428,431,432,435,436,332],{},"Git ",[329,429,430],{},"2.28 ou mais novo"," (para o ",[324,433,434],{},"git init -b","). Confira com ",[324,437,438],{},"git --version",[358,440,441,442,445],{},"Uma conta no GitHub (pessoal ou organização). O GitHub CLI (",[324,443,444],{},"gh",") é opcional; cada etapa também mostra o caminho pela interface web.",[358,447,448,449,452,453,332],{},"A pasta do Nuxfire extraída e o ",[324,450,451],{},"bun install"," feito, como em ",[454,455,456],"a",{"href":32},"Instalação",[337,458,460],{"id":459},"etapa-1-diga-ao-git-quem-você-é","Etapa 1: diga ao Git quem você é",[342,462,466],{"className":463,"code":464,"language":465,"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,467,468,481,506,525],{"__ignoreMap":348},[469,470,473,477],"span",{"class":471,"line":472},"line",1,[469,474,476],{"class":475},"sR7ES","git",[469,478,480],{"class":479},"sFhLe"," --version\n",[469,482,484,486,490,493,496,500,503],{"class":471,"line":483},2,[469,485,476],{"class":475},[469,487,489],{"class":488},"sLACW"," config",[469,491,492],{"class":479}," --global",[469,494,495],{"class":488}," user.name",[469,497,499],{"class":498},"siCPE"," \"",[469,501,502],{"class":488},"Your Name",[469,504,505],{"class":498},"\"\n",[469,507,509,511,513,515,518,520,523],{"class":471,"line":508},3,[469,510,476],{"class":475},[469,512,489],{"class":488},[469,514,492],{"class":479},[469,516,517],{"class":488}," user.email",[469,519,499],{"class":498},[469,521,522],{"class":488},"you@example.com",[469,524,505],{"class":498},[469,526,528,530,532,534,537],{"class":471,"line":527},4,[469,529,476],{"class":475},[469,531,489],{"class":488},[469,533,492],{"class":479},[469,535,536],{"class":488}," init.defaultBranch",[469,538,539],{"class":488}," stage\n",[320,541,542,543,545,546,549,550,332],{},"A última linha faz todo repositório novo que você criar começar na ",[324,544,365],{},", em vez de ",[324,547,548],{},"master"," ou ",[324,551,410],{},[320,553,554],{},[329,555,556],{},"Prompt para agentes de IA:",[342,558,561],{"className":559,"code":560,"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,562,560],{"__ignoreMap":348},[337,564,566],{"id":565},"etapa-2-proteja-seus-segredos-e-faça-o-primeiro-commit","Etapa 2: proteja seus segredos e faça o primeiro commit",[320,568,569,570,573,574,414,577,580,581,584,585,588],{},"Sua pasta já contém arquivos que ",[329,571,572],{},"nunca"," podem chegar ao Git: ",[324,575,576],{},".env.production",[324,578,579],{},".env.stage"," guardam credenciais reais (a verificação prévia do deploy até confere se os valores do banco estão preenchidos), e ",[324,582,583],{},".sst"," é o estado local do deploy. O ",[324,586,587],{},".gitignore"," do Nuxfire cobre todos eles:",[342,590,593],{"className":591,"code":592,"language":347,"meta":348},[345],".env\n.env.*\n!.env.example\n.sst\n",[324,594,592],{"__ignoreMap":348},[320,596,597,598,600],{},"Crie o repositório na ",[324,599,365],{},", prove que as regras funcionam e só então adicione tudo:",[342,602,604],{"className":463,"code":603,"language":465,"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,605,606,618,637,647],{"__ignoreMap":348},[469,607,608,610,613,616],{"class":471,"line":472},[469,609,476],{"class":475},[469,611,612],{"class":488}," init",[469,614,615],{"class":479}," -b",[469,617,539],{"class":488},[469,619,620,622,625,628,631,634],{"class":471,"line":483},[469,621,476],{"class":475},[469,623,624],{"class":488}," check-ignore",[469,626,627],{"class":479}," -v",[469,629,630],{"class":488}," .env.production",[469,632,633],{"class":488}," .env.stage",[469,635,636],{"class":488}," .sst\n",[469,638,639,641,644],{"class":471,"line":508},[469,640,476],{"class":475},[469,642,643],{"class":488}," add",[469,645,646],{"class":479}," -A\n",[469,648,649,651,654,657,660,664,667,670,672,675],{"class":471,"line":527},[469,650,476],{"class":475},[469,652,653],{"class":488}," diff",[469,655,656],{"class":479}," --cached",[469,658,659],{"class":479}," --name-only",[469,661,663],{"class":662},"sGXK2"," |",[469,665,666],{"class":475}," grep",[469,668,669],{"class":479}," -E",[469,671,499],{"class":498},[469,673,674],{"class":488},"(^|\u002F)\\.env",[469,676,505],{"class":498},[320,678,679,680,683,684,687,688,691,692,695,696,698],{},"O ",[324,681,682],{},"check-ignore"," precisa imprimir a regra que casa com cada arquivo. O último comando precisa imprimir ",[329,685,686],{},"somente"," ",[324,689,690],{},".env.example",". Se qualquer outro arquivo ",[324,693,694],{},".env*"," aparecer, pare e corrija o ",[324,697,587],{}," antes de commitar.",[342,700,702],{"className":463,"code":701,"language":465,"meta":348,"style":348},"git commit -m \"chore: initial commit from Nuxfire\"\n",[324,703,704],{"__ignoreMap":348},[469,705,706,708,711,714,716,719],{"class":471,"line":472},[469,707,476],{"class":475},[469,709,710],{"class":488}," commit",[469,712,713],{"class":479}," -m",[469,715,499],{"class":498},[469,717,718],{"class":488},"chore: initial commit from Nuxfire",[469,720,505],{"class":498},[722,723,724],"blockquote",{},[320,725,726],{},"Se um segredo for commitado alguma vez, apagar o arquivo não basta: ele continua no histórico. Trate a credencial como comprometida, troque-a primeiro e só depois limpe o histórico.",[320,728,729],{},[329,730,556],{},[342,732,735],{"className":733,"code":734,"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,736,734],{"__ignoreMap":348},[337,738,740,741],{"id":739},"etapa-3-crie-o-repositório-no-github-e-envie-a-stage","Etapa 3: crie o repositório no GitHub e envie a ",[324,742,365],{},[320,744,745,746,749,750,752,753,756,757,760],{},"Crie um repositório ",[329,747,748],{},"privado e vazio",": sem README, sem ",[324,751,587],{},", sem licença. No navegador, use ",[329,754,755],{},"New repository",", escolha ",[329,758,759],{},"Private"," e deixe as opções de inicialização desmarcadas. Ou, pela CLI, dentro da pasta do projeto:",[342,762,764],{"className":463,"code":763,"language":465,"meta":348,"style":348},"gh repo create my-product --private --source=. --remote=origin\n",[324,765,766],{"__ignoreMap":348},[469,767,768,770,773,776,779,782,785],{"class":471,"line":472},[469,769,444],{"class":475},[469,771,772],{"class":488}," repo",[469,774,775],{"class":488}," create",[469,777,778],{"class":488}," my-product",[469,780,781],{"class":479}," --private",[469,783,784],{"class":479}," --source=.",[469,786,787],{"class":479}," --remote=origin\n",[320,789,790,791,794],{},"A CLI adiciona o remoto ",[324,792,793],{},"origin"," para você. Sem ela, adicione o remoto manualmente, com a URL que o GitHub mostra:",[342,796,798],{"className":463,"code":797,"language":465,"meta":348,"style":348},"git remote add origin git@github.com:YOUR-USER\u002Fmy-product.git\n",[324,799,800],{"__ignoreMap":348},[469,801,802,804,807,809,812],{"class":471,"line":472},[469,803,476],{"class":475},[469,805,806],{"class":488}," remote",[469,808,643],{"class":488},[469,810,811],{"class":488}," origin",[469,813,814],{"class":488}," git@github.com:YOUR-USER\u002Fmy-product.git\n",[320,816,817,818,820],{},"Nos dois casos, publique a ",[324,819,365],{}," e configure o rastreamento do remoto:",[342,822,824],{"className":463,"code":823,"language":465,"meta":348,"style":348},"git push -u origin stage\n",[324,825,826],{"__ignoreMap":348},[469,827,828,830,833,836,838],{"class":471,"line":472},[469,829,476],{"class":475},[469,831,832],{"class":488}," push",[469,834,835],{"class":479}," -u",[469,837,811],{"class":488},[469,839,539],{"class":488},[320,841,842],{},[329,843,556],{},[342,845,848],{"className":846,"code":847,"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,849,847],{"__ignoreMap":348},[337,851,853,854],{"id":852},"etapa-4-crie-a-production","Etapa 4: crie a ",[324,855,374],{},[320,857,858,859,861],{},"Crie a branch a partir da ",[324,860,365],{},", no mesmo commit, publique-a e volte:",[342,863,865],{"className":463,"code":864,"language":465,"meta":348,"style":348},"git switch -c production\ngit push -u origin production\ngit switch stage\n",[324,866,867,880,892],{"__ignoreMap":348},[469,868,869,871,874,877],{"class":471,"line":472},[469,870,476],{"class":475},[469,872,873],{"class":488}," switch",[469,875,876],{"class":479}," -c",[469,878,879],{"class":488}," production\n",[469,881,882,884,886,888,890],{"class":471,"line":483},[469,883,476],{"class":475},[469,885,832],{"class":488},[469,887,835],{"class":479},[469,889,811],{"class":488},[469,891,879],{"class":488},[469,893,894,896,898],{"class":471,"line":508},[469,895,476],{"class":475},[469,897,873],{"class":488},[469,899,539],{"class":488},[320,901,902,903,905],{},"Agora adicione uma trava local para que a ",[324,904,374],{}," só possa avançar por fast-forward. O Git vai recusar qualquer merge que não seja um fast-forward:",[342,907,909],{"className":463,"code":908,"language":465,"meta":348,"style":348},"git config branch.production.mergeOptions --ff-only\n",[324,910,911],{"__ignoreMap":348},[469,912,913,915,917,920],{"class":471,"line":472},[469,914,476],{"class":475},[469,916,489],{"class":488},[469,918,919],{"class":488}," branch.production.mergeOptions",[469,921,922],{"class":479}," --ff-only\n",[320,924,925],{},[329,926,556],{},[342,928,931],{"className":929,"code":930,"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,932,930],{"__ignoreMap":348},[337,934,936,937,939,940],{"id":935},"etapa-5-torne-a-stage-a-branch-padrão-e-remova-a-main","Etapa 5: torne a ",[324,938,365],{}," a branch padrão e remova a ",[324,941,410],{},[320,943,944,945,947,948,951,952,954],{},"Quem decide a branch padrão é o GitHub, não o seu Git local. Mesmo em um repositório vazio ela pode continuar sendo a ",[324,946,410],{},", então confira explicitamente. O GitHub exige ",[329,949,950],{},"mais de uma branch"," para trocar a padrão, e é por isso que a ",[324,953,374],{}," precisava existir antes.",[320,956,957,958,961,962,964,965,968],{},"No navegador: ",[329,959,960],{},"Settings → Branches → Default branch",", clique no ícone de troca, escolha ",[324,963,365],{},", ",[329,966,967],{},"Update"," e confirme. Pela CLI:",[342,970,972],{"className":463,"code":971,"language":465,"meta":348,"style":348},"gh repo edit --default-branch stage\n",[324,973,974],{"__ignoreMap":348},[469,975,976,978,980,983,986],{"class":471,"line":472},[469,977,444],{"class":475},[469,979,772],{"class":488},[469,981,982],{"class":488}," edit",[469,984,985],{"class":479}," --default-branch",[469,987,539],{"class":488},[320,989,990,991,993,994,997],{},"Depois veja o que existe no remoto e, se a ",[324,992,410],{}," estiver lá (por exemplo, porque o repositório foi criado com um README), apague-a. Faça isso ",[329,995,996],{},"depois"," de trocar a padrão, nunca antes:",[342,999,1001],{"className":463,"code":1000,"language":465,"meta":348,"style":348},"git ls-remote --heads origin\n",[324,1002,1003],{"__ignoreMap":348},[469,1004,1005,1007,1010,1013],{"class":471,"line":472},[469,1006,476],{"class":475},[469,1008,1009],{"class":488}," ls-remote",[469,1011,1012],{"class":479}," --heads",[469,1014,1015],{"class":488}," origin\n",[342,1017,1019],{"className":463,"code":1018,"language":465,"meta":348,"style":348},"git push origin --delete main\n",[324,1020,1021],{"__ignoreMap":348},[469,1022,1023,1025,1027,1029,1032],{"class":471,"line":472},[469,1024,476],{"class":475},[469,1026,832],{"class":488},[469,1028,811],{"class":488},[469,1030,1031],{"class":479}," --delete",[469,1033,1034],{"class":488}," main\n",[320,1036,1037],{},"Por fim, atualize o seu ponteiro local para a branch padrão do remoto:",[342,1039,1041],{"className":463,"code":1040,"language":465,"meta":348,"style":348},"git remote set-head origin --auto\n",[324,1042,1043],{"__ignoreMap":348},[469,1044,1045,1047,1049,1052,1054],{"class":471,"line":472},[469,1046,476],{"class":475},[469,1048,806],{"class":488},[469,1050,1051],{"class":488}," set-head",[469,1053,811],{"class":488},[469,1055,1056],{"class":479}," --auto\n",[320,1058,1059,1060,1062,1063,1065],{},"Se a ",[324,1061,410],{}," foi criada com um README, ela tem um histórico sem relação com o seu. Não faça merge dela na ",[324,1064,365],{},"; apenas apague.",[320,1067,1068],{},[329,1069,556],{},[342,1071,1074],{"className":1072,"code":1073,"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,1075,1073],{"__ignoreMap":348},[337,1077,1079],{"id":1078},"etapa-6-travas-no-github-se-o-seu-plano-tiver","Etapa 6: travas no GitHub (se o seu plano tiver)",[320,1081,1082,1083,1086,1087,1089],{},"A trava local ",[324,1084,1085],{},"--ff-only"," não custa nada e não depende de plano. No GitHub, a proteção de branches e os rulesets dependem do seu plano e da visibilidade do repositório (os rulesets estão documentados para os planos GitHub Team e GitHub Enterprise). Se o seu plano oferecer, proteja a ",[324,1088,374],{}," bloqueando force pushes e restringindo exclusões. Se não, o processo e a trava local bastam, desde que você nunca faça force-push.",[337,1091,1093],{"id":1092},"etapa-7-o-dia-a-dia","Etapa 7: o dia a dia",[320,1095,1096,1097,1099],{},"Trabalhando sozinho, faça commit na ",[324,1098,365],{}," e envie:",[342,1101,1103],{"className":463,"code":1102,"language":465,"meta":348,"style":348},"git switch stage\ngit add -A\ngit commit -m \"feat: describe the change\"\ngit push\n",[324,1104,1105,1113,1121,1136],{"__ignoreMap":348},[469,1106,1107,1109,1111],{"class":471,"line":472},[469,1108,476],{"class":475},[469,1110,873],{"class":488},[469,1112,539],{"class":488},[469,1114,1115,1117,1119],{"class":471,"line":483},[469,1116,476],{"class":475},[469,1118,643],{"class":488},[469,1120,646],{"class":479},[469,1122,1123,1125,1127,1129,1131,1134],{"class":471,"line":508},[469,1124,476],{"class":475},[469,1126,710],{"class":488},[469,1128,713],{"class":479},[469,1130,499],{"class":498},[469,1132,1133],{"class":488},"feat: describe the change",[469,1135,505],{"class":498},[469,1137,1138,1140],{"class":471,"line":527},[469,1139,476],{"class":475},[469,1141,1142],{"class":488}," push\n",[320,1144,1145,1146,1148],{},"Trabalhando em equipe, use branches curtas e pull requests para a ",[324,1147,365],{},":",[342,1150,1152],{"className":463,"code":1151,"language":465,"meta":348,"style":348},"git switch -c feat\u002Fbilling-copy\ngit push -u origin feat\u002Fbilling-copy\n",[324,1153,1154,1165],{"__ignoreMap":348},[469,1155,1156,1158,1160,1162],{"class":471,"line":472},[469,1157,476],{"class":475},[469,1159,873],{"class":488},[469,1161,876],{"class":479},[469,1163,1164],{"class":488}," feat\u002Fbilling-copy\n",[469,1166,1167,1169,1171,1173,1175],{"class":471,"line":483},[469,1168,476],{"class":475},[469,1170,832],{"class":488},[469,1172,835],{"class":479},[469,1174,811],{"class":488},[469,1176,1164],{"class":488},[320,1178,1179,1180,400,1186,964,1189,964,1192,964,1195,1198],{},"Use ",[454,1181,1185],{"href":1182,"rel":1183},"https:\u002F\u002Fwww.conventionalcommits.org\u002F",[1184],"nofollow","Conventional Commits",[324,1187,1188],{},"feat:",[324,1190,1191],{},"fix:",[324,1193,1194],{},"docs:",[324,1196,1197],{},"chore:","). O próprio histórico do Nuxfire os segue, o que deixa as notas de release quase de graça.",[337,1200,1202],{"id":1201},"etapa-8-o-portão-antes-do-primeiro-lançamento","Etapa 8: o portão antes do primeiro lançamento",[320,1204,1205,1206,1208],{},"Nada chega à ",[324,1207,374],{}," sem passar pelas mesmas verificações, sempre:",[342,1210,1212],{"className":463,"code":1211,"language":465,"meta":348,"style":348},"bun install\nbun run test\nbun run doctor -- --stage production\n",[324,1213,1214,1222,1232],{"__ignoreMap":348},[469,1215,1216,1219],{"class":471,"line":472},[469,1217,1218],{"class":475},"bun",[469,1220,1221],{"class":488}," install\n",[469,1223,1224,1226,1229],{"class":471,"line":483},[469,1225,1218],{"class":475},[469,1227,1228],{"class":488}," run",[469,1230,1231],{"class":488}," test\n",[469,1233,1234,1236,1238,1241,1244,1247],{"class":471,"line":508},[469,1235,1218],{"class":475},[469,1237,1228],{"class":488},[469,1239,1240],{"class":488}," doctor",[469,1242,1243],{"class":479}," --",[469,1245,1246],{"class":479}," --stage",[469,1248,879],{"class":488},[320,1250,679,1251,1254,1255,1258],{},[324,1252,1253],{},"doctor"," é a verificação prévia do deploy: valida seu token da Cloudflare, seus valores ",[324,1256,1257],{},"BRAND_*",", os segredos do banco e a zona do domínio, e diz a correção exata de cada problema antes que você gaste minutos em um deploy que vai falhar.",[320,1260,1261,1262,1265,1266,1148],{},"Para um primeiro produto, faça o deploy de um ",[329,1263,1264],{},"estágio de validação"," antes da produção. Um estágio que não é de produção ganha seus próprios Workers, conexão de banco e segredos, e responde em ",[324,1267,1268],{},"\u003Cstage>.dev.\u003Cseu-domínio>",[342,1270,1272],{"className":463,"code":1271,"language":465,"meta":348,"style":348},"bun run deploy -- --stage stage\n",[324,1273,1274],{"__ignoreMap":348},[469,1275,1276,1278,1280,1283,1285,1287],{"class":471,"line":472},[469,1277,1218],{"class":475},[469,1279,1228],{"class":488},[469,1281,1282],{"class":488}," deploy",[469,1284,1243],{"class":479},[469,1286,1246],{"class":479},[469,1288,539],{"class":488},[320,1290,679,1291,1294,1295,964,1298,414,1300,1302,1303,687,1306,1309,1310,1313],{},[324,1292,1293],{},"--"," é necessário para que a flag chegue ao script. O token e os segredos estão em ",[454,1296,1297],{"href":36},"Acesso à Cloudflare",[454,1299,43],{"href":44},[454,1301,51],{"href":52},". Um pré-requisito só da produção vale conhecer desde já: o domínio raiz e o ",[324,1304,1305],{},"www",[329,1307,1308],{},"não"," podem ter nenhum registro A, AAAA ou CNAME no seu DNS, senão a Cloudflare rejeita o domínio personalizado (erro ",[324,1311,1312],{},"100117",").",[320,1315,1316],{},[329,1317,556],{},[342,1319,1322],{"className":1320,"code":1321,"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,1323,1321],{"__ignoreMap":348},[337,1325,1327],{"id":1326},"etapa-9-o-primeiro-lançamento","Etapa 9: o primeiro lançamento",[320,1329,1330,1331,1333],{},"Tudo está verde na ",[324,1332,365],{},". Promova-a:",[342,1335,1337],{"className":463,"code":1336,"language":465,"meta":348,"style":348},"git status\ngit push origin stage\n",[324,1338,1339,1346],{"__ignoreMap":348},[469,1340,1341,1343],{"class":471,"line":472},[469,1342,476],{"class":475},[469,1344,1345],{"class":488}," status\n",[469,1347,1348,1350,1352,1354],{"class":471,"line":483},[469,1349,476],{"class":475},[469,1351,832],{"class":488},[469,1353,811],{"class":488},[469,1355,539],{"class":488},[320,1357,679,1358,1361,1362,1364,1365,1148],{},[324,1359,1360],{},"git status"," precisa dizer que a árvore de trabalho está limpa. Agora avance a ",[324,1363,374],{}," por fast-forward para exatamente o mesmo commit, sem sair da ",[324,1366,365],{},[342,1368,1370],{"className":463,"code":1369,"language":465,"meta":348,"style":348},"git push origin stage:production\n",[324,1371,1372],{"__ignoreMap":348},[469,1373,1374,1376,1378,1380],{"class":471,"line":472},[469,1375,476],{"class":475},[469,1377,832],{"class":488},[469,1379,811],{"class":488},[469,1381,1382],{"class":488}," stage:production\n",[320,1384,1385,1386,1388],{},"Esse push só é aceito se for um fast-forward puro. Confirme que as duas branches são idênticas e mude para a ",[324,1387,374],{},", porque é dela que você faz o deploy:",[342,1390,1392],{"className":463,"code":1391,"language":465,"meta":348,"style":348},"git fetch origin\ngit diff --stat stage origin\u002Fproduction\ngit switch production\ngit pull --ff-only\n",[324,1393,1394,1403,1418,1426],{"__ignoreMap":348},[469,1395,1396,1398,1401],{"class":471,"line":472},[469,1397,476],{"class":475},[469,1399,1400],{"class":488}," fetch",[469,1402,1015],{"class":488},[469,1404,1405,1407,1409,1412,1415],{"class":471,"line":483},[469,1406,476],{"class":475},[469,1408,653],{"class":488},[469,1410,1411],{"class":479}," --stat",[469,1413,1414],{"class":488}," stage",[469,1416,1417],{"class":488}," origin\u002Fproduction\n",[469,1419,1420,1422,1424],{"class":471,"line":508},[469,1421,476],{"class":475},[469,1423,873],{"class":488},[469,1425,879],{"class":488},[469,1427,1428,1430,1433],{"class":471,"line":527},[469,1429,476],{"class":475},[469,1431,1432],{"class":488}," pull",[469,1434,922],{"class":479},[320,1436,679,1437,1440],{},[324,1438,1439],{},"diff"," precisa imprimir nada. Rode a verificação prévia mais uma vez e faça o deploy:",[342,1442,1444],{"className":463,"code":1443,"language":465,"meta":348,"style":348},"bun run doctor -- --stage production\nbun run deploy -- --stage production\n",[324,1445,1446,1460],{"__ignoreMap":348},[469,1447,1448,1450,1452,1454,1456,1458],{"class":471,"line":472},[469,1449,1218],{"class":475},[469,1451,1228],{"class":488},[469,1453,1240],{"class":488},[469,1455,1243],{"class":479},[469,1457,1246],{"class":479},[469,1459,879],{"class":488},[469,1461,1462,1464,1466,1468,1470,1472],{"class":471,"line":483},[469,1463,1218],{"class":475},[469,1465,1228],{"class":488},[469,1467,1282],{"class":488},[469,1469,1243],{"class":479},[469,1471,1246],{"class":479},[469,1473,879],{"class":488},[320,1475,1476],{},"Só depois que o deploy der certo, marque a release com uma tag e volte a trabalhar:",[342,1478,1480],{"className":463,"code":1479,"language":465,"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,1481,1482,1504,1515],{"__ignoreMap":348},[469,1483,1484,1486,1489,1492,1495,1497,1499,1502],{"class":471,"line":472},[469,1485,476],{"class":475},[469,1487,1488],{"class":488}," tag",[469,1490,1491],{"class":479}," -a",[469,1493,1494],{"class":488}," v1.0.0",[469,1496,713],{"class":479},[469,1498,499],{"class":498},[469,1500,1501],{"class":488},"First production release",[469,1503,505],{"class":498},[469,1505,1506,1508,1510,1512],{"class":471,"line":483},[469,1507,476],{"class":475},[469,1509,832],{"class":488},[469,1511,811],{"class":488},[469,1513,1514],{"class":488}," v1.0.0\n",[469,1516,1517,1519,1521],{"class":471,"line":508},[469,1518,476],{"class":475},[469,1520,873],{"class":488},[469,1522,539],{"class":488},[320,1524,1525,1526,1528,1529,1531],{},"Se o deploy falhar, não edite a ",[324,1527,374],{},". Corrija adiante na ",[324,1530,365],{},", rode o portão de novo e repita o fast-forward. A branch pode ficar brevemente à frente do que está no ar, e a ausência da tag mostra exatamente isso.",[320,1533,1534],{},[329,1535,556],{},[342,1537,1540],{"className":1538,"code":1539,"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,1541,1539],{"__ignoreMap":348},[337,1543,1545],{"id":1544},"etapa-10-impeça-as-duas-branches-de-se-afastarem","Etapa 10: impeça as duas branches de se afastarem",[320,1547,1548,1549,1551,1552,1554],{},"O modo de falha que pega todo mundo uma vez: uma correção cai na ",[324,1550,374],{}," (ou um deploy sai da ",[324,1553,365],{},") e as branches deixam de descrever o mesmo código sem ninguém notar. A verificação é uma linha, e deve sempre imprimir nada:",[342,1556,1558],{"className":463,"code":1557,"language":465,"meta":348,"style":348},"git fetch origin\ngit log --oneline stage..origin\u002Fproduction\n",[324,1559,1560,1568],{"__ignoreMap":348},[469,1561,1562,1564,1566],{"class":471,"line":472},[469,1563,476],{"class":475},[469,1565,1400],{"class":488},[469,1567,1015],{"class":488},[469,1569,1570,1572,1575,1578],{"class":471,"line":483},[469,1571,476],{"class":475},[469,1573,1574],{"class":488}," log",[469,1576,1577],{"class":479}," --oneline",[469,1579,1580],{"class":488}," stage..origin\u002Fproduction\n",[320,1582,1583,1584,1586,1587,1589],{},"Se imprimir commits, a ",[324,1585,374],{}," tem trabalho que a ",[324,1588,365],{}," não tem. Uma promoção será rejeitada, e isso está correto. Traga o trabalho de volta, publique e avance de novo:",[342,1591,1593],{"className":463,"code":1592,"language":465,"meta":348,"style":348},"git switch stage\ngit merge origin\u002Fproduction\ngit push origin stage\ngit push origin stage:production\n",[324,1594,1595,1603,1612,1622],{"__ignoreMap":348},[469,1596,1597,1599,1601],{"class":471,"line":472},[469,1598,476],{"class":475},[469,1600,873],{"class":488},[469,1602,539],{"class":488},[469,1604,1605,1607,1610],{"class":471,"line":483},[469,1606,476],{"class":475},[469,1608,1609],{"class":488}," merge",[469,1611,1417],{"class":488},[469,1613,1614,1616,1618,1620],{"class":471,"line":508},[469,1615,476],{"class":475},[469,1617,832],{"class":488},[469,1619,811],{"class":488},[469,1621,539],{"class":488},[469,1623,1624,1626,1628,1630],{"class":471,"line":527},[469,1625,476],{"class":475},[469,1627,832],{"class":488},[469,1629,811],{"class":488},[469,1631,1382],{"class":488},[320,1633,1634,1635,1638],{},"Se o merge relatar conflitos, resolva-os, rode o portão de novo e commite antes de enviar. Nunca resolva isso com ",[324,1636,1637],{},"--force",": você apagaria justamente os commits que quer preservar.",[320,1640,1641],{},[329,1642,556],{},[342,1644,1647],{"className":1645,"code":1646,"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,1648,1646],{"__ignoreMap":348},[337,1650,1652],{"id":1651},"voltando-atrás","Voltando atrás",[320,1654,1655,1656,1658],{},"Não reescreva a ",[324,1657,374],{},". Faça o deploy do código de uma tag anterior:",[342,1660,1662],{"className":463,"code":1661,"language":465,"meta":348,"style":348},"git tag --sort=-creatordate\ngit switch --detach v1.0.0\nbun run deploy -- --stage production\ngit switch stage\n",[324,1663,1664,1673,1684,1698],{"__ignoreMap":348},[469,1665,1666,1668,1670],{"class":471,"line":472},[469,1667,476],{"class":475},[469,1669,1488],{"class":488},[469,1671,1672],{"class":479}," --sort=-creatordate\n",[469,1674,1675,1677,1679,1682],{"class":471,"line":483},[469,1676,476],{"class":475},[469,1678,873],{"class":488},[469,1680,1681],{"class":479}," --detach",[469,1683,1514],{"class":488},[469,1685,1686,1688,1690,1692,1694,1696],{"class":471,"line":508},[469,1687,1218],{"class":475},[469,1689,1228],{"class":488},[469,1691,1282],{"class":488},[469,1693,1243],{"class":479},[469,1695,1246],{"class":479},[469,1697,879],{"class":488},[469,1699,1700,1702,1704],{"class":471,"line":527},[469,1701,476],{"class":475},[469,1703,873],{"class":488},[469,1705,539],{"class":488},[320,1707,1708,1709,1712,1713,1715],{},"Isso restaura o ",[329,1710,1711],{},"código",". As migrações do banco são aplicadas a cada deploy e não são desfeitas, então planeje mudanças de schema primeiro como aditivas (adicione uma coluna, publique o código que a usa, remova a antiga depois). Em seguida, corrija adiante na ",[324,1714,365],{}," e promova uma nova release.",[320,1717,1718],{},[329,1719,556],{},[342,1721,1724],{"className":1722,"code":1723,"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,1725,1723],{"__ignoreMap":348},[337,1727,1729],{"id":1728},"quando-algo-dá-errado","Quando algo dá errado",[1731,1732,1733,1749],"table",{},[1734,1735,1736],"thead",{},[1737,1738,1739,1743,1746],"tr",{},[1740,1741,1742],"th",{},"O que você vê",[1740,1744,1745],{},"O que significa",[1740,1747,1748],{},"O que fazer",[1750,1751,1752,1771,1786,1802,1821,1835],"tbody",{},[1737,1753,1754,1760,1768],{},[1755,1756,1757],"td",{},[324,1758,1759],{},"[rejected] stage -> production (non-fast-forward)",[1755,1761,371,1762,1764,1765,1767],{},[324,1763,374],{}," tem commits que a ",[324,1766,365],{}," não tem",[1755,1769,1770],{},"Etapa 10. Nunca use force.",[1737,1772,1773,1778,1783],{},[1755,1774,1775],{},[324,1776,1777],{},"fatal: Not possible to fast-forward, aborting.",[1755,1779,1780,1781],{},"A trava local impediu um merge na ",[324,1782,374],{},[1755,1784,1785],{},"Mesma causa e mesma solução acima",[1737,1787,1788,1793,1796],{},[1755,1789,1790,1791],{},"O GitHub não deixa apagar a ",[324,1792,410],{},[1755,1794,1795],{},"Em geral, ela ainda é a branch padrão",[1755,1797,1798,1799,1801],{},"Troque a padrão para ",[324,1800,365],{}," primeiro (Etapa 5)",[1737,1803,1804,1813,1818],{},[1755,1805,1806,1807,1809,1810],{},"Um arquivo ",[324,1808,694],{}," aparece em ",[324,1811,1812],{},"git diff --cached",[1755,1814,1815,1816],{},"Falta uma regra no ",[324,1817,587],{},[1755,1819,1820],{},"Corrija antes do commit, nunca depois",[1737,1822,1823,1826,1829],{},[1755,1824,1825],{},"Você fez o deploy da branch errada",[1755,1827,1828],{},"O deploy publica a árvore em checkout",[1755,1830,1831,1834],{},[324,1832,1833],{},"git branch --show-current"," antes de todo deploy",[1737,1836,1837,1843,1846],{},[1755,1838,1839,1840,1842],{},"Erro de domínio ",[324,1841,1312],{}," no primeiro deploy de produção",[1755,1844,1845],{},"O hostname já tem um registro DNS",[1755,1847,1848],{},"Apague o registro A, AAAA ou CNAME e faça o deploy de novo",[337,1850,1852],{"id":1851},"checklist","Checklist",[423,1854,1857,1871,1883,1894,1906,1918,1927],{"className":1855},[1856],"contains-task-list",[358,1858,1861,1865,1866,414,1868,1870],{"className":1859},[1860],"task-list-item",[1862,1863],"input",{"disabled":22,"type":1864},"checkbox"," O repositório é privado e só existem ",[324,1867,365],{},[324,1869,374],{}," no remoto",[358,1872,1874,1876,1877,1879,1880,1882],{"className":1873},[1860],[1862,1875],{"disabled":22,"type":1864}," A ",[324,1878,365],{}," é a branch padrão e a ",[324,1881,410],{}," não existe mais",[358,1884,1886,687,1888,1891,1892],{"className":1885},[1860],[1862,1887],{"disabled":22,"type":1864},[324,1889,1890],{},"git config branch.production.mergeOptions"," imprime ",[324,1893,1085],{},[358,1895,1897,1899,1900,1902,1903,1905],{"className":1896},[1860],[1862,1898],{"disabled":22,"type":1864}," Nenhum arquivo ",[324,1901,694],{},", exceto ",[324,1904,690],{},", está versionado",[358,1907,1909,687,1911,414,1914,1917],{"className":1908},[1860],[1862,1910],{"disabled":22,"type":1864},[324,1912,1913],{},"bun run test",[324,1915,1916],{},"bun run doctor -- --stage production"," estão verdes",[358,1919,1921,687,1923,1926],{"className":1920},[1860],[1862,1922],{"disabled":22,"type":1864},[324,1924,1925],{},"git diff --stat stage origin\u002Fproduction"," imprime nada antes do deploy",[358,1928,1930,1932],{"className":1929},[1860],[1862,1931],{"disabled":22,"type":1864}," A release só foi marcada com tag depois que o deploy deu certo",[320,1934,1935,1936,1938,1939,414,1941,332],{},"De volta à configuração: siga para ",[454,1937,1297],{"href":36}," para criar o token de API, depois ",[454,1940,43],{"href":44},[454,1942,51],{"href":52},[1944,1945,1946],"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":483,"depth":483,"links":1948},[1949,1950,1951,1952,1953,1955,1957,1959,1960,1961,1962,1963,1964,1965,1966],{"id":339,"depth":483,"text":340},{"id":420,"depth":483,"text":421},{"id":459,"depth":483,"text":460},{"id":565,"depth":483,"text":566},{"id":739,"depth":483,"text":1954},"Etapa 3: crie o repositório no GitHub e envie a stage",{"id":852,"depth":483,"text":1956},"Etapa 4: crie a production",{"id":935,"depth":483,"text":1958},"Etapa 5: torne a stage a branch padrão e remova a main",{"id":1078,"depth":483,"text":1079},{"id":1092,"depth":483,"text":1093},{"id":1201,"depth":483,"text":1202},{"id":1326,"depth":483,"text":1327},{"id":1544,"depth":483,"text":1545},{"id":1651,"depth":483,"text":1652},{"id":1728,"depth":483,"text":1729},{"id":1851,"depth":483,"text":1852},"DevOps","2026-09-25","Um manual de nível sênior para quem acabou de adquirir o Nuxfire: crie o repositório, torne a stage a branch padrão, remova a main, promova para production por fast-forward e publique sua primeira versão com segurança.","md","\u002Fimages\u002Fblog\u002Fgit-branching-stage-production.svg","pt-br",{},"\u002Fimages\u002Fblog\u002Fgit-branching-stage-production.png","\u002Fblog\u002Fgit-branches-stage-production-primeiro-lancamento","14 min",{"title":313,"description":1969},"blog\u002Fgit-branches-stage-production-primeiro-lancamento",[1980,1981,1982,1983,51,1984],"Git","GitHub","Branching","Release","SST",{"en":1986,"pt-br":1987,"es":1988},"git-branching-stage-production-first-release","git-branches-stage-production-primeiro-lancamento","git-ramas-stage-production-primer-lanzamiento","D9JQpAP_iVq5OXP1v3ulPn14KXjRyp-5w_8__oAJClg",1790707502208]