Sürüm Numarası Ne Anlatır? SemVer 2.0.0, Pre-release, Build Metadata ve CalVer
Sürüm numarası, kime söz verdiğine göre seçilir: paketler için SemVer 2.0.0 uyumluluk sözü verir, deploy edilen uygulamalar için CalVer ve build numarası "ne zaman, ne çıktı" sorusunu cevaplar. Pre-release ve build metadata sıralamasını NuGet.Versioning ve npm semver ile gerçek çıktılarla karşılaştırıyor, 0.x aralıklarını, breaking change türlerini, .NET ve Angular destek politikalarını ve Bookstore için karar tablosunu ele alıyoruz.
Sürüm notu: Bu yazıdaki örnekler .NET 10 (SDK 10.0.402), NuGet.Versioning 8.0.0, Node.js 24 ve semver 7.8.6 ile denenmiştir.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore'da (bir online kitapçı) API ile Angular istemcisinin paylaştığı DTO'ları (Data Transfer Object; katmanlar arasında veri taşıyan sade class'lar) Bookstore.Contracts adlı bir NuGet paketine taşımaya karar verdik. Paketin ilk yayınına giden yolda feed'de şu sürümler birikmiş durumda:
1.0.0-rc.1
1.0.0-beta.11
1.0.0
1.0.0-alpha.beta
1.0.0-beta.2
0.9.12
1.0.0-alpha
1.0.0-beta
1.0.0-alpha.1
Bunları NuGet'in ve SemVer (Semantic Versioning; sürüm numarasına uyumluluk anlamı yükleyen kural seti) 2.0.0 spesifikasyonunun gözünden eskiden yeniye sırala. Özellikle iki soruya cevap ver: beta.11 mi daha yeni, beta.2 mi? alpha.beta nereye düşer? Cevabı aşağıdaki programın çıktısında göreceğiz; o arada sürüm numarasının aslında neyi anlattığına bakalım.
SemVer 2.0.0: Üç Sayı, Bir Söz
SemVer'in kendisi bir araç değil, bir sözleşme. Spesifikasyonun ilk maddesi bir public API beyan etmeni istiyor; geri kalan her kural o API'ye göre tanımlı. MAJOR.MINOR.PATCH biçimindeki üç sayının her biri, paketi kullanan kişiye ayrı bir şey söylüyor:
- PATCH arttıysa: API değişmedi, yalnızca geriye uyumlu hata düzeltmeleri var. Gözü kapalı yükseltebilirsin.
- MINOR (ara sürüm numarası) arttıysa: geriye uyumlu yeni işlevler eklendi. Mevcut kodun derlenir ve aynı davranır; yeni bir şey kullanmak istersen kullanırsın.
- MAJOR (ana sürüm numarası) arttıysa: geriye uyumsuz bir değişiklik var. Release notlarını okumadan yükseltme.
Bir de çoğu zaman gözden kaçan bir kural var: yayınlanmış bir sürümün içeriği değiştirilmez. 1.4.2 bir kez çıktıysa, içinde hata olsa bile düzeltme 1.4.3 olarak çıkar. NuGet ve npm bu kuralı registry seviyesinde zorluyor; serinin NuGet yazısında aynı sürümü ikinci kez push'lamayı deneyip hatasını göreceğiz.
Sayıların karşılaştırılması da önemli: her bölüm sayı olarak karşılaştırılır, metin olarak değil. 1.10.0, 1.9.0'dan büyüktür. Git & GitHub serisinin "Git Tag ve Release" yazısında git tag'in listeyi alfabetik sıraladığını ve --sort=-v:refname ile düzeldiğini görmüştük; aynı hata kendi yazdığın script'lerde de olur, sürümleri string olarak sıralayan her kod er geç yanılır.
Pre-release ve Build Metadata
Üç sayının arkasına iki isteğe bağlı bölüm eklenebiliyor. Tire ile başlayan kısım pre-release etiketi (1.0.0-beta.2), artı ile başlayan kısım build metadata (1.0.0+sha.5114f85). İkisi de noktayla ayrılmış identifier'lardan oluşur; identifier'larda yalnız ASCII (temel İngilizce karakter tablosu) harf, rakam ve tire kullanılabilir, boş identifier olmaz ve pre-release'teki sayısal identifier'lar başında sıfır taşıyamaz (beta.01 geçersiz).
Sıralama kuralları şöyle: önce üç sayı karşılaştırılır. Sayılar eşitse pre-release'li sürüm, pre-release'siz sürümden küçüktür; yani 1.0.0-rc.1, 1.0.0'dan öncedir. İki pre-release karşılaştırılırken identifier'lar soldan sağa tek tek ele alınır: ikisi de sayıysa sayı olarak, değilse ASCII sırasıyla karşılaştırılır; sayısal identifier her zaman harfli olandan küçüktür; ortak kısım eşitse identifier'ı fazla olan büyüktür. Build metadata sıralamaya hiç katılmaz.
Tahmin listesini NuGet.Versioning paketiyle sıralayan küçük bir console uygulaması yazalım. Bu paket NuGet client'ının kendi sürüm mantığı; dolayısıyla dotnet restore'un vereceği kararı birebir gösteriyor:
using NuGet.Versioning;
string[] input =
[
"1.0.0", "1.0.0-rc.1", "1.0.0-beta.11", "1.0.0-beta.2",
"1.0.0-alpha.beta", "1.0.0-alpha", "1.0.0-alpha.1", "1.0.0-beta",
"0.9.12"
];
var sorted = input.Select(NuGetVersion.Parse).Order(VersionComparer.VersionRelease);
Console.WriteLine(string.Join(" < ", sorted.Select(v => v.ToFullString())));
var a = NuGetVersion.Parse("1.0.0+sha.5114f85");
var b = NuGetVersion.Parse("1.0.0+sha.0c2d9e1");
Console.WriteLine($"build metadata ignored: {a == b}");
Console.WriteLine($"with metadata compared: {VersionComparer.VersionReleaseMetadata.Equals(a, b)}");
var upper = NuGetVersion.Parse("1.0.0-RC.1");
var lower = NuGetVersion.Parse("1.0.0-rc.1");
Console.WriteLine($"RC.1 vs rc.1 (NuGet): {upper.CompareTo(lower)}");
foreach (var text in new[] { "1.0.0-beta.01", "1.0", "2026.04.1", "v1.2.3" })
{
Console.WriteLine($"{text,-14} SemVer: {SemanticVersion.TryParse(text, out _),-5} NuGet: {(NuGetVersion.TryParse(text, out var v) ? v.ToNormalizedString() : "invalid")}");
}
$ dotnet run --project tools/SemverLab
0.9.12 < 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
build metadata ignored: True
with metadata compared: False
RC.1 vs rc.1 (NuGet): 0
1.0.0-beta.01 SemVer: False NuGet: invalid
1.0 SemVer: False NuGet: 1.0.0
2026.04.1 SemVer: False NuGet: 2026.4.1
v1.2.3 SemVer: False NuGet: invalid
İlk satır tahminin cevabı. beta.11, beta.2'den büyük, çünkü ikinci identifier'lar sayı ve 11 > 2. alpha.beta, alpha.1'den büyük, çünkü harfli identifier sayısal olandan büyük sayılıyor. alpha ise alpha.1'den küçük; ortak kısım aynı ve alpha.1'in bir identifier'ı fazla. Bu sıra, SemVer spesifikasyonunun 11. maddesindeki örnek zincirle aynı.
Kalan satırlar asıl ilginç kısım. Build metadata farklı iki sürüm NuGet'e göre eşit; metadata'yı da karşılaştırmak istersen VersionComparer.VersionReleaseMetadata gibi ayrı bir comparer gerekiyor. NuGet'in sürüm referansı da metadata'yı normalize ederken atıyor. Bu yüzden commit hash'ini build metadata'ya koymak güvenli: sıralamayı bozmaz, ama aynı sayılarla iki farklı paket yayınlayabileceğin anlamına da gelmez, feed ikisini aynı sürüm sayar.
RC.1 ile rc.1'in NuGet'te eşit çıkması ise spesifikasyondan bir sapma. SemVer ASCII sırası istiyor, büyük harf küçük harften önce gelir. NuGet dokümanı bu farkı açıkça listeliyor: NuGetVersion pre-release etiketlerini büyük-küçük harf ayırmadan karşılaştırıyor, dört bölümlü sürümü (1.0.0.1) kabul ediyor ve yalnız MAJOR'ı zorunlu tutuyor. Aynı soruları npm'in kullandığı semver paketine soralım:
import semver from "semver";
console.log("RC.1 vs rc.1 (npm):", semver.compare("1.0.0-RC.1", "1.0.0-rc.1"));
console.log("valid 2026.04.1:", semver.valid("2026.04.1"));
console.log("valid v1.2.3:", semver.valid("v1.2.3"));
const checks = [
["1.9.0", "^1.2.3"],
["2.0.0", "^1.2.3"],
["0.2.9", "^0.2.3"],
["0.3.0", "^0.2.3"],
["0.0.4", "^0.0.3"],
["1.3.0-beta.1", "^1.2.0"],
["1.2.4-beta.1", "^1.2.4-alpha.1"],
];
for (const [version, range] of checks) {
console.log(`${version.padEnd(13)} ${range.padEnd(15)} ${semver.satisfies(version, range)}`);
}
$ cd tools/semver-js
$ npm start
> start
> node index.js
RC.1 vs rc.1 (npm): -1
valid 2026.04.1: null
valid v1.2.3: 1.2.3
1.9.0 ^1.2.3 true
2.0.0 ^1.2.3 false
0.2.9 ^0.2.3 true
0.3.0 ^0.2.3 false
0.0.4 ^0.0.3 false
1.3.0-beta.1 ^1.2.0 false
1.2.4-beta.1 ^1.2.4-alpha.1 true
npm tarafında 1.0.0-RC.1, 1.0.0-rc.1'den küçük; spesifikasyona uygun. Aynı ekibin hem NuGet hem npm paketi yayınladığı bir projede etiketleri her zaman küçük harfle yazmak bu farkı tamamen ortadan kaldırır. Baştaki v harfi için de iki ekosistem ayrışıyor: npm'in semver.valid'i v1.2.3'ü temizleyip kabul ediyor, NuGet reddediyor. Git tag'inde v kullanmak yerleşik bir alışkanlık, ama paket sürümüne taşınmamalı; serinin üçüncü yazısındaki araçlar tag'den sürüm üretirken bu öneki kendileri atıyor.
0.x: Başlangıç Geliştirme ve Hiç 1.0 Olmayan Paketler
Spesifikasyonun dördüncü maddesi 0.y.z aralığını başlangıç geliştirme dönemi olarak tanımlıyor: bu dönemde her şey her an değişebilir ve public API stabil kabul edilmez. 1.0.0 ise public API'yi tanımlayan sürüm. Kâğıt üzerinde basit, ama araçlar 0.x'i farklı yorumluyor. Yukarıdaki çıktıda ^1.2.3 aralığı 1.9.0'ı kabul ediyor, 2.0.0'ı etmiyor; bu beklenen. ^0.2.3 ise yalnız 0.2.x'i kabul ediyor, 0.3.0'ı reddediyor. ^0.0.3 daha da dar: sadece 0.0.3. npm, 0.x dünyasında soldaki ilk sıfır olmayan sayıyı MAJOR gibi davranıyor; yani 0.2'den 0.3'e geçişi breaking change sayıyor.
NuGet'te böyle bir özel durum yok. PackageReference'taki Version="0.2.3" "en az 0.2.3" demek ve NuGet bu koşulu sağlayan en düşük sürümü seçiyor. Kullanıcı 0.3.0'a kendisi yükselttiğinde, 0.x'te kırılma serbest olduğu için hiçbir garanti almıyor.
Pratik sonuç şu: bir paketi uzun süre 0.x'te tutmak, kullanıcıya "her güncelleme kırılabilir" demek. Bookstore.Contracts'ı API ve istemci aynı anda kullanmaya başladığı gün public API'si fiilen var; o gün 1.0.0'a çıkmak dürüst olan. Çıktının son satırı da pre-release'ler için ayrı bir kuralı gösteriyor: npm aralıkları pre-release sürümleri, aralıkta aynı MAJOR.MINOR.PATCH üçlüsüne sahip bir pre-release yazılı değilse kabul etmiyor. ^1.2.0, 1.3.0-beta.1'i seçmez; yanlışlıkla beta kurulmasını önleyen iyi bir varsayılan.
"Breaking Change" Neye Göre?
MAJOR'ı ne zaman artıracağını bilmek için önce sürüm numarasının kime söz verdiğini belirlemek gerekiyor. Üç farklı durum var.
Library için söz, public API'ye ve davranışa. Microsoft'un .NET library rehberi breaking change'leri üçe ayırıyor: kaynak seviyesinde kırılma (yeniden derleyince hata, ör. yeni bir overload'un çağrıyı belirsiz hâle getirmesi), binary kırılma (eski sürüme göre derlenmiş kodun çalışırken MissingMethodException alması, ör. method imzasına parametre eklemek) ve davranış kırılması (imza aynı, sonuç farklı). Rehber davranış değişikliğini en sık karşılaşılan tür olarak görüyor ve eski hatalı davranışa yaslanan kullanıcılar için bir hata düzeltmesinin de kırılma olabileceğini hatırlatıyor. Bunlara iki madde daha eklemek gerekiyor: desteklenen minimum framework'ü yükseltmek (net8.0 hedefini bırakmak) ve public API'de tipi görünen bir bağımlılığı yeni bir major'a taşımak. İkisi de kullanıcının kodu değişmeden derlenmesini engelleyebilir.
HTTP API için söz, contract'a. Endpoint'ler, JSON alanları, status code'lar. Buradaki sürüm genelde URL'de ya da header'da durur ve tek bir sayıdır (v1, v2); mekaniğini ASP.NET Core Web API serisinin "ASP.NET Core Web API Versioning: Asp.Versioning ile URL, Query String ve Header" yazısında anlattık. Message ve event contract'larının sürümü de ayrı bir konu, Messaging ve Event-Driven Architecture serisinde ele alındı. Deploy ettiğin uygulamanın sürümü ile API contract'ının sürümü aynı şey değil: Bookstore.Api her hafta yeni bir build çıkarırken contract hâlâ v1 olabilir.
Deploy edilen uygulama için ise kimse sürüm numarasına göre bağımlılık kurmuyor. Kullanıcı bookstore'un web sitesine girdiğinde "2.7.0'a geçeyim mi?" diye sormuyor; ona hangi sürümün geldiğine sen karar veriyorsun. Bu durumda MAJOR/MINOR ayrımı bir tartışma konusu olmaktan öteye geçmez: "bu değişiklik minor mu major mu?" toplantısı kimsenin işine yaramaz. Uygulamada sürüm numarasının görevi başka: "production'da hangi build koşuyor ve ne zaman çıktı?" sorusuna cevap vermek. Bunun için tarih ve build numarası, üç anlamsal sayıdan daha fazla bilgi taşır.
CalVer: Sürümü Takvimden Almak
CalVer (Calendar Versioning; sürüm numarasının bir kısmını yayın tarihinden alan yaklaşım) bir spesifikasyon değil, bir isimlendirme alışkanlığı. calver.org bölümleri token'larla tarif ediyor: YYYY tam yıl, YY 2000'den itibaren sıfırsız kısa yıl (2026 için 26), 0Y sıfırla doldurulmuş kısa yıl, MM yerine artık M ve 0M ay için, benzer şekilde hafta ve gün token'ları. Yanına MINOR, MICRO gibi sıradan sayılar eklenebiliyor. Bilinen kullanıcılar: Ubuntu YY.0M (26.04), pip YY.MINOR.MICRO, JetBrains IDE'leri YYYY.MINOR.MICRO, Home Assistant YYYY.M.MICRO.
CalVer'in güçlü olduğu yer, sürümün yaşını tek bakışta söylemesi. 2026.11.3 gören biri Kasım 2026'nın üçüncü yayını olduğunu anlar; destek tarihlerini konuşurken çok işe yarar. Zayıf olduğu yer ise uyumluluk hakkında hiçbir şey söylememesi. Bu yüzden library'lerde değil, deploy edilen uygulamalarda tercih ediliyor.
.NET ve npm dünyasında CalVer kullanacaksan iki teknik sınıra dikkat et. Birincisi sıfır doldurma: 0M formatında 2026.04.1 yazarsan, ilk programın çıktısında görüldüğü gibi NuGet bunu 2026.4.1'e normalize ediyor, npm'in semver.valid'i ise tamamen reddediyor (null). İki ekosistemde de sıfırsız M kullan. İkincisi bölüm büyüklüğü: .NET'in AssemblyVersion ve FileVersion bölümleri 65535'ten büyük olamaz. Tarihi tek sayıya sıkıştırmaya çalışırsan build kırılıyor:
$ dotnet build tools/SemverLab -p:Version=20261114.1.0
…/tools/SemverLab/obj/Debug/net10.0/SemverLab.AssemblyInfo.cs(19,55): error CS7034: The specified version string '20261114.1.0.0' does not conform to the required format - major[.minor[.build[.revision]]]
YYYY.M.BUILD biçimi (2026.11.3) her bölümde sınırın altında kalıyor ve hem NuGet hem npm hem de System.Version tarafından kabul ediliyor.
Destek Politikalarını Okumak: .NET ve Angular
Sürüm numarası, yayın takvimi ve destek süresiyle birlikte okununca anlam kazanıyor. Bookstore'un iki ana bağımlılığının politikası, kendi politikamızı yazarken iyi birer örnek.
.NET her Kasım bir major sürüm çıkarıyor. Çift sayılı sürümler LTS (Long Term Support; uzun süreli destek) ve üç yıl destekleniyor; tek sayılılar STS (Standard Term Support; standart süreli destek) ve iki yıl. Microsoft'un destek sayfasına göre .NET 8 (LTS) ve .NET 9 (STS) desteği aynı gün, 10 Kasım 2026'da bitti; .NET 10 ve .NET 11'in desteği 14 Kasım 2028'de bitiyor. Patch'ler ayda bir, genelde Patch Tuesday'de (her ayın ikinci salısı) çıkıyor ve kümülatif: destekte kalmak için en son patch'te olmak gerekiyor. Burada sürüm numarası bir sözü değil bir takvimi taşıyor; .NET 11'in .NET 10'dan "daha kırıcı" olduğu anlamına gelmiyor.
Angular ise SemVer kullanıyor ve breaking change'leri yalnız major sürümlerde yapıyor. Angular'ın release sayfasına göre v22'den itibaren major sürümler yaklaşık 12 ayda bir çıkıyor (önceden 6 ayda bir çıkıyordu); her major 12 ay aktif destek, ardından 12 ay LTS alıyor. LTS döneminde yalnız kritik düzeltmeler ve güvenlik yamaları geliyor. Deprecate edilen API'ler en az bir major boyunca (yaklaşık bir yıl) kalıyor ve yalnız major sürümde kaldırılıyor. Sayfadaki tabloya göre şu an v22 aktif, v21 ve v20 LTS'te.
İki politikadan çıkan ders: bir sürüm numarası, ancak arkasında yazılı bir destek politikası varsa kullanıcıya planlama imkânı veriyor. Serinin son yazısında Bookstore için bu politikanın şablonunu yazacağız.
Bookstore İçin Karar Tablosu
Bookstore'da sürümlenen dört şey var ve her biri farklı bir kitleye cevap veriyor:
| Bileşen | Kimin için | Şema | Örnek |
|---|---|---|---|
Bookstore.Api | Ops ekibi, destek, log ve telemetri | CalVer + build | 2026.11.3+5114f85 |
bookstore-web | Ops ekibi ve hata bildiren kullanıcı | CalVer + build | 2026.11.3+5114f85 |
Bookstore.Contracts (NuGet) | Paketi kullanan .NET projeleri | SemVer 2.0.0 | 1.4.0, 2.0.0-rc.1 |
@bookstore/ui (npm) | Paketi kullanan Angular projeleri | SemVer 2.0.0 | 1.2.0, 1.3.0-next.0 |
Uygulamalar CalVer kullanıyor, çünkü onları kimse aralıkla referans etmiyor ve "ne zaman çıktı" bilgisi daha değerli. Commit hash'i build metadata olarak sona ekleniyor; sıralamayı etkilemiyor ama hangi koddan derlendiğini kesin olarak söylüyor. Paketler SemVer kullanıyor, çünkü başka projeler onlara ^1.2.0 veya Version="1.4.0" gibi aralıklarla bağlanıyor ve bu aralıkların doğru çalışması MAJOR'ın dürüst artırılmasına bağlı. HTTP API contract'ı ise ayrı bir eksen: Bookstore.Api 2026.11.3 sürümünde de 2027.2.1 sürümünde de /api/v1/books'u sunabilir.
Üretimde Dikkat
Sürüm numarası bir kez yayınlandıktan sonra geri alınamaz, bu yüzden kuralları yayından önce yaz. Bir VERSIONING.md dosyasında hangi bileşenin hangi şemayı kullandığını, MAJOR'ı neyin tetiklediğini ve pre-release etiketlerinin adlarını (alpha, beta, rc, hepsi küçük harf) belirt. Etiket adlarını sabitlemek, NuGet ile npm arasındaki büyük-küçük harf farkını da kendiliğinden çözüyor.
Pre-release numaralarını her zaman nokta ile ayır: beta.2, beta2 değil. beta2 tek bir harfli identifier olduğu için ASCII sırasıyla karşılaştırılıyor ve beta10, beta2'den önce geliyor. NuGet dokümanının SemVer 2.0 sıralama örneğinde de alpha10'un alpha2'den önce sıralandığı görülüyor.
Uygulama sürümünü loglarda ve telemetride her satırla birlikte taşımak, bir hatanın hangi sürümle başladığını bulmayı dakikalara indirir. Bunun .NET ve Angular'daki mekaniği bir sonraki yazının konusu. Son olarak, sürüm kararını tek bir yerde ver: aynı commit'in CI'da 1.4.0, geliştiricinin makinesinde 1.4.0-dev diye etiketlenmesi en çok kafa karıştıran durumlardan biri.
Sık Düşülen Tuzaklar
Minor diye yayınlanan major. Bookstore.Contracts 1.5.0'da yalnız bir property ekledin, ama aynı sürümde public API'de tipi görünen bir bağımlılığı bir üst major'a çektin ya da net8.0 hedefini bıraktın. Kullanıcı için bu bir kırılma; SemVer FAQ (sık sorulan sorular) bölümü bağımlılık güncellemesini ancak public API değişmiyorsa uyumlu sayıyor. Hedef framework'ü veya public bağımlılığın major'ını değiştiren sürüm MAJOR'dır.
1.0'a hiç çıkmamak. "Henüz stabil değil" diye yıllarca 0.x'te kalan paketlerde npm her minor'ı kırıcı sayıyor ve kullanıcılar ^0.4.0 gibi dar aralıklara sıkışıyor. Paketi production'da biri kullanıyorsa 1.0.0 zamanı gelmiştir.
Sürümleri string olarak sıralamak. Deploy script'inde sort ile "en son sürüm"ü bulmak 1.10.0'ı 1.9.0'ın altına koyar. Sürüm karşılaştırmasını her zaman bir SemVer kütüphanesine bırak.
Build metadata ile yeni sürüm çıkardığını sanmak. 1.4.0+a1 ile 1.4.0+b2 NuGet için aynı sürüm; feed ikincisini kabul etmez, kabul eden bir registry'de ise hangisinin çözüleceği belirsiz kalır.
CalVer'de sıfır doldurma ve tek sayılı tarih. 2026.04.1 NuGet'te sessizce 2026.4.1 olur, npm'de geçersizdir; 20261114 gibi bir bölüm .NET assembly sürümünde build'i kırar.
Küçük Bir Deneme
★☆☆ SemverLab'daki listeye 1.0.0-beta.2.1, 1.0.0-beta.-1 ve 1.0.0-0.3.7 ekle ve önce tahminini yaz, sonra çalıştır. Hangisi geçerli, geçerli olanlar sıralamada nereye düşüyor?
★★☆ semver-js'e ~0.2.3, ~1.2.3 ve 1.2.x aralıklarını ekle ve ^ ile farkını tabloya dök. Aynı aralıkları NuGet'in VersionRange.Parse'ıyla ifade etmeye çalış; hangileri NuGet'te doğrudan karşılığa sahip değil?
★★★ Kendi ekibinin bir library'si ve bir uygulaması için kısa bir VERSIONING.md yaz: şema, MAJOR'ı tetikleyen değişikliklerin listesi (minimum framework ve public bağımlılık dahil), pre-release etiketleri ve CalVer formatı. Son üç sürümünüzü bu kurallara göre yeniden numaralandır; kaç tanesi değişiyor?
Sürüm numarasının ne anlattığını konuştuk; ama numara build çıktısına ve çalışan uygulamaya taşınmazsa production'da kimse onu göremez. Bir sonraki yazıda .NET'in Version, AssemblyVersion, FileVersion ve InformationalVersion property'lerini, Source Link'i ve Bookstore API'sinde bir /version endpoint'ini ele alıyoruz.