Lesson 15 / 15
Tagging
Giving permanent names to specific points in history; the difference between a lightweight tag and a tag object, the fourth object type, locating position by tag, and semantic versioning.
Contents
Up to this point, points in history have been referred to by forty-character IDs or by
relative notation like HEAD~1. Neither is a permanent name: an ID cannot be kept in
mind, and relative notation points at a different commit as history grows.
A tag is a fixed name given to a specific commit. Its difference from branch tips is that it does not budge when a new commit is written: the branch advances, the tag stays.
Lightweight Tag
The plainest form binds a commit ID to a name:
git tag v1.0.0 498105a git tag -l
v1.0.0
cat .git/refs/tags/v1.0.0
498105a461806443b43bf3287f41a9fe045f7ef8
The file’s content is directly the commit ID. A lightweight tag creates no new object in the object database; it only writes a ref file.
git cat-file -t v1.0.0
commit
The name points at a commit. Who placed the tag, when, and why is recorded nowhere. This is insufficient for marking a published release.
git tag -d v1.0.0
Deleted tag 'v1.0.0' (was 498105a)
The Tag Object
git tag -a v1.0.0 -m "İlk kararlı sürüm: arama, harf duyarsızlığı, hata kodu" 498105a git cat-file -t v1.0.0
tag
The object type changed. An annotated tag is the last of the four object types introduced in the second topic, and it is written to the object database:
git cat-file -p v1.0.0
object 498105a461806443b43bf3287f41a9fe045f7ef8 type commit tag v1.0.0 tagger Deniz Kaya <[email protected]> 1710309600 +0300 İlk kararlı sürüm: arama, harf duyarsızlığı, hata kodu
There are five components: the ID and type of the pointed-at object, the tag name, the person who placed the tag together with the time, and the description text. The structure resembles a commit object — and it is named by the same rule:
git rev-parse v1.0.0
8fa8557633aff60f8bc5bce08050ea0c524d866f
This ID belongs to the tag object, not the commit. To reach the pointed-at commit, a type conversion is requested:
git rev-parse "v1.0.0^{commit}"
498105a461806443b43bf3287f41a9fe045f7ef8
Most commands perform this conversion on their own; the distinction shows up only when the object itself is asked for directly.
git show v1.0.0 --stat
tag v1.0.0 Tagger: Deniz Kaya <[email protected]> Date: Wed Mar 13 09:00:00 2024 +0300 İlk kararlı sürüm: arama, harf duyarsızlığı, hata kodu commit 498105a461806443b43bf3287f41a9fe045f7ef8 Author: Deniz Kaya <[email protected]> Date: Tue Mar 12 09:48:00 2024 +0300 Aramanın harf duyarsızlığını README'de belirt README.md | 2 ++ 1 file changed, 2 insertions(+)
The output shows the tag first, then the commit it points at.
| Criterion | Lightweight tag | Annotated tag |
|---|---|---|
| Creates an object | No | Yes |
| Records who and when | No | Yes |
| Description text | No | Yes |
| Use | Temporary, local marker | Published release |
Listing Tags
After the listing option is finished, a second release is tagged:
git tag -a v1.1.0 -m "Listeleme seçeneği (-l) eklendi" git tag -l
v1.0.0 v1.1.0
git tag -l "v1.0*"
v1.0.0
git tag -n
v1.0.0 İlk kararlı sürüm: arama, harf duyarsızlığı, hata kodu v1.1.0 Listeleme seçeneği (-l) eklendi
Tags also show up in the history list:
git log --oneline --decorate -n 5
396729b (HEAD -> main, tag: v1.1.0) README'de -l seçeneğini belgele 701fa37 Tüm terimleri listeleyen -l seçeneğini ekle 498105a (tag: v1.0.0) Aramanın harf duyarsızlığını README'de belirt a58791f Revert "Arama çıktısını yalnızca Türkçe sütuna indir" ad60f31 Arama çıktısını yalnızca Türkçe sütuna indir
All the refs can also be listed with a single command:
git for-each-ref refs/tags
8fa8557633aff60f8bc5bce08050ea0c524d866f tag refs/tags/v1.0.0 2054d80edbfbbb29b1da99ba01f3e121b7b50a39 tag refs/tags/v1.1.0
The second column gives the object type; for lightweight tags, this column would read
commit.
Locating Position by Tag
git describe
v1.1.0
When a new commit is written after the tag, the output changes:
git describe
v1.1.0-1-g2aff8c5
There are three parts: the nearest tag, the number of commits written since that tag,
and the current commit’s shortened ID. The g at the start of the ID marks the value as
a git object. When this string is embedded in an executable program’s version
information, it says exactly which commit the binary in hand was built from.
Semantic Versioning
A tag’s name is free; but there is a common scheme for marking releases: semantic versioning. A version number consists of three numbers separated by dots, and incrementing each number makes a promise:
| Part | When it increments | What it tells the user |
|---|---|---|
| Major | When backward compatibility breaks | Adaptation may be needed |
| Minor | When a compatible new capability is added | Existing use is not broken |
| Patch | When only a fix is made | Behavior is the same, a flaw was fixed |
In the example repository, v1.0.0 marked the first stable release, and v1.1.0
marked the addition of a backward-compatible capability: the -l option does not break
previous use, it only adds a new form of invocation. If the script’s exit codes had been
changed, the major version would have needed to increment.
The scheme’s value lies less in the number itself than in the promise it makes. The concept of backward compatibility was defined in the Programming Fundamentals course, in the context of language choice; a version number is a machine-readable declaration of that same concept.
The Limits of Tags
Tags can be moved, but they should not be. If a tag is shifted to another commit after being published, copies that already have that tag keep pointing at the old commit; the same name ends up naming two different pieces of content. The point a published tag points at is not changed; a new tag is placed instead, if one is needed.
Deletion carries the same problem. A tag deleted locally keeps standing in other copies of the repository.
Tags can also point at objects other than commits — a tag can be placed on a blob or a tree. In practice this is rarely used; a tag’s usual target is a commit.
Summary
- A tag is a fixed name given to a commit, one that does not get displaced by new commits.
- A lightweight tag is only a ref file; an annotated tag is a separate object storing who placed it and a description.
- The tag object is the fourth object type, and it is named by the same rule as the others.
git describegives the number of commits since the nearest tag and the current ID.- Semantic versioning promises backward compatibility with a three-number version.
- Published tags are not moved or deleted; a new tag is placed when needed.
Course Wrap-Up
A single repository was built across the course, and it reached its present state through eighteen commits:
git log --oneline --decorate
2aff8c5 (HEAD -> main) Bileşik terim örneği ekle 396729b (tag: v1.1.0) README'de -l seçeneğini belgele 701fa37 Tüm terimleri listeleyen -l seçeneğini ekle 498105a (tag: v1.0.0) Aramanın harf duyarsızlığını README'de belirt a58791f Revert "Arama çıktısını yalnızca Türkçe sütuna indir" ad60f31 Arama çıktısını yalnızca Türkçe sütuna indir 18600c5 README'ye kullanım bölümü ekle bfe57d3 Öbek ve dizi terimlerini ekle cb8f7ee Yerel notları izlemeden çıkar 7783378 Yerel notları ekle 9b23cc3 Üretilen dosyaları yoksayma listesine al ece664b Küme terimini ekle 2c883a7 Eşleşme bulunamadığında hata bildir 60e13bd Aramayı büyük/küçük harften bağımsız yap 43370ca Üç veri yapısı terimi ekle 3132c78 Biçim örneğindeki yazımı düzelt 546c174 Terim arama betiği ekle 13d31bf Terim listesini ve biçim belgesini ekle
This list shows the course’s structure: files being added, atomic commits, a mistake being committed and reverted, ignore rules being set up, and two releases being tagged.
The course’s real subject was not the commands but the model underneath them. Four object types — blob, tree, commit, tag — are named by content-addressed storage; commits build a directed acyclic graph through their parent links; the staging area accumulates the next snapshot to be added to that graph. Every command is a consequence of these three sentences. Why amending produces a new ID, why reverting does not disturb history, why the same content gives the same ID — the answer to all three is in the model.
One subject was deliberately left out across the course: history stayed a single chain
throughout. Yet the graph’s definition allowed branching, and --graph’s output coming
out as a single column was not a limitation — it was a property of this particular
repository.
The next course — Branching and Collaboration — multiplies that column. It takes up
the fact that a branch is nothing but a pointer, how two branches are merged, how
conflicts are resolved, and how history is synced with remote repositories. The model
built in this course holds there too: a branch is nothing but a file under refs/heads;
a merge is nothing but a commit with two parents.
To keep your progress and take notes, Log in
My notes
Log in to take notes.