Skip to content
academia.sh

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 describe gives 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.

Start typing to search.

↑↓ Esc navigate · open · close