Bagaimana perbedaan tag dengan cabang di Git? Yang mana yang harus saya gunakan, di sini?

616

Saya mengalami kesulitan memahami cara menggunakan tag versus cabang di.

Saya baru saja memindahkan versi kode kami saat ini dari untuk , dan sekarang saya akan mengerjakan subset dari kode itu untuk fitur tertentu. Beberapa pengembang lain akan mengerjakan ini juga, tetapi tidak semua pengembang di grup kami akan peduli dengan fitur ini. Haruskah saya membuat cabang atau tag? Dalam situasi apa saya harus menggunakan yang satu versus yang lain?

Bialecki
sumber
4
Karena pencarian web untuk menggunakan tag git membawa saya ke tautan itu terlebih dahulu, saya menambahkan bahwa ada jawaban (IMHO) yang lebih baik tentang tag di sini: stackoverflow.com/questions/35979642/…
Alexei Martianov

Jawaban:

520

Sebuah tag merupakan versi cabang tertentu pada saat dalam waktu. Sebuah cabang mewakili thread terpisah dari pembangunan yang dapat berjalan bersamaan dengan upaya pembangunan lainnya pada basis kode yang sama. Perubahan pada cabang akhirnya dapat digabungkan kembali ke cabang lain untuk menyatukannya.

Biasanya Anda akan tag versi tertentu sehingga Anda dapat menciptakan itu, misalnya, ini adalah versi kita dikirim ke XYZ Corp . Sebuah cabanglebih merupakan strategi untuk menyediakan pembaruan yang sedang berlangsung pada versi kode tertentu sambil terus melakukan pengembangan di atasnya. Anda akan membuat cabang dari versi yang dikirimkan, melanjutkan pengembangan di jalur utama, tetapi melakukan perbaikan bug ke cabang yang mewakili versi yang dikirimkan. Akhirnya, Anda akan menggabungkan perbaikan bug ini kembali ke jalur utama. Seringkali Anda akan menggunakan kedua percabangan dan penandaan bersama. Anda akan memiliki berbagai tag yang mungkin berlaku untuk jalur utama dan cabangnya yang menandai versi tertentu (misalnya yang dikirimkan ke pelanggan) di sepanjang setiap cabang yang mungkin ingin Anda buat ulang - untuk pengiriman, diagnosis bug, dll.

Ini sebenarnya lebih rumit dari ini - atau serumit yang Anda inginkan - tetapi contoh-contoh ini seharusnya memberi Anda gambaran tentang perbedaan.

tvanfosson
sumber
40
dalam kasus dia ingin menggunakan cabang, mungkin Anda juga harus mencatat ini dalam jawaban Anda;)
knittl
13
AFAIK, tag tidak unik per cabang. Jadi, Anda tidak dapat memberikan nama yang sama untuk komit yang berbeda di cabang terpisah.
MY
5
@MY Tentu bukan hal yang buruk, IMHO. Terutama dalam cara yang dijelaskan oleh tvanfosson, memiliki lebih dari satu tag dengan nama yang sama di cabang yang berbeda dapat menjadi sulit untuk dipelihara. Diberikan contoh, saya akan berpikir bahwa jika Anda dapat memiliki tag dengan nama yang sama di cabang yang berbeda, itu akan dengan cepat ditetapkan sebagai praktik yang buruk. Senang mengetahui bahwa Anda tidak bisa. Terima kasih SAYA!
Putar
28
Tag hanyalah alias untuk hash komit. Sama seperti Anda dapat checkout komit dengan git checkout 88c9f229fAnda dapat melakukan sesuatu seperti git checkout your_tagdan Anda akan checkout komit yang telah dihapus oleh tag.
jterm
6
@ jterm, bukankah cabang juga alias? Satu-satunya perbedaan adalah bahwa cabang-alias secara otomatis menunjuk sendiri ke komit terbaru dalam rantai.
Viktor Molokostov
529

Dari sudut pandang teoritis :

  • tag adalah nama simbolis untuk revisi yang diberikan . Mereka selalu menunjuk ke objek yang sama (biasanya: ke revisi yang sama); mereka tidak berubah.
  • cabang adalah nama simbolis untuk lini pengembangan . Komit baru dibuat di atas cabang. Penunjuk cabang secara alami bergerak maju, menunjuk ke komit yang lebih baru dan lebih baru.

Dari sudut pandang teknis :

  • tag berada di refs/tags/namespace, dan dapat menunjuk ke objek tag (tag bertanda GPG beranotasi dan opsional) atau langsung melakukan objek (tag ringan yang jarang digunakan untuk nama lokal), atau dalam kasus yang sangat jarang bahkan untuk objek pohon atau objek gumpalan (misalnya tanda tangan GPG ).
  • cabang berada di refs/heads/namespace, dan hanya bisa menunjuk ke objek komit . The HEADpointer harus mengacu ke cabang (referensi simbolik) atau langsung ke komit (KEPALA terpisah atau cabang yang tidak disebutkan namanya).
  • cabang pelacakan jarak jauh berada di refs/remotes/<remote>/namespace, dan ikuti cabang biasa di repositori jarak jauh <remote>.

Lihat juga halaman manual gitglossary :

cabang

"Cabang" adalah jalur pengembangan yang aktif. Komit terbaru pada cabang disebut sebagai ujung cabang itu. Ujung cabang direferensikan oleh kepala cabang, yang bergerak maju sebagai pengembangan tambahan dilakukan pada cabang. Repositori git tunggal dapat melacak sejumlah cabang yang berubah-ubah, tetapi pohon kerja Anda hanya dikaitkan dengan salah satu dari mereka (cabang "saat ini" atau "diperiksa"), dan HEAD menunjuk ke cabang itu.

menandai

Ref menunjuk ke tag atau melakukan objek. Berbeda dengan kepala, tag tidak diubah oleh komit. Tag (bukan objek tag) disimpan di $GIT_DIR/refs/tags/. [...] Tag biasanya digunakan untuk menandai titik tertentu dalam rantai leluhur komit.

objek tag

Objek yang berisi referensi yang menunjuk ke objek lain, yang bisa berisi pesan seperti objek komit. Itu juga bisa berisi tanda tangan (PGP), dalam hal ini disebut "objek tag bertanda".

Jakub Narębski
sumber
36
Pertanyaan: jika Anda memperlakukan cabang seperti tag (yaitu, Anda membuatnya, lalu tidak pernah memperbaruinya), apakah ada perbedaan nyata?
Steve Bennett
30
@SteveBennett benar-benar. Di sana berisi informasi yang berbeda (Anda dapat menandatangani tag, Anda dapat menambahkan deskripsi ke cabang). Anda dapat memindahkan cabang (jadi meskipun Anda tidak pernah memperbaruinya, Anda masih dapat mem-rebase itu.). Anda tidak dapat memindahkan tag (itu terkait dengan komit tertentu). Anda dapat memilih untuk mendorong cabang. Tag tidak didorong secara default. Anda seharusnya tidak pernah menggunakan satu untuk yang lain (kecuali jika Anda benar-benar dalam pola pikir SVN, dalam hal ini Anda perlu "un-belajar" secepat itu jika Anda ingin melanjutkan dengan git).
VonC
19
@SteveBennett: Ada perbedaan bagaimana Git memperlakukan cabang vs bagaimana ia memperlakukan tag. Selain apa yang dikatakan VonC, Anda tidak dapat memajukan tag secara tidak sengaja: " git checkout <tag>" akan menghasilkan cabang tanpa nama anonim (disebut 'kepala terpisah') dan memilih status tag. Membuat komit baru melakukannya di cabang yang tidak disebutkan namanya ini, dan tidak mengubah tag yang ditunjuk.
Jakub Narębski
60
IMO, cabang dipisahkan timeline (dunia paralel), dan tag adalah momen spesifik pada timeline.
Eonil
25
Belum ada seorang pun di sini yang menyebutkannya, tetapi Anda dapat menggunakan tag sebagai titik untuk memulai cabang:git checkout -b <branch name> <tag name>
143

Jika Anda menganggap repositori Anda sebagai buku yang mencatat kemajuan proyek Anda ...

Ranting

Anda dapat menganggap cabang sebagai salah satu penanda tempel tersebut :

masukkan deskripsi gambar di sini

Repositori baru hanya memiliki salah satu dari mereka (dipanggil master), yang secara otomatis pindah ke halaman terbaru (anggap komit ) yang Anda tulis. Namun, Anda bebas membuat dan menggunakan lebih banyak bookmark, untuk menandai tempat menarik lainnya di buku, sehingga Anda dapat kembali ke sana dengan cepat.

Selain itu, Anda selalu dapat memindahkan bookmark tertentu ke beberapa halaman buku lainnya (menggunakan git-reset, misalnya); tempat menarik biasanya bervariasi dari waktu ke waktu.

Tag

Anda dapat menganggap tag sebagai judul bab .

penanda buku

Ini mungkin berisi judul (pikirkan tag beranotasi ) atau tidak. Tag mirip tetapi berbeda dengan cabang, karena menandai titik minat historis pada buku. Untuk mempertahankan aspek historisnya, setelah Anda membagikan tag (yaitu mendorongnya ke remote bersama), Anda tidak seharusnya memindahkannya ke tempat lain di buku.

jub0bs
sumber
16
Saya akan membayangkan bahwa cabang akan menjadi sebuah buku, dan penanda adalah tag. Anda dapat terus menulis buku, tetapi Anda tidak dapat mengeditnya. Tag hanyalah momen tetap dalam buku.
Mārtiņš Briedis
5
@Jubobs Saya menyukai penjelasan cabang sebagai garis pengembangan. Buku akan menjadi cabang. Anda dapat memulai buku baru berdasarkan tempat meninggalkan cabang utama. Anda dapat menulisnya secara paralel dan kemudian mencoba untuk bergabung ke satu buku / cabang.
Mārtiņš Briedis
2
@ MārtiņšBriedis, saya mengerti cara Anda berpikir tentang cabang, tetapi saya menemukan bahwa, di Git, itu sebenarnya menyesatkan. Lihat stackoverflow.com/questions/25068543/…
jub0bs
2
jawaban yang benar-benar hemat waktu ini
Ali Foroughi
2
Jika Anda mulai menulis buku dan memiliki 50 halaman pertama, Anda dapat menyalinnya (membuat cabang baru darinya) dan terus menulis dua buku secara bersamaan (atau memberikan salinan buku itu kepada beberapa penulis - pengembang lain) dan akhirnya Anda dapat menggabungkan perubahan dari buku lain ke buku Anda.
barell
42

Apa yang perlu Anda sadari, berasal dari CVS, adalah bahwa Anda tidak lagi membuat direktori saat membuat cabang.
Tidak ada lagi "tag lengket" (yang dapat diterapkan hanya pada satu file), atau "tag cabang".
Cabang dan tag adalah dua objek berbeda di Git, dan mereka selalu berlaku untuk semua repo.

Anda tidak lagi (dengan SVN saat ini) harus secara terstruktur membuat repositori Anda dengan:

branches
   myFirstBranch
     myProject
       mySubDirs
   mySecondBranch
     ...
tags
   myFirstTag
     myProject
       mySubDirs
   mySecondTag
   ...

Struktur itu berasal dari kenyataan bahwa CVS adalah sistem revisi dan bukan sistem versi (lihat Kontrol sumber vs. Kontrol Revisi? ).
Itu berarti cabang ditiru melalui tag untuk CVS, salinan direktori untuk SVN.

Pertanyaan Anda masuk akal jika Anda terbiasa checkout tag, dan mulai bekerja di dalamnya .
Yang tidak seharusnya Anda lakukan;)
Tag seharusnya mewakili konten yang tidak dapat diubah , hanya digunakan untuk mengaksesnya dengan jaminan untuk mendapatkan konten yang sama setiap kali.

Di Git, sejarah revisi adalah serangkaian komitmen, membentuk grafik.
Cabang adalah satu jalur dari grafik itu

x--x--x--x--x # one branch
    \ 
     --y----y # another branch
       1.1
        ^
        |
        # a tag pointing to a commit
  • Jika Anda mencentang tag, Anda harus membuat cabang untuk mulai bekerja darinya.
  • Jika Anda checkout cabang, Anda akan langsung melihat komit terbaru ('KEPALA') cabang itu.

Lihat jawaban Jakub Narębski untuk semua teknis, tetapi terus terang, pada titik ini, Anda tidak perlu (belum) semua detail;)

Poin utamanya adalah: sebuah tag menjadi pointer sederhana ke sebuah komit, Anda tidak akan pernah bisa mengubah kontennya. Anda membutuhkan cabang.


Dalam kasus Anda, setiap pengembang mengerjakan fitur tertentu:

  • harus membuat cabang mereka sendiri di repositori masing-masing
  • melacak cabang dari repositori kolega mereka (yang bekerja pada fitur yang sama)
  • menarik / mendorong untuk berbagi pekerjaan Anda dengan rekan-rekan Anda.

Alih-alih melacak langsung cabang kolega Anda, Anda hanya dapat melacak cabang dari satu repositori pusat "resmi" tempat setiap orang mendorong pekerjaannya untuk mengintegrasikan dan membagikan karya semua orang untuk fitur khusus ini.

VONC
sumber
1
terima kasih telah menjelaskan cara kerja cabang dan tag :) saya tidak akan dapat sepenuhnya memahaminya tanpa contoh Anda.
ufk
3
@VonC: Saya pikir maksud Anda "SVN" dalam jawaban Anda dan bukan "CVS". CVS tidak memiliki struktur direktori; SVN melakukannya. Sebenarnya, penandaan dalam git mengingatkan saya lebih banyak pada penandaan di RCS / CVS daripada penandaan di SVN (di mana tag == degenerate branch).
Chris Cleeland
1
@ChrisCleeland poin bagus. Saya telah mencoba untuk memisahkan lebih banyak poin CVS dan SVN dalam jawaban (diedit).
VonC
37

Cabang-cabangnya terbuat dari kayu dan tumbuh dari batang pohon. Tag terbuat dari kertas (turunan dari kayu) dan digantung seperti Ornamen Natal dari berbagai tempat di pohon.

Proyek Anda adalah pohon, dan fitur Anda yang akan ditambahkan ke proyek akan tumbuh di cabang. Jawabannya adalah cabang.

Jason
sumber
3
love for the
analogogy
16

Sepertinya cara terbaik untuk menjelaskan adalah bahwa tag bertindak sebagai hanya cabang baca. Anda dapat menggunakan cabang sebagai tag, tetapi Anda dapat memperbaruinya secara tidak sengaja dengan komitmen baru. Tag dijamin untuk menunjuk komit yang sama selama ada.

Vassili Gorshkov
sumber
11
Tag dijamin untuk menunjuk komit yang sama selama ada. Tidak sepenuhnya benar. Anda benar-benar dapat memindahkan tag git tag -f.
jub0bs
14

Tag dapat ditandatangani atau tidak ditandatangani ; cabang tidak pernah masuk.

Tag yang ditandatangani tidak pernah bisa bergerak karena terikat secara kriptografis (dengan tanda tangan) ke komit tertentu. Tag yang tidak ditandatangani tidak terikat dan dimungkinkan untuk memindahkannya (tetapi memindahkan tag bukanlah hal yang biasa).

Cabang tidak hanya bisa pindah ke komit yang berbeda tetapi diharapkan juga melakukannya. Anda harus menggunakan cabang untuk proyek pengembangan lokal Anda. Tidak masuk akal untuk melakukan pekerjaan pada repositori Git "pada tag".

Greg Hewgill
sumber
12

Saya suka menganggap cabang sebagai tujuan Anda , tag sebagai tujuan Anda .

Tag terasa seperti penunjuk titik penting tertentu di masa lalu, seperti rilis versi.

Sedangkan cabang adalah jalan tertentu proyek turun, dan dengan demikian penanda cabang maju bersama Anda. Setelah selesai, Anda menggabungkan / menghapus cabang (yaitu penanda). Tentu saja, pada saat itu Anda dapat memilih untuk menandai komit itu.

Gazzer
sumber
10

The Git Perumpamaan menjelaskan bagaimana DVCS khas akan dibuat dan mengapa pencipta mereka melakukan apa yang mereka lakukan. Juga, Anda mungkin ingin melihat Git for Computer Scientist ; itu menjelaskan apa yang dilakukan setiap jenis objek di Git, termasuk cabang dan tag.

Bombe
sumber
6

Tag digunakan untuk menandai versi, lebih khusus itu merujuk titik waktu pada cabang. Cabang biasanya digunakan untuk menambahkan fitur ke proyek.

Number45
sumber
4

sederhana:

Tag diharapkan selalu mengarah pada versi proyek yang sama, sementara pimpinan diharapkan untuk maju seiring kemajuan pembangunan.

Git User Manual

Bar Horing
sumber
4

jawaban sederhana adalah:

cabang: pointer cabang saat ini bergerak dengan setiap komit ke repositori

tapi

tag: komit yang ditandai oleh suatu tag tidak berubah, sebenarnya tag itu adalah snapshot dari komit itu.

jsina
sumber