Kärnan princip: göra utsläpp snabbt och smärtfritt, och du kommer att släppa oftare. Detta är avgörande för en smidig utveckling - snabba, tillförlitliga distributioner skapar den snabba återkopplingsslinga du behöver. När utplaceringen är skrämmande eller långsam, grupper batch upp förändringar, ökande risk. När utplacering är tråkigt och automatiskt, du skeppar små förändringar ofta.
Denna guide täcker de utgivningsstrategier jag använder i produktionen, från enkla tag-baserade distributioner till multi-paket monorepo publicering. Alla exempel kommer från verkliga GitHub-åtgärder arbetsflöden i det här arkivet.
Före dykning i detaljer, här är hur gemensamma strategier jämföra:
"Strategi på bästa sätt för komplexitet" |----------|----------|------------|-----------| | Taggbaserad Applikationer, explicita utgåvor med låga startups, solo devs, mogna team och | Filialbaserad till Kontinuerlig driftsättning och låg startups, snabbrörliga team | GitFlow Ordförande på Regulerade utgåvor, flera versioner på hög nivå på företag, compliance-tungt | Trunk-baserade + funktionsflaggor Höghastighetsteam med medelhög teknik, mogna startups | Multipelförpackning för Monorepo på biblioteken, delade kodbaser på medelhöga plattformar, OSS-projekt
Startups och små team: Börja med taggbaserad eller grenbaserad distribution. Håll det enkelt - du kan alltid lägga till komplexitet senare. Trunk-baserad utveckling med funktionsflaggor är populärt i skala men överdöd för små lag.
Företag: Ofta kräver GitFlow eller liknande för efterlevnad, verifieringsspår, och release management. Flera miljöer (dev, QA, iscensättning, prod) med godkännande grindar. Artifact intyg allt mer krävs för leveranskedjan säkerhet.
Solo utvecklare: Tag-baserad är perfekt. Tryck på en tagg, utplacering händer. Ingen ceremoni, ingen overhead.
Plattform/Biblioteksgrupper: Behöver monorepo strategier med oberoende versionering per paket. Semantisk versionering är avgörande för nedströms konsumenter.
Den enklaste och mest tillförlitliga strategin. Olika taggar prefixar rutt till olika miljöer eller utlösa olika åtgärder.
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
Varför det fungerar: Enkel mental modell, explicita utplaceringar, enkel rollback via tidsstämplade taggar.
# 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
För monorepos med flera publiceringsbara paket, använd taggprefix för att identifiera vilket paket som ska släppas:
# 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
Extrahera versionen och använd den i hela:
- 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 }}
För automatisk versionshantering, MinVer beräknar versioner från Git-taggar:
<PackageReference Include="MinVer" Version="6.0.0" PrivateAssets="all" />
<PropertyGroup>
<MinVerTagPrefix>umamiv</MinVerTagPrefix>
</PropertyGroup>
Utplacera automatiskt när koden landar på specifika grenar. Vanliga i startups och snabbrörliga team.
on:
push:
branches: [main] # → Production
# branches: [develop] # → Staging
Förmåner: Inga manuella steg, driftsättningar vid sammanfogning Nackdelar: Oavsiktlig driftsättning möjlig, mindre explicit historia
Jag använder en hybrid metod - bygga på gren push (CI-verifiering), men bara publicera på taggar:
on:
push:
tags: ['scheduler-*']
branches: [main, local]
jobs:
build:
# Always build
publish:
if: startsWith(github.ref, 'refs/tags/') # Only publish on tags
För självvärdiga utplaceringar, Vakttornet drar automatiskt nya bilder:
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
Utbyggnadsflöde: Push tag → GitHub Åtgärder bygger → Tryck till register → Watchtower drar → Container omstarter. Total tid: ~5 minuter.
Snabba distributioner är värdelösa om du distribuerar buggar. Varje arbetsflöde bör innehålla grindar:
- name: Run tests
run: dotnet test --configuration Release
- name: Build
run: dotnet build --configuration Release
# Tests or build fail → workflow stops → no publish
För flerramspaket, bygg alla mål:
- run: dotnet build -c Release --framework net8.0
- run: dotnet build -c Release --framework net9.0
Modernt tillvägagångssätt - inga hemligheter att rotera, inga nycklar att läcka:
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 byter sin OIDC- token mot en kortlivad NuGet API-nyckel. Konfigurera förtroendet på NuGet.org för att aktivera detta.
Artefaktintyg Bevisa att dina artefakter byggdes i CI, inte manipulerade.
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
Konsumenterna kontrollerar med: gh attestation verify oci://index.docker.io/myuser/myapp:latest --owner myuser
Detta uppnår SLSA nivå 2. För nivå 3, användning Återanvändbara arbetsflöden.
Lag behöver intressenter för att förhandsgranska ändringar innan sammanslagning.
Företagsstrategi - Branch-baserade förhandsgranskningsmiljöer:
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.
Uppstart/solo-inflygning - Tunnel din lokala maskin:
# Cloudflare Tunnel (free)
cloudflared tunnel run --url http://localhost:5000 my-preview
# → https://my-preview.cfargotunnel.com
Eller använd Trådvakt VPN för intern åtkomst till din dev-maskin.
Taggstädning: Git taggar stanna kvar för alltid.
git tag -d old-test-tag # Delete local
git push origin :refs/tags/old-test-tag # Delete remote
Namngivningskonventioner: Var konsekvent.
release-YYYY.MM.DD för framställninglocal-feature-name för devpackagev1.2.3 för bibliotekHemligheter: Förvaras i GitHub hemligheter, aldrig i kod. Obligatoriska hemligheter typiskt:
DOCKER_HUB_ACCESS_TOKENNUGET_API_KEY (eller använd OIDC)NPM_TOKENMonorepo-utveckling: Använd projektreferenser under utveckling, byt till paketreferenser för verifiering av installation:
<ProjectReference Include="..\MyLib\MyLib.csproj" />
<!-- <PackageReference Include="MyLib" Version="1.0.0" /> -->
Samma principer, olika verktyg:
på Docker Komposiera på Kubernetes |----------------|------------| på Vakttornet Förbehåll IIIA-PT-17 / Flux | på docker-compose.yml-miljöer på omstart av container med rullande driftsättning på plats på manuell upprullning på GitOps upprullning på
De arbetsflöden som visas här körs i det här arkivet - kontrollera .github/workflows/ för fullständiga genomföranden.
Kom ihåg: Snabba, pålitliga driftsättningar är grunden för smidig utveckling. Investera i din lansering pipeline tidigt.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.