Mengapa git commit tidak mengandung nama cabang tempat mereka diciptakan?


20

Ketika bekerja dengan git dalam sebuah tim yang menggunakan cabang fitur, saya sering merasa sulit untuk memahami struktur cabang dalam sejarah.

Contoh:

Katakanlah ada fitur cabang fitur / kopi , dan perbaikan bug berlanjut pada master secara paralel dengan cabang fitur.

Sejarah mungkin terlihat seperti ini:

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

Masalah

Pada pandangan pertama, saya merasa sulit untuk mengatakan sisi mana yang merupakan cabang fitur. Saya biasanya perlu menelusuri beberapa komentar di kedua sisi untuk mendapatkan ide yang mana. Ini menjadi lebih rumit jika ada beberapa cabang fitur secara paralel (terutama jika mereka untuk fitur terkait erat), atau jika ada penggabungan di kedua arah antara fitur cabang dan master.

Sebagai kontras, dalam Subversion, ini jauh lebih mudah karena nama cabang adalah bagian dari sejarah - jadi saya bisa langsung tahu bahwa komit awalnya dibuat pada "fitur / kopi".

Git dapat membuat ini lebih mudah dengan memasukkan nama cabang saat ini di metadata komit ketika membuat komit (bersama dengan penulis, tanggal dll.). Namun, git tidak melakukan ini.

Adakah alasan mendasar mengapa ini tidak dilakukan? Atau hanya tidak ada yang menginginkan fitur tersebut? Jika yang terakhir, apakah ada cara lain untuk memahami tujuan cabang sejarah tanpa melihat nama?


1
Pertanyaan terkait: Mencari dari cabang mana komit berasal . Ini adalah tentang bagaimana menemukan informasi ini walaupun faktanya git tidak secara eksplisit mencatatnya.
sleske

1
Catatan untuk diri sendiri: Menariknya, di Mercurial, komit memang berisi nama cabang. Jadi nampaknya para Mercurial devs membuat keputusan desain yang berbeda dari para git devs. Lihat misalnya felipec.wordpress.com/2012/05/26/… untuk detailnya.
sleske

Jawaban:


14

Mungkin karena nama cabang hanya bermakna dalam satu repositori. Jika saya berada di make-coffeetim dan mengirimkan semua perubahan saya melalui penjaga gerbang, mastercabang saya mungkin akan ditarik ke make-coffee-guicabang penjaga gerbang , yang akan ia gabungkan dengan make-coffee-backendcabangnya, sebelum rebasing ke make-coffeecabang yang akan bergabung ke mastercabang pusat .

Bahkan dalam satu repositori, nama cabang dapat dan memang berubah seiring alur kerja Anda berkembang. mastermungkin berubah nanti untuk dipanggil development, misalnya.

Seperti yang disinggung CodeGnome, git memiliki filosofi desain yang kuat untuk tidak memasukkan sesuatu ke dalam data jika itu tidak diperlukan. Pengguna diharapkan untuk menggunakan opsi di git logdan git diffuntuk menghasilkan data sesuai dengan keinginan mereka setelah fakta. Saya sarankan mencoba beberapa sampai Anda menemukan format yang berfungsi lebih baik untuk Anda. git log --first-parent, misalnya, tidak akan menampilkan komit dari cabang yang digabung.


2
Perlu dicatat bahwa orang tua pertama biasanya salah. Karena biasanya seseorang hanya menarik tuan ke dalam apa pun yang mereka kerjakan dan mendorong keluar membuat pekerjaan mereka sebagai orang tua pertama dan menguasai yang kedua.
Jan Hudec

1
@ JanHudec: Sebenarnya, ini tergantung :-). Jika orang yang melakukan pekerjaan menggabungkannya, maka ya. Jika penggabungan terjadi kemudian, mungkin setelah peninjauan, maka lebih mungkin peninjau telah menguasai memeriksa dan menggabungkan cabang fitur menjadi master, mengujinya dan mendorong.
sleske

5

Lacak Sejarah Cabang dengan --no-ff

Di Git, komit memiliki leluhur, tetapi "cabang" sebenarnya hanyalah kepala dari beberapa lini pembangunan saat ini. Dengan kata lain, komit adalah snapshot dari pohon yang bekerja pada suatu saat, dan dapat menjadi bagian dari sejumlah cabang sekaligus. Ini adalah bagian dari apa yang membuat Git bercabang sangat ringan jika dibandingkan dengan DVCSes lainnya.

Komit Git tidak membawa informasi cabang karena itu tidak diperlukan untuk sejarah Git. Namun, penggabungan yang tidak maju cepat tentu dapat membawa informasi tambahan tentang cabang apa yang digabungkan. Anda dapat memastikan bahwa riwayat Anda berisi informasi ini dengan selalu mengedarkan --no-ffbendera ke gabungan Anda. git-merge (1) mengatakan:

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

Ini umumnya akan membuat pesan gabungan yang mirip dengan Merge branch 'foo', jadi Anda biasanya dapat menemukan informasi tentang "cabang leluhur" dengan garis yang mirip dengan berikut:

$ git log --regexp-ignore-case --grep 'merge branch'

Terima kasih, tetapi itu (sebagian besar) tidak menjawab pertanyaan saya. Saya tidak bertanya apa cara lain untuk menemukan cabang asli, tetapi mengapa informasi tersebut tidak dimasukkan sebagai metadata biasa - ini lebih merupakan pertanyaan desain.
sleske

1
@sleske Saya pikir jawaban saya responsif: Git tidak melacaknya karena riwayat Git tidak membutuhkannya; Saya tidak berpikir itu menjadi lebih mendasar dari itu. Anda harus melihat sumber untuk spesifik, tetapi sejarah secara efektif dihitung mundur dari ujung cabang saat ini. Anda selalu dapat membandingkannya dengan beberapa DVCS lain yang memperlakukan cabang sebagai objek kelas satu dan melihat apakah Anda menyukai filosofi desain itu dengan lebih baik. YMMV.
CodeGnome

1
Yang terakhir seharusnya git log --merges.
Dan

3

Jawaban yang paling sederhana adalah bahwa nama cabang bersifat sementara. Bagaimana jika Anda, misalnya, mengganti nama cabang ( git branch -m <oldname> <newname>)? Apa yang akan terjadi pada semua komitmen terhadap cabang itu? Atau bagaimana jika dua orang memiliki cabang yang memiliki nama yang sama pada repositori lokal yang berbeda?

Satu-satunya hal yang memiliki makna dalam git adalah checksum dari commit itu sendiri. Ini adalah unit dasar pelacakan.

Informasi ada di sana, Anda hanya tidak memintanya, dan tidak persis di sana.

Git menyimpan checksum kepala setiap cabang di .git/refs/heads. Sebagai contoh:

... /. git / refs / kepala $ ls test 
-rw-rw-r-- 1 michealt michealt 41 Sep 30 11:50 ujian
... /. git / refs / kepala $ tes kucing 
87111111111111111111111111111111111111d4

(ya, saya mengacaukan git checksum saya, itu tidak istimewa, tetapi mereka adalah repositori pribadi yang saya lihat pada saat itu yang tidak perlu ada kebocoran secara tidak sengaja).

Dengan melihat ini dan melacak kembali setiap komit yang memiliki ini sebagai orang tua, atau orang tua orang tua atau orang tua orang tua ... Anda dapat mengetahui apa cabang komit yang diberikan masuk Ini hanya grafik besar untuk membuat.

Menyimpan di mana secara spesifik nama cabang (yang dapat berubah seperti disebutkan di atas) komit ada di komit itu sendiri adalah overhead tambahan pada komit yang tidak membantu itu. Simpan orang tua dari komit dan barangnya.

Anda dapat melihat cabang dengan menjalankan perintah git log dengan flag yang sesuai.

git log --branches --source --pretty = oneline --graph
git log --all --source --pretty = oneline --graph

Ada banyak cara berbeda untuk memilih apa yang Anda inginkan - lihat dokumentasi git log - -allbagian dan beberapa opsi yang mengikuti.

* 87111111111111111111111111111111111111d4 uji Gabung cabang 'test1' menjadi uji
| \  
| * 42111111111111111111111111111111111111e8 pembaruan test1: tambahkan barang
* | dd11111111111111111111111111111111111159 uji Gabung cabang 'test3' menjadi tes
| \ \  

'Tes', 'test1', dan 'test2' adalah cabang-cabang ini berkomitmen untuk.

Perhatikan bahwa dokumentasi git log sangat besar dan sangat mungkin untuk mendapatkan hampir semua yang Anda inginkan.


3

Mengapa git commit tidak mengandung nama cabang tempat mereka dibuat?

Hanya keputusan desain. Jika Anda memerlukan informasi itu, Anda dapat menambahkan hook bersiap-komit-komit atau komit-pesan untuk menegakkan itu di repositori tunggal.

Setelah bencana BitKeeper, Linus Torvalds mengembangkan git agar sesuai dengan proses pengembangan kernel Linux. Di sana, sampai tambalan diterima, tambalan itu direvisi, diedit, dipoles beberapa kali (semua melalui Mail), ditandatangani (= mengedit komit), dipetik dengan ceri, mengembara ke cabang-cabang letnan mungkin sering diubah, lebih banyak pengeditan, ceri -picks dan seterusnya sampai mereka akhirnya bergabung dengan Linus.

Dalam alur kerja seperti itu mungkin tidak ada asal spesifik komit, dan seringkali komit baru saja dibuat di beberapa cabang debugging sementara di beberapa repositori acak pribadi yang tidak penting dengan nama cabang lucu, karena git didistribusikan.

Mungkin keputusan desain itu terjadi secara kebetulan saja, tetapi persis sama dengan proses pengembangan kernel Linux.


2

Karena dalam Git, komit seperti "membuat kopi" dianggap sebagai bagian dari kedua cabang ketika cabang fitur digabungkan. Bahkan ada perintah untuk memeriksa itu:

% git branch --contains @
  feature/make-coffee
  master

Juga, cabang-cabang itu murah, lokal, dan ethereal; mereka dapat dengan mudah ditambahkan, dihapus, diganti namanya, didorong, dan dihapus dari server.

Git mengikuti prinsip bahwa semuanya dapat dilakukan, yang mengapa Anda dapat dengan mudah menghapus cabang dari server jauh, dan Anda dapat dengan mudah menulis ulang sejarah.

Katakanlah saya berada di cabang 'master', dan saya membuat dua komitmen: 'membuat kopi' dan 'menambahkan susu dan gula', lalu saya memutuskan untuk menggunakan cabang baru untuk itu, jadi saya mengatur ulang 'master' kembali ke 'asal /menguasai'. Tidak masalah, semua sejarah masih bersih: 'membuat kopi' dan 'menambahkan susu dan gula' bukan bagian dari master, hanya fitur / make-coffee.

Mercurial adalah kebalikannya; tidak ingin mengubah banyak hal. Cabang bersifat permanen, riwayat penulisan ulang disukai, Anda tidak bisa hanya menghapus cabang dari server.

Singkatnya: Git memungkinkan Anda untuk melakukan segalanya, Mercurial ingin membuat segalanya menjadi mudah (dan membuatnya sangat sulit untuk membiarkan Anda melakukan apa yang Anda inginkan).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.