Git'te etiketler: git tag ile sürümleri nasıl işaretlersiniz
git tag, belirli bir commit'e kalıcı bir ad verir; genellikle v1.2.0 gibi bir sürüm için. Açıklamalı etiket git tag -a v1.2.0 -m "mesaj" ile oluşturulur, etiketler sunucuya ayrıca gönderilir: git push origin v1.2.0 ya da git push --tags.
git tag, belirli bir commit'e verilen adlandırılmış bir işarettir. Branch'ten farklı olarak yeni commit'lerle birlikte ilerlemez: v1.2.0 bir yıl sonra da aynı kod anlık görüntüsünü gösterir. Bu yüzden etiketler sürümler için kullanılır ve CI/CD sistemleri çoğu zaman tam da bir etiketin oluşmasıyla derleme ve yayımlama işlemini başlatır.
Hafif ve açıklamalı etiketler
Git'te iki tür etiket vardır ve aralarındaki fark önemlidir.
| Hafif (lightweight) | Açıklamalı (annotated) | |
|---|---|---|
| Oluşturma | git tag v1.0.0 | git tag -a v1.0.0 -m "..." |
| Nedir | Yalnızca bir commit'e işaretçi | Git veritabanında ayrı bir nesne |
| Yazar, tarih, mesaj | Yok | Var |
| GPG/SSH imzası | Yok | Mümkün (-s) |
Varsayılan olarak git describe tarafından dikkate alınır | Hayır | Evet |
| Ne zaman kullanılır | Kişisel, geçici işaretler | Sürümler ve yayımlanan her şey |
Sürümler için açıklamalı etiket kullanın: kimin ve ne zaman yayımladığı kaydedilir ve imzalanabilir.
Etiket nasıl oluşturulur
Mevcut commit üzerinde
git tag -a v1.2.0 -m "Sürüm 1.2.0: rapor dışa aktarma, API zaman aşımı düzeltildi"
-m olmadan Git mesaj için bir editör açar; değişiklik listesini yazmak istiyorsanız bu kullanışlıdır.
Eski bir commit üzerinde
Sürüm çıkarırken etiketi koymayı unuttuysanız sorun değil; etiketi herhangi bir commit'e verebilirsiniz:
git log --oneline -5
# 7be41d0 feat: rapor dışa aktarma
# 1c02e8f fix: istek zaman aşımı
git tag -a v1.1.0 1c02e8f -m "Sürüm 1.1.0"
İmzalı etiket
git tag -s v1.2.0 -m "Sürüm 1.2.0"
git tag -v v1.2.0 # imzayı doğrula
Yapılandırılmış bir GPG anahtarı gerekir (ya da gpg.format=ssh ise SSH anahtarı). GitHub ve GitLab bu etiketleri doğrulanmış olarak gösterir.
Etiketleri nasıl görüntülersiniz
git tag # tüm etiketler, alfabetik
git tag -l "v1.*" # desenle
git tag -n # mesajın ilk satırıyla birlikte
git tag --sort=-v:refname # sürüme göre, yeniler üstte
git show v1.2.0 # etiketin ve commit'in bilgileri
git describe --tags # en yakın etiket: v1.2.0-3-g7be41d0
Sıralamaya dikkat edin: varsayılan sıralamada v1.10.0, v1.9.0'dan önce gelir, çünkü metinler karakter karakter karşılaştırılır. --sort=v:refname anahtarı sürüm numaralarını doğru sıralar.
git describe çıktısı şöyle okunur: v1.2.0 etiketinden sonra üç commit var ve mevcut commit 7be41d0 (g harfi git anlamına gelir). Sürümler arasındaki derlemelerde sürüm numarası kaynağı olarak kullanışlıdır.
Etiketi sunucuya nasıl gönderirsiniz
Sıradan git push etiketleri göndermez — «neden etiket GitHub'da yok» sorusunun en yaygın cevabı budur.
git push origin v1.2.0 # tek bir etiket
git push --tags # yerel tüm etiketler
git push --follow-tags # commit'ler + bunlara işaret eden açıklamalı etiketler
--follow-tags, --tags'ten daha güvenlidir: kendiniz için koyduğunuz rastgele hafif etiketleri göndermez. Varsayılan olarak açmak için: git config --global push.followTags true.
Sunucudaki etiketleri almak için git fetch --tags. Düz git fetch de indirilen commit'lere işaret eden etiketleri getirir.
Etiketi nasıl silersiniz veya taşırsınız
Silme
git tag -d v1.2.0 # yerelde
git push origin --delete v1.2.0 # sunucuda
# eski eşdeğeri: git push origin :refs/tags/v1.2.0
Etiketi başka bir commit'e taşıma
git tag -a -f v1.2.0 <yeni-hash> -m "Sürüm 1.2.0"
git push origin -f v1.2.0
Teknik olarak mümkündür, ama herkese açık projelerde yayımlanmış bir etiketi taşımayın. Etiketi zaten indirmiş olanlarda güncellenmez: Git, mevcut yerel etiketleri fetch sırasında --force olmadan üzerine yazmaz. Sonuçta farklı kişilerde «v1.2.0» farklı kod olur. Doğrusu v1.2.1 yayımlamaktır.
Bir sürüme hangi commit'ler girdi
Etiketleri, geçmişi okuyan tüm komutlarda aralık sınırı olarak kullanabilirsiniz:
git log v1.1.0..v1.2.0 --oneline # iki sürüm arasındaki commit'ler
git diff v1.1.0 v1.2.0 --stat # hangi dosyalar değişti
git tag --contains 1c02e8f # bu commit hangi sürümlerde var
git merge-base --is-ancestor 1c02e8f v1.2.0 && echo "sürümde var"
Son iki komut, destek ekiplerinin sık sorduğu soruyu yanıtlar: «Bu düzeltme kullanıcılara ulaştı mı?» Düzeltme yalnızca main'e girdiyse ve sürüm daha önce alındıysa, git tag --contains boş bir liste döndürür ve yeni bir etiket gerektiği anlaşılır.
Bir başka yöntem, belirli bir sürümün kaynak kodunu geçmiş olmadan indirmektir: git archive --format=zip -o app-1.2.0.zip v1.2.0. Müşteriye teslim edilecek arşivler ya da izole ortamda derleme için böyle oluşturulur.
Etiketteki sürüme nasıl geçersiniz
git switch --detach v1.1.0
# HEAD is now at 1c02e8f fix: istek zaman aşımı
detached HEAD durumuna geçersiniz: bakabilir ve derleyebilirsiniz, ama yeni commit'ler hiçbir branch'e ait olmaz. Eski bir sürümü düzeltmeniz gerekiyorsa etiketten bir branch oluşturun:
git switch -c hotfix/1.1.x v1.1.0
# düzeltmeler, commit
git tag -a v1.1.1 -m "Güvenlik düzeltmesi"
git push origin hotfix/1.1.x --follow-tags
SemVer ile sürüm numaralandırma
Etiket adları için en yaygın şema Semantic Versioning: MAJOR.MINOR.PATCH.
- MAJOR uyumsuz API değişikliklerinde artar:
1.4.2 → 2.0.0. - MINOR geriye uyumlu yeni işlevsellikte artar:
1.4.2 → 1.5.0. - PATCH hata düzeltmelerinde artar:
1.4.2 → 1.4.3. - Ön sürümler sonek ile işaretlenir:
2.0.0-beta.1,2.0.0-rc.1.
v öneki (v1.4.2) etiket adları için yaygın bir gelenektir; SemVer'in kendisi bunu zorunlu kılmaz. Önemli olan tek bir biçim seçip ona sadık kalmaktır; aksi halde son sürümü arayan betikler bozulur.
Sürüm sürecinde etiketler
Ekipte tipik süreç şöyledir:
- Değişiklikler main'e birleşir, testler yeşildir.
- CHANGELOG ve proje dosyalarındaki sürüm numarası güncellenir (proje bunları saklıyorsa).
- Açıklamalı etiket konur:
git tag -a v1.5.0 -m "Sürüm 1.5.0". git push origin main --follow-tags.- CI yeni etiketi görür, artefaktları derler ve yayımlar; GitHub ve GitLab etiketten bir Release sayfası oluşturur: açıklama ve dosyalarla birlikte.
Böylece üretimdeki her sürüm koda kesin olarak bağlanır: derleme adındaki etikete bakarsınız, git show ile neyin girdiğini görürsünüz. Sürüm notları için git log v1.4.0..v1.5.0 --oneline iki sürüm arasındaki değişiklikleri listeler.
Etiketlerden sürüm notu üretme
Commit mesajları anlamlıysa, etiketler geçmişi hazır bir değişiklik listesine dönüştürür. Son ve bir önceki sürümü elle aramadan bulabilirsiniz:
LAST=$(git describe --tags --abbrev=0)
PREV=$(git describe --tags --abbrev=0 "$LAST^")
git log "$PREV..$LAST" --no-merges --pretty=format:"- %s (%h)"
# - feat: rapor dışa aktarma (7be41d0)
# - fix: istek zaman aşımı (1c02e8f)
Ekip commit'lerini Conventional Commits kuralıyla yazıyorsa (feat:, fix:, feat!:), bir sonraki sürüm numarası otomatik hesaplanabilir: fix PATCH'i, feat MINOR'ü, ünlem işareti ya da BREAKING CHANGE MAJOR'ü artırır. Popüler otomatik sürüm araçları bu mantığa dayanır: etiketi kendileri koyar ve CHANGELOG'u kendileri yazar.
Etiketler ve CI/CD
Pipeline'lar genellikle iki olayı ayırt eder: bir branch'e push ve bir etiketin oluşması. Branch'e push'ta testler ve test ortamı derlemesi çalışır; etiket oluştuğunda yayımlama yapılır. GitHub Actions'ta bu şöyle görünür:
on:
push:
tags:
- "v*.*.*"
GitLab CI'de aynı rolü CI_COMMIT_TAG değişkeni ve rules: - if: $CI_COMMIT_TAG kuralı oynar. Pipeline içinde etiket adı Docker imajının ya da paketin sürüm numarası olur; bu yüzden etiket biçimi katı ve öngörülebilir olmalıdır.
Etiketleri taşımamanın bir başka nedeni de budur: pipeline 1.2.0 paketini bir kayda yayımladıysa, aynı numarayla yeniden yayımlamak genellikle yasaktır ve kullanıcılardaki 1.2.0 imajı eski kalır.
Etiket adlarında neler serbesttir
Etiket adı, branch adlarıyla aynı kurallara tabidir: boşluk yok, ~ ^ : ? * [ karakterleri yok, art arda iki nokta yok. Eğik çizgi serbesttir; bu yüzden monorepo'larda api/v1.2.0 ve web/v3.0.1 gibi etiketler görülür — her paket için ayrı bir sürüm dizisi. Adı önceden kontrol etmek için git check-ref-format "refs/tags/v1.2.0" kullanılabilir: hata varsa sıfırdan farklı bir kodla çıkar.
Etiketleri koruma
Ekip depolarında sürüm etiketlerini korumak iyi bir fikirdir: GitHub ve GitLab, belirli bir desene (örneğin v*) uyan etiketlerin oluşturulmasını, üzerine yazılmasını ve silinmesini yalnızca bakımcılarla sınırlayabilir. Böylece bir başkasının bilgisayarındaki yanlışlıkla çalıştırılan git push --tags plansız bir sürüm yayımlamaz, yanlış bir git push origin --delete de sürüm geçmişini silemez.
Sık yapılan hatalar
- Etiket sunucuda yok.
git push origin <etiket>ya da--follow-tagsunutulmuştur. - Etiketle branch aynı adı taşıyor. Git
refname is ambiguousuyarısı verir; etiketler içinvöneki kullanın ve adları ayırın. - Etiket commit edilmemiş durumda. Etiket commit'e konur, dosyalara değil: commit edilmemiş düzeltmeler sürüme girmez.
- Sürüm için hafif etiket. Yazar, tarih ve mesaj yoktur;
git describede varsayılan olarak onu görmez.
Kısaca
git tag geçmişte değişmez bir nokta işaretler: sürümler için git tag -a ile açıklamalı etiketler oluşturun, SemVer ile adlandırın ve sunucuya açıkça gönderin — git push origin <etiket> ya da --follow-tags. Yayımlanmış etiketleri taşımayın; yeni bir sürüm yayımlayın. Etiketler, rebase, stash ve cherry-pick ile birlikte Git kursunda uygulamalı olarak anlatılmaktadır.
Sık sorulan sorular
Etiket ile branch arasındaki fark nedir?
Branch her yeni commit'te ilerler; etiket ise sürekli aynı commit'i gösterir.
Aynı commit'e iki etiket koyabilir miyim?
Evet, bir commit'in etiket sayısında sınır yoktur; örneğin v2.0.0 ve latest-stable aynı anda olabilir.
Branch silindiğinde etiketler de silinir mi?
Hayır. Etiketler branch'lerden bağımsızdır; branch silinse de etiketli commit erişilebilir kalır.
Bir commit hangi sürüme girdi, nasıl anlarım?
git tag --contains <hash> komutunu çalıştırın; bu commit'in geçmişinde bulunduğu tüm etiketleri gösterir.
Bir betikte son etiketi nasıl alırım?
git describe --tags --abbrev=0 kullanın; hash eki olmadan en yakın etiketin adını yazar.
Bu konu “Sıfırdan Güvenilir Geliştiriciye Git” kursunda uygulamalı olarak ayrıntılı işleniyor.
Kursa git