Chapterبەش 3 · Lectureوانە 3.1

Versions and Builds: What 1.0.0 Meansوەشانەکان و بیلدەکان: ⁦1.0.0⁩ واتای چییە

What version numbers promise and how software is built and released: version vs build vs release, Semantic Versioning 2.0.0 (MAJOR.MINOR.PATCH, breaking changes, resets), what 1.0.0 means, pre-releases and build metadata, a runnable semver sort in Python and the text-sorting mistake, CalVer, PEP 440, Java LTS, Android versionCode and Flutter's version line, version constraints and lock files, build pipelines and artifacts (a zipapp .pyz), debug vs release builds, annotated Git tags and git describe, changelogs, and continuous delivery vs deployment — told through Bazaar Cart's version story from 0.1.0 to 2.0.0.

ژمارەی چ بەڵێنێک دەدات و چۆن و بڵاو دەکرێتەوە: ، و ، ⁦2.0.0 (MAJOR.MINOR.PATCH⁩، ، سفرکردنەوە)، ⁦1.0.0⁩ واتای چییە، و زانیاریی ، ڕیزکردنی semver بە Python و هەڵەی ڕیزکردن وەک دەق، CalVer، ⁦PEP 440⁩، LTSـی Java، versionCodeـی Android و دێڕی وەشانی Flutter، و ، زنجیرەی و (.pyzـێکی zipapp)، debug و release، ڕوونکراوە و git describe، و بەرامبەر — لە ڕێگەی چیرۆکی Bazaar Cart لە ⁦0.1.0⁩ـەوە تا ⁦2.0.0⁩.

20 min read22 خولەک خوێندنەوە · 21 stepsهەنگاو

What you will learnچی فێر دەبیت

  • Tell a version, a build and a release apart.
  • Choose the next semantic version for a change, and explain what 0.y.z and 1.0.0 promise.
  • Order versions with pre-releases and build metadata, in your head and in Python, and avoid sorting them as text.
  • Read other schemes (CalVer, PEP 440, Android and Flutter version numbers) and dependency constraints with lock files.
  • Build a runnable artifact, tag a release in Git, write a changelog entry, and tell continuous delivery from continuous deployment.
  • ، و لە یەک جیا بکەیتەوە.
  • داهاتووی بۆ گۆڕانکارییەک هەڵبژێریت و ڕوون بکەیتەوە ⁦0.y.z⁩ و ⁦1.0.0⁩ چ بەڵێنێک دەدەن.
  • لەگەڵ و زانیاریی ڕیز بکەیت، لە مێشکتدا و بە Python و خۆت لە ڕیزکردنیان وەک دەق بپارێزیت.
  • شێوازەکانی تر بخوێنیتەوە (CalVer، ⁦PEP 440⁩، ژمارەی وەشانی Android و Flutter) و لەگەڵ .
  • کارپێکراو بکەیت، لە Gitـدا تاگ بکەیت، بەشێکی بنووسیت و لە جیا بکەیتەوە.

1.0.0, 1.0.1, 2.0.0: what do the numbers promise?⁦1.0.0⁩، ⁦1.0.1⁩، ⁦2.0.0⁩: ژمارەکان چ بەڵێنێک دەدەن؟

Bazaar Cart has a history in numbers. The team released 0.1.0, 0.2.0 and 0.3.0 while they were still building, and 1.0.0 when Soran's shop began taking real orders. A rounding bug led to 1.0.1, a discount to 1.1.0, and a change that broke other programs to 2.0.0. Each number tells users something before they update.

Bazaar Cart مێژوویەکی هەیە بە ژمارە. تیمەکە ⁦0.1.0⁩، ⁦0.2.0⁩ و ⁦0.3.0⁩ـی بڵاو کردەوە کاتێک هێشتا دروستیان دەکرد و ⁦1.0.0⁩ کاتێک دوکانەکەی سۆران دەستی کرد بە وەرگرتنی داواکاریی ڕاستەقینە. بەرزکردنەوەی نرخ بوو بە هۆی ⁦1.0.1⁩، داشکانێک بوو بە هۆی ⁦1.1.0⁩ و گۆڕانکارییەک کە تری تێکدا بوو بە هۆی ⁦2.0.0⁩. هەر ژمارەیەک پێش شتێک بە دەڵێت.

Other programs use Bazaar Cart's code: the shop's website and its Telegram bot call line_price(), delivery_fee() and place_order(). These functions, with their parameters and results, are Bazaar Cart's public API — and the public API is what the numbers make promises about.

تر کۆدی Bazaar Cart بەکار دەهێنن: ماڵپەڕی دوکانەکە و بۆتی تێلێگرامەکەی بانگی line_price()، delivery_fee() و place_order() دەکەن. ئەم لەگەڵ و ئەنجامەکانیان گشتیی Bazaar Cartـن — و ژمارەکان لەبارەی گشتی بەڵێن دەدەن.

Animation of a version counter with three boxes, MAJOR, MINOR and PATCH. 0.1.0: line_price() works. 0.2.0: delivery fee, MINOR goes up. 0.3.0: products in SQLite. 1.0.0: first release, Soran's shop takes real orders, MAJOR becomes 1 and the others reset to 0. 1.0.1: rounding fix, PATCH goes up. 1.1.0: 5 % discount, MINOR goes up and PATCH resets. 2.0.0: place_order() now returns an Order receipt instead of a number, a breaking change, so MAJOR goes up and MINOR and PATCH reset.
Animation of a version counter with three boxes, MAJOR, MINOR and PATCH. 0.1.0: line_price() works. 0.2.0: delivery fee, MINOR goes up. 0.3.0: products in SQLite. 1.0.0: first release, Soran's shop takes real orders, MAJOR becomes 1 and the others reset to 0. 1.0.1: rounding fix, PATCH goes up. 1.1.0: 5 % discount, MINOR goes up and PATCH resets. 2.0.0: place_order() now returns an Order receipt instead of a number, a breaking change, so MAJOR goes up and MINOR and PATCH reset.
Bazaar Cart's version story: which number goes up, and why.چیرۆکی Bazaar Cart: کام ژمارە زیاد دەبێت و بۆچی.CêIT

Version, build and releaseوەشان، بیلد و وەشانی بڵاوکراوە

Three words that are easy to mix up (the words in English):

سێ وشە کە بە ئاسانی تێکەڵ دەکرێن (وشەکان بە ئینگلیزی):

  • Version: one numbered state of the software, such as 1.0.1.
  • Build: turning source code into something that runs, and the result of one such run. A team may build many times a day; each build gets a build number.
  • Release: a version given to people outside the team — customers, an app store, other programs.
  • : یەک دۆخی ژمارەداری ، وەک ⁦1.0.1⁩.
  • : گۆڕینی بۆ شتێک کە کار دەکات و ئەنجامی یەک جار لەو کارە. تیمێک لەوانەیە ڕۆژانە چەندین جار بکات؛ هەر ژمارەیەک وەردەگرێت، کە پێی دەوترێت .
  • : کە دەدرێت بە خەڵکی دەرەوەی تیمەکە — کڕیاران، ، تر.
The bakery next to the shopنانەواخانەکەی تەنیشت دوکانەکە

The baker's recipe is the version (“recipe 3”). Every batch he bakes from it is a build (batch 57, batch 58…). The batch he puts on the counter for customers is the release. He may bake test batches that nobody buys.

ڕەچەتەی نانەواکە («ڕەچەتەی 3»). هەر جارێک کە لێیەوە نان دەکات (جاری ⁦57⁩، جاری ⁦58⁩…). ئەو نانەی دایدەنێت لەسەر پێشخانەکە بۆ کڕیاران . لەوانەیە نانی تاقیکردنەوەش بکات کە کەس نایکڕێت.

Where the analogy stops workingسنووری ئەم نموونەیە

Two batches of bread are never exactly the same; two builds of the same code should be.

دوو جاری نان هەرگیز ڕێک وەک یەک نین؛ دوو هەمان کۆد دەبێت وەک یەک بن.

Version 1.0.1 at the left. Arrows go to three builds made from it, numbered 55, 56 and 57. Builds 55 and 56 stay inside the team for testing. Build 57 goes on to the right as the release, to the shop's website, the Telegram bot and customers' phones.وەشانی 1.0.1 لە چەپ. تیرەکان دەچن بۆ سێ بیلد کە لێی دروست کراون، بە ژمارەکانی 55، 56 و 57. بیلدەکان 55 و 56 لە ناو تیمەکەدا بۆ تاقیکردنەوە دەمێننەوە. بیلدی 57 بەرەو ڕاست دەڕوات وەک وەشانی بڵاوکراوە، بۆ ماڵپەڕی دوکانەکە، بۆتی تێلێگرام و مۆبایلی کڕیاران.
One version, many builds, one release.یەک ، زۆر ، یەک .CêIT

Semantic Versioning: MAJOR.MINOR.PATCHوەشانبەندیی واتایی: ⁦MAJOR.MINOR.PATCH⁩

Most libraries and many apps follow Semantic Versioning 2.0.0 (semver.org), written by Tom Preston-Werner, a co-founder of GitHub. A version has three numbers, MAJOR.MINOR.PATCH, and each one tells the users of your public API what kind of change happened:

زۆربەی و زۆر پەیڕەوی ⁦2.0.0⁩ ⁦(semver.org)⁩ دەکەن، کە تۆم پرێستن-وێرنەر، یەکێک لە دامەزرێنەرانی GitHub، نووسیویەتی. سێ ژمارەی هەیە ⁦(MAJOR.MINOR.PATCH)⁩ و هەر یەکەیان بە بەکارهێنەرانی گشتیت دەڵێت چ جۆرە گۆڕانکارییەک ڕووی داوە:

  • PATCH goes up for bug fixes that break nothing: 1.0.0 → 1.0.1.
  • MINOR goes up for new features that break nothing, and when something is marked deprecated; PATCH goes back to 0: 1.0.1 → 1.1.0.
  • MAJOR goes up for a breaking change: code that worked with the old version may stop working. MINOR and PATCH go back to 0: 1.1.0 → 2.0.0.
  • PATCH () بۆ چاککردنەوەی زیاد دەبێت کە هیچ شتێک تێک نادات: ⁦1.0.0 → 1.0.1⁩.
  • MINOR () بۆ تایبەتمەندیی نوێ کە هیچ شتێک تێک نادات زیاد دەبێت، هەروەها کاتێک شتێک وەک نیشان دەکرێت؛ PATCH دەگەڕێتەوە بۆ ⁦0: 1.0.1 → 1.1.0⁩.
  • MAJOR () بۆ زیاد دەبێت: کۆدێک کە لەگەڵ کۆن کاری دەکرد لەوانەیە ئیتر کار نەکات. MINOR و PATCH دەگەڕێنەوە بۆ ⁦0: 1.1.0 → 2.0.0⁩.

One more rule: once a version is released, its contents never change. Every change, however small, needs a new number.

یاسایەکی تر: کاتێک بڵاو کرایەوە، ناوەڕۆکەکەی هەرگیز ناگۆڕێت. هەموو گۆڕانکارییەک، هەرچەند بچووک بێت، ژمارەیەکی نوێی پێویستە.

The version 2.1.3-rc.1+57 written large in coloured parts. 2 is MAJOR: breaking changes. 1 is MINOR: new features that break nothing. 3 is PATCH: bug fixes. -rc.1 is an optional pre-release label after a hyphen. +57 is optional build metadata after a plus, ignored when comparing versions.وەشانی 2.1.3-rc.1+57 بە گەورەیی و بە بەشی ڕەنگاوڕەنگ نووسراوە. 2 MAJORـە: گۆڕانکارییە شکێنەرەکان. 1 MINORـە: تایبەتمەندیی نوێ کە هیچ تێک نادات. 3 PATCHـە: چاککردنەوەی باگەکان. -rc.1 نیشانەیەکی ئارەزوومەندانەی وەشانی پێش بڵاوکردنەوەیە دوای خەتێکی بچووک. +57 زانیاریی ئارەزوومەندانەی بیلدە دوای +، کە لە بەراوردکردنی وەشانەکاندا پشتگوێ دەخرێت.
The parts of a semantic version.بەشەکانی ژمارەیەکی .CêIT

Semantic Versioning: MAJOR.MINOR.PATCHوەشانبەندیی واتایی: ⁦MAJOR.MINOR.PATCH⁩

Which number goes up?کام ژمارە زیاد دەبێت؟

Ask three questions in this order; the first yes decides. The number that goes up resets every number to its right to 0. Version numbers are not decimals: after 1.9.0 comes 1.10.0, not 2.0.

سێ پرسیار بەم ڕیزە بکە؛ یەکەم بەڵێ بڕیار دەدات. ئەو ژمارەیەی زیاد دەبێت هەموو ژمارەکانی لای ڕاستی دەگەڕێنێتەوە بۆ 0. ژمارەی ژمارەی دەیی نییە: دوای ⁦1.9.0⁩ دێت ⁦1.10.0⁩، نەک ⁦2.0⁩.

A flowchart. First question: can code that uses the public API break? Yes: raise MAJOR, for example 1.4.2 to 2.0.0. No: second question: did you add something, or mark something deprecated? Yes: raise MINOR, 1.4.2 to 1.5.0. No: only fixes: raise PATCH, 1.4.2 to 1.4.3.هێڵکارییەکی ڕەوت. پرسیاری یەکەم: ئایا کۆدێک کە APIـی گشتی بەکار دەهێنێت دەشکێت؟ بەڵێ: MAJOR زیاد بکە، بۆ نموونە 1.4.2 بۆ 2.0.0. نەخێر: پرسیاری دووەم: ئایا شتێکت زیاد کردووە یان شتێکت وەک بەسەرچوو نیشان کردووە؟ بەڵێ: MINOR زیاد بکە، 1.4.2 بۆ 1.5.0. نەخێر: تەنیا چاککردنەوە: PATCH زیاد بکە، 1.4.2 بۆ 1.4.3.
Ask about breaking first, then about new things; everything else is a patch.سەرەتا لەبارەی شکاندن بپرسە، دواتر لەبارەی شتی نوێ؛ هەموو شتێکی تر پینەیە.CêIT

What 1.0.0 means⁦1.0.0⁩ واتای چییە

Major version zero (0.y.z) is for early development: anything may change at any time, and nobody should treat the API as stable. Semver's FAQ suggests starting at 0.1.0 and raising MINOR with every release — exactly what Bazaar Cart did.

سفر ⁦(0.y.z)⁩ بۆ قۆناغی سەرەتای گەشەپێدانە: هەر شتێک هەر کاتێک لەوانەیە بگۆڕێت و کەس نابێت وەک شتێکی جێگیر سەیر بکات. پرسیارە باوەکانی semver پێشنیار دەکەن لە ⁦0.1.0⁩ـەوە دەست پێ بکەیت و لەگەڵ هەر MINOR زیاد بکەیت — ڕێک ئەوەی Bazaar Cart کردی.

1.0.0 defines the public API. From then on, the numbers keep their promise: no breaking change without a new MAJOR. Release 1.0.0 when people use the software in production or depend on its API. The FAQ puts it simply: if you already worry a lot about backward compatibility, you should probably be at 1.0.0 already.

⁦1.0.0⁩ گشتی دیاری دەکات. لەوە بەدواوە ژمارەکان بەڵێنەکەیان دەپارێزن: هیچ بەبێ MAJORـی نوێ نییە. ⁦1.0.0⁩ بڵاو بکەرەوە کاتێک خەڵک بە ڕاستی بەکار دەهێنن یان پشت بە دەبەستن. پرسیارە باوەکان بە سادەیی دەیڵێن: ئەگەر ئێستا زۆر نیگەرانی لەگەڵ کۆنیت، لەوانەیە دەبوو پێشتر گەیشتبیتە ⁦1.0.0⁩.

1.0.0 does not mean perfect, finished or bug-free. That is why 1.0.1 exists.

⁦1.0.0⁩ واتای تەواو، کۆتاییهاتوو یان بێ نییە. بۆیە ⁦1.0.1⁩ هەیە.

A road. On the left, a building site with 0.1.0, 0.2.0 and 0.3.0: anything may change. In the middle, a gate marked 1.0.0: the public API is promised. On the right, after the gate: 1.0.1 fixes, 1.1.0 new features and 2.0.0 breaking changes, each announced by its number.ڕێگایەک. لە چەپ، شوێنێکی بیناسازی بە 0.1.0، 0.2.0 و 0.3.0: هەر شتێک لەوانەیە بگۆڕێت. لە ناوەڕاست، دەروازەیەک بە نیشانەی 1.0.0: بەڵێن بە APIـی گشتی دەدرێت. لە ڕاست، دوای دەروازەکە: 1.0.1 چاککردنەوە، 1.1.0 تایبەتمەندیی نوێ و 2.0.0 گۆڕانکارییە شکێنەرەکان، هەر یەکەیان بە ژمارەکەی ڕادەگەیەنرێت.
Before 1.0.0 anything goes; from 1.0.0 the numbers keep a promise.پێش ⁦1.0.0⁩ هەر شتێک دەبێت؛ لە ⁦1.0.0⁩ـەوە ژمارەکان بەڵێنێک دەپارێزن.CêIT

Pre-releases and build metadataوەشانەکانی پێش بڵاوکردنەوە و زانیاریی بیلد

Before a big release, teams publish test versions. A pre-release adds a hyphen and labels after PATCH: 1.0.0-alpha, 1.0.0-beta.2, 1.0.0-rc.1. Alpha is early and incomplete. A beta version is nearly finished and given to some real users to find bugs. rc means release candidate: it becomes the release if no serious bug appears. Real labels in 2026: ArtCraft's apps are marked early alpha and numbered 0.x (Case Study: ArtCraft).

پێش گەورە، تیمەکان تاقیکردنەوە بڵاو دەکەنەوە. خەتێکی بچووک و نیشانە دوای PATCH زیاد دەکات: 1.0.0-alpha، 1.0.0-beta.2، 1.0.0-rc.1. ئەلفا سەرەتایی و ناتەواوە. نزیکە لە تەواوبوون و دەدرێت بە هەندێک ڕاستەقینە بۆ دۆزینەوەی . rc واتە کاندیدی بڵاوکردنەوە: ئەگەر هیچ گەورە دەرنەکەوت، دەبێت بە . نیشانەی ڕاستەقینە لە ⁦2026⁩دا: ArtCraft وەک سەرەتایی نیشان کراون و ژمارەکانیان بە 0 دەست پێ دەکەن (نموونەیەکی ڕاستەقینە: ArtCraft).

To decide which version is newer, semver compares MAJOR, MINOR and PATCH as numbers, then ranks every pre-release below its normal version. Labels are compared part by part: numbers as numbers, words in ASCII order, and a longer list wins when the first parts are equal. Build metadata after a plus (1.0.0+57) is ignored.

بۆ ئەوەی دیاری بکرێت کام نوێترە، semver MAJOR، MINOR و PATCH وەک ژمارە بەراورد دەکات، دواتر هەموو لە خوار دادەنێت. نیشانەکان بەش بە بەش بەراورد دەکرێن: ژمارە وەک ژمارە، وشە بە ڕیزی ASCII و لیستی درێژتر دەباتەوە ئەگەر بەشەکانی سەرەتا وەک یەک بن. زانیاریی دوای + (1.0.0+57) پشتگوێ دەخرێت.

A ladder from bottom to top: 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 and, at the top, 1.0.0. Notes: beta.11 is above beta.2 because 11 > 2 as numbers; every pre-release is below 1.0.0; 1.0.0+57 is on the same step as 1.0.0.پەیژەیەک لە خوارەوە بۆ سەرەوە: 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. تێبینییەکان: beta.11 لە سەرووی beta.2ـەوەیە چونکە وەک ژمارە 11 > 2؛ هەموو وەشانێکی پێش بڵاوکردنەوە لە خوار 1.0.0ـەوەیە؛ 1.0.0+57 لەسەر هەمان پلەی 1.0.0ـە.
Precedence: from the earliest pre-release up to the release.پێشینەیی: لە یەکەم بۆ .CêIT

Comparing versions in Pythonبەراوردکردنی وەشانەکان لە Pythonـدا

A short program can sort versions the semver way. A regular expression splits a version into its parts, and semver_key() turns each version into a tuple, which Python compares part by part.

کورت دەتوانێت بە شێوەی semver ڕیز بکات. بۆ بەشەکانی دابەش دەکات و semver_key() هەر دەکات بە ، کە Python بەش بە بەش بەراوردی دەکات.

A semver sort keyکلیلی ڕیزکردنی semversemver.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسە
"""Compare version numbers the Semantic Versioning 2.0.0 way."""
import re

PATTERN = re.compile(
    r"(\d+)\.(\d+)\.(\d+)"        # MAJOR.MINOR.PATCH
    r"(?:-([0-9A-Za-z.-]+))?"     # -pre-release (optional)
    r"(?:\+([0-9A-Za-z.-]+))?"    # +build metadata (optional, ignored)
)


def semver_key(version):
    """A sort key: numbers compare as numbers, pre-releases come first."""
    m = PATTERN.fullmatch(version)
    if m is None:
        raise ValueError(f"not a semantic version: {version!r}")
    major, minor, patch = int(m[1]), int(m[2]), int(m[3])
    if m[4] is None:                      # a normal release ...
        pre = (1,)                        # ... ranks above its pre-releases
    else:
        parts = []
        for part in m[4].split("."):      # alpha.1 -> "alpha", "1"
            if part.isdigit():
                parts.append((0, int(part), ""))   # numbers first, by value
            else:
                parts.append((1, 0, part))         # then words, A-Z order
        pre = (0, parts)
    return (major, minor, patch, pre)


if __name__ == "__main__":
    versions = ["1.10.0", "1.0.0", "2.0.0", "1.0.0-rc.1", "1.9.0",
                "1.0.0-beta.11", "1.0.0-alpha", "1.0.0-beta.2", "0.3.0"]
    print(sorted(versions, key=semver_key))
    print(semver_key("1.0.0+57") == semver_key("1.0.0"))
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 4-8

Three numbers, then an optional -pre-release and an optional +build part.

سێ ژمارە، دواتر بەشێکی ئارەزوومەندانەی -pre-release و بەشێکی ئارەزوومەندانەی +build.

Lineدێڕی 16

int() makes 10 bigger than 9 — the whole point.

int() ⁦10⁩ لە 9 گەورەتر دەکات — ئەمە هەموو مەبەستەکەیە.

Lineدێڕی 17-18

A normal release gets (1,); a pre-release gets (0, …), so it sorts lower.

ئاسایی (1,) وەردەگرێت؛ (0, …) وەردەگرێت، بۆیە لە خوارەوە ڕیز دەکرێت.

Lineدێڕی 22-25

Numeric labels rank below words; numbers compare by value, words in ASCII order.

نیشانە ژمارەییەکان لە خوار وشەکانەوەن؛ ژمارە بە بەها و وشە بە ڕیزی ASCII بەراورد دەکرێن.

Lineدێڕی 34

Build metadata is ignored: 1.0.0+57 and 1.0.0 get the same key.

زانیاریی پشتگوێ دەخرێت: ⁦1.0.0+57⁩ و ⁦1.0.0⁩ هەمان کلیل وەردەگرن.

Package managers such as pip, pub and npm do this comparison for you every time they choose a version. Writing it once shows why versions must never be compared as plain text — the next screen.

وەک pip، pub و npm هەموو جارێک کە هەڵدەبژێرن ئەم بەراوردە بۆت دەکەن. نووسینی بۆ یەک جار پیشان دەدات بۆچی هەرگیز نابێت وەک دەقی ئاسایی بەراورد بکرێن — شاشەی داهاتوو.

Comparing versions in Pythonبەراوردکردنی وەشانەکان لە Pythonـدا

A common mistake: sorting versions as textهەڵەیەکی باو: ڕیزکردنی وەشانەکان وەک دەق

Versions look like text, but text is compared character by character (lexicographic order). At the third character 1 (from 1.10.0) is smaller than 9, so “1.10.0” comes first. The fix is to compare numbers:

وەک دەق دەردەکەون، بەڵام دەق پیت بە پیت بەراورد دەکرێت (ڕیزبەندیی فەرهەنگی). لە پیتی سێیەمدا 1 (لە ⁦1.10.0⁩) لە 9 بچووکترە، بۆیە «⁦1.10.0⁩» یەکەم دێت. چارەسەرەکە بەراوردکردنی ژمارەکانە:

Text order vs number orderڕیزی دەق بەرامبەر ڕیزی ژمارەsort_mistake.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسە
versions = ["1.9.0", "1.10.0", "1.2.0"]

print(sorted(versions))            # strings: compared letter by letter
print("1.10.0" > "1.9.0")

def numbers(version):
    return tuple(int(n) for n in version.split("."))

print(sorted(versions, key=numbers))   # (1, 10, 0) > (1, 9, 0)
print(numbers("1.10.0") > numbers("1.9.0"))
1.10.0 and 1.9.0 written under each other, character by character. The first two characters, 1 and the dot, are equal. At the third character, 1 is less than 9, so text order puts 1.10.0 first: wrong. Below, the same versions as numbers: (1, 10, 0) and (1, 9, 0). 10 is greater than 9, so 1.10.0 is newer: right.1.10.0 و 1.9.0 لە ژێر یەکتردا، پیت بە پیت نووسراون. دوو پیتی یەکەم، 1 و خاڵەکە، وەک یەکن. لە پیتی سێیەمدا 1 لە 9 بچووکترە، بۆیە ڕیزی دەق 1.10.0 یەکەم دادەنێت: هەڵە. لە خوارەوە هەمان وەشانەکان وەک ژمارە: (1, 10, 0) و (1, 9, 0). 10 لە 9 گەورەترە، بۆیە 1.10.0 نوێترە: ڕاست.
Text compares characters; versions need numbers.دەق پیتەکان بەراورد دەکات؛ پێویستیان بە ژمارەیە.CêIT

Git has the same trap: git tag lists tags in alphabetical order, while git tag --sort=v:refname sorts them as versions:

Git هەمان تەڵەی هەیە: git tag بە ڕیزی ئەلفوبێ لیست دەکات، بەڵام git tag --sort=v:refname وەک ڕیزیان دەکات:

Listing tagsلیستکردنی تاگەکانی GitBASHType in a terminalلە تێرمیناڵدا بینووسە
git tag
git tag --sort=v:refname

Other numbering schemesشێوازەکانی تری ژمارەدانان

Semver is not the only scheme. You will meet these too:

semver تاکە شێواز نییە. ئەمانەش دەبینیت:

  • Calendar versioning (CalVer): the number is a date. Ubuntu 26.04 LTS came out in April 2026 (year.month); pip uses year.minor.micro. It tells when a version came out, not how much changed — useful for software released on a timetable.
  • Python packages (PEP 440): pre-releases are written 1.0.0a1, 1.0.0b2, 1.0.0rc1, plus 1.0.0.post1 and 1.0.0.dev0; Python itself came as 3.13.0rc1 before 3.13.0. MAJOR.MINOR.PATCH fits, but semver's hyphen and plus parts are not allowed in published versions: 1.0.0-rc.1 becomes 1.0.0rc1.
  • Java: a feature release every six months and a long-term support version every two years; 17.0.20 means Java 17, update 20 (Java versions).
  • ⁦(CalVer)⁩: ژمارەکە ڕێکەوتێکە. ⁦Ubuntu 26.04 LTS⁩ لە نیسانی ⁦2026⁩ـدا دەرچوو (ساڵ.مانگ)؛ pip ساڵ⁦.minor.micro⁩ بەکار دەهێنێت. دەڵێت کەی دەرچوو، نەک چەند گۆڕاوە — بۆ کە بە خشتەی کات دەردەچێت بەسوودە.
  • ⁦Python (PEP 440)⁩: بەم شێوەیە دەنووسرێن 1.0.0a1، 1.0.0b2، 1.0.0rc1، لەگەڵ 1.0.0.post1 و 1.0.0.dev0؛ خودی Python وەک ⁦3.13.0rc1⁩ پێش ⁦3.13.0⁩ هات. ⁦MAJOR.MINOR.PATCH⁩ دەگونجێت، بەڵام بەشی خەت و +ـی semver لە بڵاوکراوەدا ڕێگەپێدراو نین: 1.0.0-rc.1 دەبێت بە 1.0.0rc1.
  • Java: هەر شەش مانگ و هەر دوو ساڵ ؛ 17.0.20 واتە ⁦Java 17⁩، ⁦20⁩ (وەشانەکانی Java).
A table of four schemes. Semantic versioning, example 2.1.3: what kind of change. Calendar versioning, example Ubuntu 26.04: when it was released, April 2026. PEP 440, example 3.13.0rc1: a Python release candidate. Java, example 17.0.20: feature release 17, update 20.خشتەیەکی چوار شێواز. وەشانبەندیی واتایی، نموونە 2.1.3: چ جۆرە گۆڕانکارییەک. وەشانبەندیی ڕێکەوتی، نموونە Ubuntu 26.04: کەی بڵاو کرایەوە، نیسانی 2026. PEP 440، نموونە 3.13.0rc1: کاندیدی بڵاوکردنەوەی Python. Java، نموونە 17.0.20: وەشانی بڵاوکراوەی 17، نوێکردنەوەی 20.
Four schemes, four kinds of information in the number.چوار شێواز، چوار جۆر زانیاری لە ژمارەکەدا.CêIT

Other numbering schemesشێوازەکانی تری ژمارەدانان

Version numbers in mobile appsژمارەی وەشان لە ئەپەکانی مۆبایلدا

An Android app carries two numbers. versionName is the text users see, such as "1.0.1". versionCode is a whole number users never see. It must grow with every upload: Android will not install a lower versionCode over a higher one, Google Play rejects a versionCode you have already used, and the largest allowed value is 2,100,000,000.

Android دوو ژمارە هەڵدەگرێت. versionName ئەو دەقەیە کە دەیبینن، وەک ⁦"1.0.1"⁩. versionCode کە هەرگیز نایبینن. دەبێت لەگەڵ هەر زیاد بێت: Android versionCodeـێکی نزمتر لە سەر بەرزترێک دانامەزرێنێت، Google Play versionCodeـێک کە پێشتر بەکارت هێناوە ڕەت دەکاتەوە و گەورەترین بەهای ڕێگەپێدراو ⁦2,100,000,000⁩ـە.

Flutter writes both in one line of pubspec.yaml (the project file): version: 1.0.1+2. The part before + becomes versionName; the number after it is the build number and becomes versionCode. You can also set them when building: flutter build appbundle --build-name=1.0.1 --build-number=2.

Flutter هەردووکیان لە یەک دێڕی pubspec.yamlـدا دەنووسێت (فایلی پڕۆژەکە): version: 1.0.1+2. بەشی پێش + دەبێت بە versionName؛ ژمارەکەی دوای ئەوە ـە و دەبێت بە versionCode. دەتوانیت لە کاتی دیاریشیان بکەیت: flutter build appbundle --build-name=1.0.1 --build-number=2.

The pubspec line version: 1.0.1+2. An arrow from 1.0.1 to versionName: the text users see in the store. An arrow from 2 to versionCode, the build number: a whole number that must grow with every upload. A note: in semver, +2 would be ignored; in Flutter it is compared.دێڕی pubspec: version: 1.0.1+2. تیرێک لە 1.0.1ـەوە بۆ versionName: ئەو دەقەی بەکارهێنەرەکان لە فرۆشگای ئەپدا دەیبینن. تیرێک لە 2ـەوە بۆ versionCode، ژمارەی بیلد: ژمارەیەکی تەواو کە دەبێت لەگەڵ هەر هەڵبارکردنێک زیاد بێت. تێبینییەک: لە semverـدا +2 پشتگوێ دەخرا؛ لە Flutterـدا بەراورد دەکرێت.
One line, two numbers.یەک دێڕ، دوو ژمارە.CêIT

Why package managers care about semverبۆچی بەڕێوەبەرەکانی پاکێج گرنگی بە semver دەدەن

Your project depends on other people's packages, and they release new versions too. A version constraint says which versions you accept. Because of semver, a constraint can safely say “newer versions with the same MAJOR are fine”:

پڕۆژەکەت پشت بە خەڵکی تر دەبەستێت و ئەوانیش نوێ بڵاو دەکەنەوە. دەڵێت کام وەردەگریت. بەهۆی semverـەوە دەتوانێت بە دڵنیاییەوە بڵێت « نوێتر بە هەمان MAJOR باشن»:

  • ^1.2.3 (Dart's pub, npm): at least 1.2.3 and below 2.0.0. Below 1.0 the caret stops earlier: ^0.20.3 stops before 0.21.0. The full table is in Dependencies and version constraints.
  • ~=1.4.5 (Python's pip, PEP 440): at least 1.4.5 and still 1.4.. ~=2.2 means at least 2.2 and still 2..
  • ^1.2.3 (pubـی Dart، npm): لانیکەم ⁦1.2.3⁩ و لە خوار ⁦2.0.0⁩. لە خوار ⁦1.0⁩ـەوە نیشانەی ^ زووتر دەوەستێت: ^0.20.3 پێش ⁦0.21.0⁩ دەوەستێت. خشتە تەواوەکە لە وابەستەییەکان و مەرجەکانی وەشانـدایە.
  • ~=1.4.5 (pipـی Python، ⁦PEP 440⁩): لانیکەم ⁦1.4.5⁩ و هێشتا ⁦1.4⁩.. ~=2.2 واتە لانیکەم ⁦2.2⁩ و هێشتا 2..

Ranges let fixes in, but two computers could still choose different versions on different days. A lock file (pubspec.lock, package-lock.json) records the exact version of every dependency that was installed, so every computer — and the build server — builds with the same ones. Dart's guide: commit the lock file of an app, not of a library.

مەوداکان ڕێگە بە چاککردنەوەکان دەدەن، بەڵام دوو کۆمپیوتەر هێشتا دەتوانن لە دوو ڕۆژی جیاوازدا جیاواز هەڵبژێرن. (pubspec.lock، package-lock.json) ڕێک هەموو ئەو دامەزراون تۆمار دەکات، بۆ ئەوەی هەموو کۆمپیوتەرێک — و — بە هەمان بکات. ڕێبەری Dart دەڵێت: بکە، نەک هی .

Two number lines. Top, ^1.2.3: versions 1.2.2, 1.2.3, 1.6.0, 1.9.9 and 2.0.0 are marked; the range from 1.2.3 up to just before 2.0.0 is shaded. Bottom, ~=1.4.5: versions 1.4.4, 1.4.5, 1.4.9 and 1.5.0; the range from 1.4.5 up to just before 1.5.0 is shaded. Beside them, a lock file pins one exact version: http 1.6.0.دوو هێڵی ژمارە. سەرەوە، ^1.2.3: وەشانەکان 1.2.2، 1.2.3، 1.6.0، 1.9.9 و 2.0.0 نیشان کراون؛ مەودای 1.2.3 تا ڕێک پێش 2.0.0 ڕەنگ کراوە. خوارەوە، ~=1.4.5: وەشانەکان 1.4.4، 1.4.5، 1.4.9 و 1.5.0؛ مەودای 1.4.5 تا ڕێک پێش 1.5.0 ڕەنگ کراوە. لە تەنیشتیانەوە فایلی قوفڵ یەک وەشانی ورد دەچەسپێنێت: http 1.6.0.
A constraint allows a range; a lock file pins one version. مەودایەک ڕێگە پێدەدات؛ یەک دەچەسپێنێت.CêIT

Builds: from source code to an artifactبیلد: لە کۆدی سەرچاوەوە بۆ بەرهەمی بیلد

A build puts the right versions of all the parts together into something that can run or be installed. A typical build runs the same steps every time: get the source code of one commit, check it (compile it, look for obvious errors), run the tests, and package it.

دروستی هەموو بەشەکان پێکەوە دەنێت بۆ شتێک کە کار بکات یان دابمەزرێت. ئاسایی هەموو جارێک هەمان هەنگاوەکان دەکات: یەک وەردەگرێت، دەیپشکنێت ( بەکار دەهێنێت، بەدوای هەڵەی ئاشکرادا دەگەڕێت)، تاقیکردنەوەکان جێبەجێ دەکات و دەیپێچێتەوە.

The result is a build artifact: the file you test, keep and give to users — an Android app bundle (.aab), a Windows .exe, a Java .jar, a Python .pyz. Each build gets a build number that only goes up, so everyone can say exactly which build they tested.

ئەنجامەکە ـە: ئەو تاقیی دەکەیتەوە، هەڵیدەگریت و دەیدەیت بە — app bundleـی Android (.aab)، .exeـی Windows، .jarـی Java، .pyzـی Python. هەر ژمارەیەک وەردەگرێت () کە تەنیا زیاد دەبێت، بۆ ئەوەی هەموو کەس بتوانێت ڕێک بڵێت کام تاقی کردەوە.

Teams build on a clean build server from a fresh copy of the repository, not on one developer's laptop, so “it works on my machine” cannot hide a missing file or a different library version. Running build and tests automatically on every push is continuous integration — see Continuous integration.

تیمەکان لەسەر پاک و لە کۆپییەکی نوێی دەکەن، نەک لەسەر لاپتۆپی یەک ، بۆ ئەوەی «لەسەر ئامێرەکەی من کار دەکات» نەتوانێت ون یان جیاوازی بشارێتەوە. جێبەجێکردنی خۆکاری و تاقیکردنەوەکان لەگەڵ هەر — بڕوانە پێکەوەبەستنی بەردەوام.

A build pipeline from left to right: source code (one Git commit), check (compile, look for errors), test (run the tests), package (zip it up), artifact (bazaar_cart-1.0.0.pyz). A stamp above says build #57. Examples of artifacts underneath: .aab for Android, .exe for Windows, .jar for Java, .pyz for Python.زنجیرەیەکی بیلد لە چەپەوە بۆ ڕاست: کۆدی سەرچاوە (یەک کۆمیتی Git)، پشکنین (کۆمپایلەر، گەڕان بەدوای هەڵەدا)، تاقیکردنەوە (جێبەجێکردنی تاقیکردنەوەکان)، پێچانەوە (کردنی بە زیپ)، بەرهەمی بیلد (bazaar_cart-1.0.0.pyz). مۆرێک لە سەرەوە دەڵێت بیلد #57. نموونەی بەرهەمەکانی بیلد لە خوارەوە: .aab بۆ Android، .exe بۆ Windows، .jar بۆ Java، .pyz بۆ Python.
The same steps every time, ending in an artifact with a build number.هەمان هەنگاوەکان هەموو جارێک، کە بە و کۆتایی دێت.CêIT

Builds: from source code to an artifactبیلد: لە کۆدی سەرچاوەوە بۆ بەرهەمی بیلد

Build Bazaar Cart 1.0.0 into one file⁦Bazaar Cart 1.0.0⁩ بکە بە یەک فایل

Python's standard library can turn a folder of code into one runnable file with zipapp. By 1.0.0, cart.py has a main() function that prints a sample order (made-up prices, in IQD). The build copies only the files that ship into build/app/, packs them, runs the result and looks inside:

ستانداردی Python دەتوانێت بە zipapp فۆڵدەرێکی کۆد بکات بە یەک کارپێکراو. لە ⁦1.0.0⁩ـدا cart.py main()ـی هەیە کە داواکارییەکی نموونە چاپ دەکات (نرخی دروستکراو، بە دینار). تەنیا ئەو دەنێردرێن کۆپی دەکات بۆ build/app/، دەیانپێچێتەوە، ئەنجامەکە جێبەجێ دەکات و سەیری ناوی دەکات:

Build, run and look inside the artifactبیلد، جێبەجێکردن و سەیرکردنی ناو بەرهەمی بیلدBASHType in a terminalلە تێرمیناڵدا بینووسە
mkdir -p build/app dist && cp prices.py cart.py storage.py build/app/
python3.13 -m zipapp build/app -m "cart:main" -p "/usr/bin/env python3" -o dist/bazaar_cart-1.0.0.pyz
python3.13 dist/bazaar_cart-1.0.0.pyz
python3.13 -m zipfile -l dist/bazaar_cart-1.0.0.pyz
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 1

Copy only the files that ship: no tests, no .git, no secrets.

تەنیا ئەو دەنێردرێن کۆپی بکە: نە تاقیکردنەوە، نە .git، نە نهێنی.

Lineدێڕی 2

-m writes a __main__.py that calls cart.main(); -p adds a first line so the file runs by itself on Mac and Linux; -o names the artifact with its version.

-m __main__.py دەنووسێت کە بانگی cart.main() دەکات؛ -p دێڕێکی یەکەم زیاد دەکات بۆ ئەوەی لەسەر Mac و Linux بە تەنیا کار بکات؛ -o ناوی بە دادەنێت.

Lineدێڕی 3

Run the artifact. In the output, 350 g of sumac shows 2,750 IQD — rule R1 says round up, so it should be 3,000.

جێبەجێ بکە. لە دەرئەنجامەکەدا ⁦350⁩ گرام سماق ⁦2,750⁩ دینار پیشان دەدات — یاسای ⁦R1⁩ دەڵێت بەرزی بکەرەوە، بۆیە دەبێت ⁦3,000⁩ بێت.

Lineدێڕی 4

List the zip: the three modules plus the __main__.py that -m wrote.

ناوەڕۆکی زیپەکە لیست بکە: سێ لەگەڵ ئەو __main__.pyـیەی کە -m نووسیویەتی.

Look at the sumac line: Bazaar Cart 1.0.0 was released with a rounding bug. A day before the release Karwan had “simplified” round_up_250() to amount // 250 * 250, which rounds down. The fix is a PATCH, 1.0.1, and a new build of 1.0.1 shows 3,000 IQD for the sumac and 18,500 IQD to pay. How tests catch such bugs is in Every bug gets a test. In the course project you build and release 1.0.0 again, this time with tests that stop this bug.

سەیری دێڕی سماقەکە بکە: ⁦Bazaar Cart 1.0.0⁩ بە بەرزکردنەوەی نرخەوە بڵاو کرایەوە. ڕۆژێک پێش کاروان round_up_250()ـی «سادە کردبووەوە» بۆ amount // 250 * 250، کە نرخەکە بەرەو خوارەوە دەبات. چاککردنەوەکە ، ⁦1.0.1⁩ و نوێی ⁦1.0.1⁩ بۆ سماقەکە ⁦3,000⁩ دینار و بۆ پارەدان ⁦18,500⁩ دینار پیشان دەدات. تاقیکردنەوەکان چۆن ئەم جۆرە دەگرن لە هەر باگێک تاقیکردنەوەیەک وەردەگرێتـدایە. لە پڕۆژەی خولەکە جارێکی تر ⁦1.0.0⁩ دروست دەکەیت و بڵاوی دەکەیتەوە، ئەم جارە لەگەڵ تاقیکردنەوەی وا کە ڕێگە لەم دەگرن.

The artifact bazaar_cart-1.0.0.pyz drawn as an open zip box. Its first line is #!/usr/bin/env python3, so Mac and Linux can run it directly. Inside: __main__.py, which calls cart.main(), and the modules cart.py (__version__ = 1.0.0 and main()), prices.py (rules R1, R2, R4) and storage.py (SQLite).بەرهەمی بیلدەکە bazaar_cart-1.0.0.pyz وەک سندوقێکی زیپی کراوە کێشراوە. یەکەم دێڕی #!/usr/bin/env python3ـە، بۆیە Mac و Linux دەتوانن ڕاستەوخۆ جێبەجێی بکەن. لە ناویدا: __main__.py، کە بانگی cart.main() دەکات و مۆدیوڵەکان cart.py (__version__ = 1.0.0 و main())، prices.py (یاساکانی R1، R2، R4) و storage.py (SQLite).
Inside the artifact: a start line, a __main__.py and the code.ناو : دێڕی دەستپێک، ⁦__main__.py⁩ و کۆدەکە.CêIT

Builds: from source code to an artifactبیلد: لە کۆدی سەرچاوەوە بۆ بەرهەمی بیلد

Debug builds and release buildsبیلدی پشکنین و بیلدی بڵاوکردنەوە

Many tools make two kinds of build. A debug build keeps extra checks and helpers for developers; a release build is optimised for users. Flutter's three modes are explained in Debug, profile and release mode. Python has a small version of the same idea: python -O removes every assert statement.

زۆر ئامراز دوو جۆر دروست دەکەن. debug پشکنین و یارمەتیدەری زیادە بۆ دەهێڵێتەوە؛ release بۆ باشتر کراوە. سێ دۆخەکەی Flutter لە دۆخی debug، profile و release ڕوون کراونەتەوە. Python وەشانێکی بچووکی هەمان بیرۆکەی هەیە: python -O هەموو دەستەواژەیەکی assert لادەبات.

Here is Karwan's buggy delivery.py from the requirements lesson, run both ways:

ئەمە delivery.pyـەکەی کاروانە کە تێدایە، لە وانەی پێداویستییەکان، بە هەردوو شێوە جێبەجێ کراوە:

The same bug, with and without -Oهەمان باگ، بە -O و بەبێ -OBASHType in a terminalلە تێرمیناڵدا بینووسە
python3.13 delivery.py
python3.13 -O delivery.py

With -O the checks are gone and the wrong fee passes silently. So assert is for checking your own assumptions while you develop and test — rules that must always hold, such as R2's 100 to 10,000 g, need a real if … raise ValueError.

بە -O پشکنینەکان نامێنن و کرێیە هەڵەکە بە بێدەنگی تێدەپەڕێت. بۆیە assert بۆ پشکنینی گریمانەکانی خۆتە لە کاتی گەشەپێدان و تاقیکردنەوەدا — ئەو یاسایانەی دەبێت هەمیشە جێبەجێ بن، وەک ⁦100⁩ تا ⁦10,000⁩ گرامی ⁦R2⁩، پێویستیان بە if … raise ValueErrorـی ڕاستەقینەیە.

Two build boxes side by side. Debug build: for developers, extra checks on, asserts run, hot reload in Flutter, bigger and slower. Release build: for users, optimised and smaller, debugging helpers removed; in Python with -O the asserts are removed too. A warning under the release box: never rely on assert for rules that must always hold.دوو چوارگۆشەی بیلد لە تەنیشت یەکتر. بیلدی debug: بۆ بەرنامەسازەکان، پشکنینی زیادە کار دەکەن، assertـەکان جێبەجێ دەبن، بارکردنەوەی گەرم لە Flutterـدا، گەورەتر و خاوتر. بیلدی release: بۆ بەکارهێنەرەکان، باشترکراو و بچووکتر، یارمەتیدەرەکانی کرمەکوژی لابراون؛ لە Pythonـدا بە -O assertـەکانیش لادەبرێن. ئاگادارییەک لە ژێر چوارگۆشەی release: هەرگیز پشت بە assert مەبەستە بۆ ئەو یاسایانەی دەبێت هەمیشە جێبەجێ بن.
Debug for developers, release for users.debug بۆ ، release بۆ .CêIT

Releases and Git tagsوەشانە بڵاوکراوەکان و تاگەکانی Git

A release must point to the exact code it was built from. A Git tag gives one commit a permanent name. You met a quick, lightweight tag in Branches and merging; for releases Pro Git recommends annotated tags (-a), which also store who tagged, when, and a message. Tag names usually start with v, but the version itself is 1.0.0.

دەبێت ئاماژە بە ڕێک ئەو کۆدە بکات کە لێیەوە کراوە. ناوێکی هەمیشەیی دەدات بە یەک . تاگێکی خێرا و سووکـت لە لق و بەیەککردنـدا بینی؛ بۆ ، Pro Git پێشنیاری تاگی ڕوونکراوە (annotated، -a) دەکات کە هەروەها تۆمار دەکات کێ و کەی تاگی کردووە لەگەڵ پەیامێک. ناوی زۆرجار بە v دەست پێدەکەن، بەڵام خودی 1.0.0ـە.

Tag the release commitتاگکردنی کۆمیتی وەشانی بڵاوکراوەBASHType in a terminalلە تێرمیناڵدا بینووسە
git tag -a v1.0.0 -m "Bazaar Cart 1.0.0: first release"
git tag
git show --no-patch v1.0.0
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 1

-a makes an annotated tag; -m is its message.

-a تاگێکی ڕوونکراوە دروست دەکات؛ -m پەیامەکەیەتی.

Lineدێڕی 3

git show prints the tag's own information (who, when, why), then the commit it points to — the code of release 1.0.0.

git show سەرەتا زانیاریی خودی (کێ، کەی، بۆچی) چاپ دەکات، دواتر ئەو ئاماژەی پێدەکات — کۆدی ⁦1.0.0⁩.

A row of six commits from left to right: v0.1.0 line price, v0.2.0 delivery fee, v0.3.0 SQLite storage, an untagged commit that simplified round_up_250 (the one that brought the bug), v1.0.0 prepare 1.0.0, and v1.0.1 round up again. The main branch and HEAD point to the last commit.ڕیزێک لە شەش کۆمیت لە چەپەوە بۆ ڕاست: v0.1.0 نرخی دێڕ، v0.2.0 کرێی گەیاندن، v0.3.0 هەڵگرتن لە SQLite، کۆمیتێکی بێ تاگ کە round_up_250ـی سادە کردەوە (باگەکەی هێنا)، v1.0.0 ئامادەکردنی 1.0.0 و v1.0.1 دووپاتە بەرزکردنەوە. لقی main و HEAD ئاماژە بە دوایین کۆمیت دەکەن.
Each release is a tag on one commit.هەر لەسەر یەک .CêIT

Releases and Git tagsوەشانە بڵاوکراوەکان و تاگەکانی Git

Between releases, and sharing tagsلە نێوان وەشانە بڵاوکراوەکاندا و هاوبەشکردنی تاگەکانی Git

Two days later Shilan commits the rounding fix. git describe names any commit from the nearest tag: v1.0.0-1-g216e807 means one commit after v1.0.0, at commit 216e807. Build numbers and bug reports often use such names. After the team tags 1.0.1, the log reads like the version story:

دوو ڕۆژ دواتر شیلان چاککردنەوەی بەرزکردنەوەکە دەکات. git describe هەر لە نزیکترین ناو دەنێت: v1.0.0-1-g216e807 واتە یەک دوای ⁦v1.0.0⁩، لە ⁦216e807⁩. و ڕاپۆرتی زۆرجار ناوی لەم جۆرە بەکار دەهێنن. دوای ئەوەی تیمەکە ⁦1.0.1⁩ تاگ دەکات، وەک چیرۆکی دەخوێندرێنەوە:

Describe, tag and read the logdescribe، تاگ و خوێندنەوەی logBASHType in a terminalلە تێرمیناڵدا بینووسە
git commit -am "Round line prices up again (R1)"
git describe
git tag -a v1.0.1 -m "Bazaar Cart 1.0.1: rounding fix"
git describe
git log --oneline --decorate

Tags do not travel with a normal git push: after pushing main, the team's shared repository (remotes and pushing) still lists no tags. Push them by name:

لەگەڵ git pushـی ئاسایی ناڕۆن: دوای main، هاوبەشی تیمەکە (کۆگاکانی کۆدی دوور و پوش) هێشتا هیچ تاگێک پیشان نادات. بە ناو بکە:

Push the release tagsپوشی تاگەکانی GitBASHType in a terminalلە تێرمیناڵدا بینووسە
git push -q origin main
git ls-remote --tags origin
git push origin v1.0.0 v1.0.1

Releases and Git tagsوەشانە بڵاوکراوەکان و تاگەکانی Git

A changelog for peopleتۆماری گۆڕانکارییەکان بۆ خەڵک

A changelog lists the notable changes of every version for people (Keep a Changelog 1.1.0): the newest version first, dates as YYYY-MM-DD, an Unreleased section on top for what is coming, and changes grouped as Added, Changed, Deprecated, Removed, Fixed and Security. It is not a copy of git log: commit messages are for developers; the changelog tells users what changed for them.

گۆڕانکارییە گرنگەکانی هەموو بۆ خەڵک ڕیز دەکات ⁦(Keep a Changelog 1.1.0)⁩: نوێترین لە سەرەوە، ڕێکەوت بە شێوەی ⁦YYYY-MM-DD⁩، بەشێکی Unreleased لە سەرەوە بۆ ئەوەی دێت و گۆڕانکارییەکان بە گرووپی Added، Changed، Deprecated، Removed، Fixed و Security. کۆپیی git log نییە: پەیامی بۆ ؛ بە دەڵێت چی بۆ ئەوان گۆڕاوە.

Bazaar Cart's CHANGELOG.md while 1.1.0 is being builtCHANGELOG.mdـی Bazaar Cart لە کاتێکدا ⁦1.1.0⁩ دروست دەکرێتCHANGELOG.mdTEXT
# Changelog

All notable changes to Bazaar Cart are written in this file.
Bazaar Cart follows Semantic Versioning.

## [Unreleased]

### Added

- 5 % off goods totals of 100,000 IQD or more (R5).

## [1.0.1] - 2026-11-09

### Fixed

- Line prices are rounded up to the next 250 IQD again (R1).
  1.0.0 rounded some down: 350 g of sumac cost 2,750 instead of 3,000.

## [1.0.0] - 2026-11-07

### Added

- Order lines priced per kg and rounded up to 250 IQD (R1, R2).
- Never sell more than the stock (R3).
- Delivery inside Sulaimani: 3,000 IQD, free from 50,000 IQD (R4).
- Products stored in an SQLite database.

The “What's new” text in an app store (how an app reaches the store) is a short, friendly version of the same list. Fuller release notes also name known problems and what the software needs to run.

دەقی «⁦What's new⁩» لە (ئەپێک چۆن دەگاتە فرۆشگاکە) وەشانێکی کورت و دۆستانەی هەمان لیستە. تێبینییە تەواوەکانی کێشە ناسراوەکان و ئەوەی بۆ کارکردن پێویستیەتیش دەڵێن.

Releases and Git tagsوەشانە بڵاوکراوەکان و تاگەکانی Git

Continuous delivery and continuous deploymentگەیاندنی بەردەوام و خستنەکاری بەردەوام

Once building, testing and packaging are automatic, a team can keep its software always ready to release. In continuous delivery (Martin Fowler), every change that passes the pipeline could go to production, and a person decides when — with one button. Continuous deployment goes one step further: every change that passes all the checks reaches users automatically.

کاتێک ، تاقیکردنەوە و پێچانەوە خۆکار بن، تیمێک دەتوانێت هەمیشە ئامادەی بڵاوکردنەوە بهێڵێتەوە. لە ـدا (مارتن فاولەر)، هەر گۆڕانکارییەک کە لە زنجیرەکە دەردەچێت دەتوانێت بڕوات بۆ بەکارهێنانی ڕاستەقینە و کەسێک بڕیار دەدات کەی — بە یەک . هەنگاوێک زیاتر دەڕوات: هەر گۆڕانکارییەک کە لە هەموو پشکنینەکان دەردەچێت خۆکارانە دەگاتە .

Bazaar Cart uses continuous delivery: Soran does not want a new version on a busy Thursday evening, so Aram presses the button on Saturday morning. Apps on phones also pass the store's checks after upload, so they never reach every phone the same minute.

Bazaar Cart بەکار دەهێنێت: سۆران نوێ لە ئێوارەیەکی قەرەباڵغی پێنجشەممەدا ناوێت، بۆیە ئارام بەیانیی شەممە دادەگرێت. مۆبایلیش دوای بە پشکنینەکانی تێدەپەڕن، بۆیە هەرگیز لە هەمان خولەکدا ناگەنە هەموو مۆبایلێک.

Two pipelines. Both start with commit, build, test and package. Continuous delivery: the artifact waits at a release button that a person presses, then users get it. Continuous deployment: no button; every change that passes goes straight to users.دوو زنجیرە. هەردووکیان بە کۆمیت، بیلد، تاقیکردنەوە و پێچانەوە دەست پێدەکەن. گەیاندنی بەردەوام: بەرهەمی بیلد لای دوگمەیەکی بڵاوکردنەوە چاوەڕێ دەکات کە کەسێک دایدەگرێت، دواتر بەکارهێنەرەکان وەریدەگرن. خستنەکاری بەردەوام: هیچ دوگمەیەک نییە؛ هەر گۆڕانکارییەک کە دەردەچێت ڕاستەوخۆ دەچێت بۆ بەکارهێنەرەکان.
Delivery: ready, a person releases. Deployment: released automatically.: ئامادەیە، کەسێک بڵاوی دەکاتەوە. : خۆکارانە بڵاو دەبێتەوە.CêIT

Common mistakesهەڵە باوەکان

A tag name is not a versionناوی تاگی Git وەشان نییەtag_check.pyPYTHONType in a terminalلە تێرمیناڵدا بینووسە
from semver import semver_key

tag = "v1.0.0"                 # a Git tag name
print(semver_key(tag))
Explain the codeڕوونکردنەوەی کۆدەکە
Lineدێڕی 3

Fix: semver_key(tag.removeprefix("v")) gives (1, 0, 0, (1,)).

چارەسەر: semver_key(tag.removeprefix("v")) دەدات (1, 0, 0, (1,)).

Exercisesڕاهێنانەکان

ExerciseڕاهێنانWhich number for these six changes?کام ژمارە بۆ ئەم شەش گۆڕانکارییە؟

Bazaar Cart is at 1.1.0. For each change on its own, write the next version: (a) the honey price was shown per 100 g by mistake — fixed; (b) a new function favourites(); (c) the old function total(), which the website still calls, is removed; (d) a faster database query that gives the same results; (e) place_order(user_id) is marked deprecated and place_order(customer) is added; (f) a library Bazaar Cart uses is updated to fix a security bug, and Bazaar Cart's own API does not change.

Bazaar Cart لە ⁦1.1.0⁩ـدایە. بۆ هەر گۆڕانکارییەک بە جیا، داهاتوو بنووسە: ⁦(a)⁩ نرخی هەنگوین بە هەڵە بۆ ⁦100⁩ گرام پیشان دەدرا — چاک کرا؛ ⁦(b)⁩ نوێی favourites()؛ ⁦(c)⁩ کۆنەکەی total()، کە ماڵپەڕەکە هێشتا بانگی دەکات، لادەبرێت؛ ⁦(d)⁩ پرسیارێکی خێراتری کە هەمان ئەنجام دەدات؛ ⁦(e)⁩ place_order(user_id) وەک نیشان دەکرێت و place_order(customer) زیاد دەکرێت؛ ⁦(f)⁩ کە Bazaar Cart بەکاری دەهێنێت بۆ چاککردنی نوێ دەکرێتەوە و خودی Bazaar Cart ناگۆڕێت.

Show answerوەڵامەکە پیشان بدە
  • (a) 1.1.1 — a bug fix.
  • (b) 1.2.0 — a new feature.
  • (c) 2.0.0 — removing a function others call is breaking.
  • (d) 1.1.1 — nothing changes for callers.
  • (e) 1.2.0 — a deprecation and an addition are MINOR.
  • (f) 1.1.1 — semver's FAQ: a dependency update that fixes a bug, with no API change, is a patch.
  • ⁦(a) 1.1.1⁩ — چاککردنەوەی .
  • ⁦(b) 1.2.0⁩ — تایبەتمەندیی نوێ.
  • ⁦(c) 2.0.0⁩ — لابردنی کە ئەوانی تر بانگی دەکەن شکێنەرە.
  • ⁦(d) 1.1.1⁩ — هیچ شتێک بۆ بانگکەران ناگۆڕێت.
  • ⁦(e) 1.2.0⁩ — نیشانکردنی و زیادکردن MINORـن.
  • ⁦(f) 1.1.1⁩ — پرسیارە باوەکانی semver: کە چاک دەکات بێ گۆڕینی ، پینەیە.
ExerciseڕاهێنانPut them in orderڕیزیان بکە

Sort from oldest to newest: 2.0.0-rc.1, 1.10.0, 2.0.0, 1.9.3, 2.0.0-beta, 1.10.0+build.5. Which two have the same precedence?

لە کۆنترینەوە بۆ نوێترین ڕیزیان بکە: ⁦2.0.0-rc.1⁩، ⁦1.10.0⁩، ⁦2.0.0⁩، ⁦1.9.3⁩، ⁦2.0.0-beta⁩، ⁦1.10.0+build.5⁩. کام دووانیان هەمان پێشینەیییان هەیە؟

Show answerوەڵامەکە پیشان بدە
Answer (checked with semver.py)وەڵام (بە ⁦semver.py⁩ پشکنراوە)TEXT
1.9.3 < 1.10.0 = 1.10.0+build.5 < 2.0.0-beta < 2.0.0-rc.1 < 2.0.0

1.10.0 and 1.10.0+build.5 have the same precedence, because build metadata is ignored. "beta" comes before "rc" in ASCII order.

⁦1.10.0⁩ و ⁦1.10.0+build.5⁩ هەمان پێشینەیییان هەیە، چونکە زانیاریی پشتگوێ دەخرێت. «beta» بە ڕیزی ASCII پێش «rc» دێت.

ExerciseڕاهێنانA Flutter app, two releasesئەپێکی Flutter، دوو وەشانی بڵاوکراوە

Hana's Hawler Ride app has version: 1.4.2+17 in pubspec.yaml. Write the line for (1) a bug-fix release, then (2) a release with a new feature after it.

Hawler Rideـی هانا لە pubspec.yamlـدا version: 1.4.2+17ـی هەیە. دێڕەکە بنووسە بۆ ⁦(1)⁩ چاککردنەوە، دواتر ⁦(2)⁩ بە تایبەتمەندییەکی نوێ دوای ئەوە.

Show answerوەڵامەکە پیشان بدە
AnswerوەڵامYAML
version: 1.4.3+18   # (1) PATCH up, build number up
version: 1.5.0+19   # (2) MINOR up, PATCH reset, build number up

The build number never goes back, even when MINOR or MAJOR resets other numbers.

هەرگیز ناگەڕێتەوە دواوە، تەنانەت کاتێک MINOR یان MAJOR ژمارەکانی تر سفر دەکاتەوە.

ExerciseڕاهێنانTime for 1.0.0?کاتی ⁦1.0.0⁩ـە؟

Lana's timetable app (0.8.0) is used every day by 300 students, and two other school apps read its timetable through its API. Should Lana release 1.0.0? Explain in two sentences.

خشتەی لانا ⁦(0.8.0)⁩ هەموو ڕۆژێک ⁦300⁩ قوتابی بەکاری دەهێنن و دوو تری قوتابخانە لە ڕێگەی خشتەکەی دەخوێننەوە. ئایا لانا دەبێت ⁦1.0.0⁩ بڵاو بکاتەوە؟ بە دوو ڕستە ڕوونی بکەرەوە.

Show answerوەڵامەکە پیشان بدە

Yes. The app is used in production and other programs depend on its API, so semver says it should already be 1.0.0; from then on a breaking change needs 2.0.0, which protects the two other apps.

بەڵێ. بە ڕاستی بەکار دەهێنرێت و تر پشت بە دەبەستن، بۆیە semver دەڵێت دەبوو پێشتر ⁦1.0.0⁩ بووایە؛ لەوە بەدواوە پێویستی بە ⁦2.0.0⁩ دەبێت، کە دوو تر دەپارێزێت.

ExerciseڕاهێنانWrite the 1.1.0 entryبەشی ⁦1.1.0⁩ بنووسە

Bazaar Cart 1.1.0 is released on 2026-11-20 with the R5 discount. Write its CHANGELOG entry and say what happens to the Unreleased section.

⁦Bazaar Cart 1.1.0⁩ لە ⁦2026-11-20⁩ لەگەڵ داشکانی ⁦R5⁩ بڵاو دەکرێتەوە. بەشەکەی لە بنووسە و بڵێ چی بە بەشی Unreleased دەکرێت.

Show answerوەڵامەکە پیشان بدە
AnswerوەڵامTEXT
## [Unreleased]

## [1.1.0] - 2026-11-20

### Added

- 5 % off goods totals of 100,000 IQD or more,
  rounded up to 250 IQD (R5).

The entry moves from Unreleased into the new 1.1.0 section, and Unreleased starts empty again.

بەشەکە لە Unreleasedـەوە دەچێتە بەشی نوێی ⁦1.1.0⁩ و Unreleased دیسان بە بەتاڵی دەست پێدەکاتەوە.

ExerciseڕاهێنانTag and share 1.1.0تاگکردن و هاوبەشکردنی ⁦1.1.0⁩

Write the Git commands to tag the current commit as release 1.1.0 with a message, send the tag to origin, and check the name of the current commit.

فەرمانەکانی Git بنووسە بۆ تاگکردنی ئێستا وەک ⁦1.1.0⁩ لەگەڵ پەیامێک، ناردنی بۆ origin و پشکنینی ناوی ئێستا.

Show answerوەڵامەکە پیشان بدە
AnswerوەڵامBASH
git tag -a v1.1.0 -m "Bazaar Cart 1.1.0: 5 % discount (R5)"
git push origin v1.1.0
git describe            # prints v1.1.0 on the tagged commit

Summaryپوختە

  • Version = a numbered state; build = turning source into a runnable artifact (with a build number); release = a version given to people outside the team.
  • Semver 2.0.0: MAJOR for breaking changes, MINOR for compatible features and deprecations, PATCH for fixes; the number that goes up resets those to its right; released contents never change.
  • 0.y.z = anything may change; 1.0.0 defines the public API — release it when people depend on it. It does not mean bug-free.
  • Pre-releases (-alpha, -beta.2, -rc.1) rank below the release; build metadata (+57) is ignored. Compare versions as numbers, never as text.
  • Other schemes: CalVer (Ubuntu 26.04), PEP 440 (1.0.0rc1), Java LTS; Android's versionName + versionCode, Flutter's version: 1.0.1+2 (the +2 is the build number).
  • Constraints (^1.2.3, ~=1.4.5) accept compatible updates; a lock file pins exact versions.
  • Release with an annotated tag, push the tag, keep a changelog for people; continuous delivery keeps every change ready, continuous deployment ships it automatically.
  • = دۆخێکی ژمارەدار؛ = گۆڕینی بۆ کارپێکراو (بە )؛ = کە دەدرێت بە خەڵکی دەرەوەی تیم.
  • ⁦semver 2.0.0⁩: MAJOR بۆ ، MINOR بۆ تایبەتمەندیی گونجاو و ، PATCH بۆ چاککردنەوە؛ ئەو ژمارەیەی زیاد دەبێت ژمارەکانی لای ڕاستی سفر دەکاتەوە؛ ناوەڕۆکی بڵاوکراوە هەرگیز ناگۆڕێت.
  • ⁦0.y.z⁩ = هەر شتێک لەوانەیە بگۆڕێت؛ ⁦1.0.0⁩ گشتی دیاری دەکات — بڵاوی بکەرەوە کاتێک خەڵک پشتی پێ دەبەستن. واتای بێ نییە.
  • (-alpha، -beta.2، -rc.1) لە خوار ؛ زانیاریی (+57) پشتگوێ دەخرێت. وەک ژمارە بەراورد بکە، هەرگیز وەک دەق.
  • شێوازەکانی تر: CalVer ⁦(Ubuntu 26.04)⁩، ⁦PEP 440⁩ (1.0.0rc1)، LTSـی Java؛ ⁦versionName + versionCode⁩ـی Android، version: 1.0.1+2ـی Flutter (+2 ).
  • (^1.2.3، ~=1.4.5) گونجاو وەردەگرن؛ ورد دەچەسپێنێت.
  • بە تاگی ڕوونکراوە بڵاو بکەرەوە، بکە، بۆ خەڵک بنووسە؛ هەموو گۆڕانکارییەک ئامادە دەهێڵێتەوە، خۆکارانە دەینێرێت.

Next: make the computer check every build for you — Automated testing.

داهاتوو: وا بکە کۆمپیوتەر هەموو بۆت بپشکنێت — تاقیکردنەوەی خۆکار.

Lesson complete!وانەکە تەواو بوو!

Well done. Review the key terms, then go on to the next lesson.دەستخۆش. سەیرێکی زاراوە سەرەکییەکان بکەرەوە، پاشان بڕۆ بۆ وانەی داهاتوو.

Key termsزاراوە سەرەکییەکان

Next lessonوانەی داهاتوو

Automated Testing: Code That Checks Your Codeتاقیکردنەوەی خۆکار: کۆدێک کە کۆدەکەت دەپشکنێت

References and further readingسەرچاوەکان و خوێندنەوەی زیاتر

This lecture is a first edition. The Kurdish text and terminology are waiting for review by Kurdish IT teachers.ئەم وانەیە چاپی یەکەمە. دەقە کوردییەکە و زاراوەکانی چاوەڕێی پێداچوونەوەی مامۆستایانی کوردی بواری IT ن.

Appearanceڕووکار

Modeدۆخ
Styleشێواز
Coloursڕەنگەکان

Saved on this device only.تەنیا لەسەر ئەم ئامێرە پاشەکەوت دەکرێت.