Il principio di base: rendere i rilasci veloci e indolore, e si rilascerà più spesso. Questo è fondamentale per lo sviluppo agile - le distribuzioni rapide e affidabili creano il loop di feedback veloce di cui hai bisogno. Quando la distribuzione è spaventosa o lenta, i team batch up cambiano, aumentando il rischio. Quando la distribuzione è noiosa e automatica, spedisci spesso piccoli cambiamenti.
Questa guida copre le strategie di rilascio che uso in produzione, dalle semplici implementazioni basate su tag alla pubblicazione multi-package monorepo. Tutti gli esempi provengono dal reale Azioni GitHub flussi di lavoro in questo repository.
Prima di tuffarsi nei dettagli, ecco come le strategie comuni confrontano:
| Strategy | Best For | Complexity | Common In |
|---|---|---|---|
| Tag-based | Applicazioni, uscite esplicite | Basso | Startups, solo devs, team maturi |
| Basato su un ramo | Dispiegamento continuo | Basso | Startup, squadre in movimento rapido |
| GitFlowCity name (optional, probably does not need a translation) | Release regolamentati, versioni multiple | High | Enterprise, compliance-heavy |
| Opzioni basate su Trunk + Funzionalità | Squadre ad alta velocità | Media | Big tech, startup mature |
| Pacchetto multi-monorepo | Biblioteche, basi di codice condivise | Medium | Platform teams, OSS projects |
Startup e squadre piccole: Inizia con l'implementazione basata su tag o rami. Mantieni la semplicità - puoi sempre aggiungere la complessità in seguito. Lo sviluppo basato su Trunk con flag di funzionalità è popolare in scala, ma l'overkill per i piccoli team.
Impresa: Spesso richiede GitFlow o simili per la conformità, audit trail, e la gestione del rilascio. Ambienti multipli (dev, QA, messa in scena, prod) con cancelli di omologazione.
Sviluppatori singoli: Tag-based è l'ideale. Spingere un tag, la distribuzione avviene. Nessuna cerimonia, nessuna sopra spese.
Piattaforma/Squadre di biblioteca: Necessita di strategie monorepo con versione indipendente per pacchetto. La versione semantica è fondamentale per i consumatori a valle.
La strategia più semplice e affidabile. Different tag prefixes route to different environments or trigger different actions.
on:
push:
tags:
- 'release-*' # Production
- 'local-*' # Dev environment
- name: Build Docker image
run: |
TAG_NAME=${GITHUB_REF#refs/tags/}
if [[ "$TAG_NAME" == local-* ]]; then
docker build -t myapp:local .
else
docker build -t myapp:latest -t myapp:$(date +%s) .
fi
Perché funziona: Modello mentale semplice, spiegamenti espliciti, facile rollback tramite tag con timestamped.
# Deploy to production
git tag release-v2024.12.01 && git push origin release-v2024.12.01
# Deploy to dev
git tag local-feature-test && git push origin local-feature-test
Per le monorepos con più pacchetti pubblicabili, utilizzare i prefissi dei tag per identificare quale pacchetto rilasciare:
# Different workflows, different tag patterns
# umami-net.yml
on:
push:
tags: ['umamiv*.*.*'] # e.g., umamiv1.0.5
# fetchextension.yml
on:
push:
tags: ['fetchextension-v*.*.*'] # e.g., fetchextension-v1.2.0
Estrarre la versione e usarla in tutto:
- name: Extract version
run: echo "VERSION=${GITHUB_REF#refs/tags/umamiv}" >> $GITHUB_OUTPUT
- name: Build & Pack
run: |
dotnet build -c Release -p:Version=${{ steps.version.outputs.VERSION }}
dotnet pack -c Release -p:PackageVersion=${{ steps.version.outputs.VERSION }}
Per la versione automatica, MinVerCity name (optional, probably does not need a translation) calcola le versioni dai tag Git:
<PackageReference Include="MinVer" Version="6.0.0" PrivateAssets="all" />
<PropertyGroup>
<MinVerTagPrefix>umamiv</MinVerTagPrefix>
</PropertyGroup>
Distribuire automaticamente quando il codice atterra su rami specifici. Comune in startup e team in rapido movimento.
on:
push:
branches: [main] # → Production
# branches: [develop] # → Staging
Pro: Nessun passo manuale, implementa sulla fusione Contro: Implementazioni accidentali possibili, cronologia meno esplicita
Uso un approccio ibrido - basato su branch push (verifica CI), ma pubblica solo sui tag:
on:
push:
tags: ['scheduler-*']
branches: [main, local]
jobs:
build:
# Always build
publish:
if: startsWith(github.ref, 'refs/tags/') # Only publish on tags
Per i dispiegamenti auto-ospitati, Torre di guardia automaticamente tira nuove immagini:
services:
app:
image: myapp:latest
labels:
- "com.centurylinklabs.watchtower.enable=true"
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 300 # Check every 5 minutes
Flusso di distribuzione: Push tag → GitHub Azioni costruisce → Push to Registry → Torre di controllo tira → Riavvia contenitore. Tempo totale: ~5 minuti.
Le implementazioni veloci sono inutili se implementa i bug. Ogni flusso di lavoro dovrebbe includere i cancelli:
- name: Run tests
run: dotnet test --configuration Release
- name: Build
run: dotnet build --configuration Release
# Tests or build fail → workflow stops → no publish
Per i pacchetti multi-frame, creare tutti gli obiettivi:
- run: dotnet build -c Release --framework net8.0
- run: dotnet build -c Release --framework net9.0
Approccio moderno - nessun segreto da ruotare, nessuna chiave da perdere:
permissions:
id-token: write
contents: read
- uses: NuGet/login@v1
with:
user: 'myusername'
- run: dotnet nuget push *.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }}
GitHub scambia il suo token OIDC per una chiave NuGet API di breve durata. Configura la fiducia su NuGet.org per abilitarla.
Certificazioni di artefatti Dimostra che i tuoi artefatti sono stati costruiti in CI, non manomessi.
permissions:
id-token: write
attestations: write
- uses: docker/build-push-action@v6
id: push
with:
push: true
tags: myapp:latest
- uses: actions/attest-build-provenance@v2
with:
subject-name: index.docker.io/myuser/myapp
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
I consumatori verificano con: gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser
A tal fine SLSA Livello 2. Per il livello 3, utilizzare flussi di lavoro riutilizzabili.
Le squadre hanno bisogno di stakeholder per visualizzare in anteprima i cambiamenti prima di fondersi.
Approccio alle imprese - Ambienti di anteprima basati su branch:
on:
pull_request:
types: [opened, synchronize]
- run: |
BRANCH=$(echo ${{ github.head_ref }} | sed 's/[^a-zA-Z0-9]/-/g')
docker build -t myapp:preview-$BRANCH .
# Deploy to k8s namespace, cloud platform, etc.
Approccio di avvio/solo - Tunnel la vostra macchina locale:
# Cloudflare Tunnel (free)
cloudflared tunnel run --url http://localhost:5000 my-preview
# → https://my-preview.cfargotunnel.com
O usare WireguardCity name (optional, probably does not need a translation) VPN per l'accesso interno del team alla macchina dev.
Pulizia etichetta: Git tag rimangono in giro per sempre.
git tag -d old-test-tag # Delete local
git push origin :refs/tags/old-test-tag # Delete remote
Convenzioni di denominazione: Siate coerenti.
release-YYYY.MM.DD per la produzionelocal-feature-name per devpackagev1.2.3 per le bibliotecheSegreti: Conservare in Segreti di GitHub, mai in codice. Segreti richiesti in genere:
DOCKER_HUB_ACCESS_TOKENNUGET_API_KEY (o usare OIDC)NPM_TOKENSviluppo di Monorepo: Utilizzare i riferimenti del progetto durante lo sviluppo, passare ai riferimenti dei pacchetti per la verifica dell'implementazione:
<ProjectReference Include="..\MyLib\MyLib.csproj" />
<!-- <PackageReference Include="MyLib" Version="1.0.0" /> -->
Stessi principi, diversi strumenti:
| Docker Compose | Kubernetes |
|---|---|
| Torre di Controllo | ArgoCD / Flux |
| Ambienti docker-compose.yml | Namespace |
| Riavvio del contenitore | spiegamento del rotolamento |
| Rollback manuale | GitOps rollback |
I flussi di lavoro mostrati qui vengono eseguiti in questo repository - check .github/workflows/ per implementazioni complete.
Ricorda: Gli implementazioni rapide e affidabili sono alla base dello sviluppo agile. Investite presto nella vostra pipeline di rilascio.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.