Rumah  >  Artikel  >  tutorial komputer  >  Adakah Git melakukan perbezaan, syot kilat atau sejarah?

Adakah Git melakukan perbezaan, syot kilat atau sejarah?

PHPz
PHPzke hadapan
2024-02-19 11:39:421098semak imbas

Git 提交是差异、快照还是历史记录?

Mudah untuk saya memahami cara Git commit dilaksanakan, tetapi sukar untuk memahami cara orang lain melihat commit. Jadi saya bertanya beberapa soalan kepada orang lain di Mastodon.

Apa pendapat anda tentang penyerahan Git?

Saya menjalankan tinjauan yang sangat tidak saintifik yang bertanya kepada orang ramai tentang pendapat mereka tentang komitmen Git: adakah ia petikan, perbezaan atau senarai semua komitmen sebelumnya? (Sudah tentu, adalah munasabah untuk menganggapnya sebagai ketiga-tiganya, tetapi saya ingin tahu tentang perkara utama orang

Hasilnya ialah:

  • 51% perbezaan
  • 42% Syot Kilat
  • 4% Sejarah semua komitmen sebelumnya
  • 3% “Lain-lain”

Saya terkejut betapa hampirnya nisbah kedua-dua pilihan dalam Perbezaan dan Syot Kilat. Orang ramai juga membuat beberapa perkara yang menarik tetapi bercanggah, seperti
"Nampaknya komit adalah satu perbezaan, tetapi saya fikir ia sebenarnya dilaksanakan sebagai petikan" dan
"Nampaknya komit adalah Gambar, tetapi saya rasa ia sebenarnya datang dalam bentuk perbezaan”. Kami akan bercakap lebih lanjut tentang cara penyerahan sebenarnya dilaksanakan kemudian.

Sebelum kita pergi lebih jauh: apakah yang kita maksudkan dengan "perbezaan" atau "gambar"?

Apa bezanya?

"Perbezaan" yang saya maksudkan mungkin agak jelas: perbezaannya ialah apa yang anda dapat apabila anda berlari git show COMMIT_ID . Sebagai contoh, berikut ialah pembetulan kesilapan menaip dalam projek rbspy:

diff --git a/src/ui/summary.rs b/src/ui/summary.rs
index 5c4ff9c..3ce9b3b 100644
--- a/src/ui/summary.rs
+++ b/src/ui/summary.rs
@@ -160,7 +160,7 @@ mod tests {
";
let mut buf: Vec = Vec::new();
-stats.write(&mut buf).expect("Callgrind write failed");
+stats.write(&mut buf).expect("summary write failed");
let actual = String::from_utf8(buf).expect("summary output not utf8");
assert_eq!(actual, expected, "Unexpected summary output");
}

Anda boleh melihatnya di GitHub: https://github.com/rbspy/rbspy/commit/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b

Apa itu syot kilat?

Dengan “snapshot” saya maksudkan “semua fail yang anda dapat apabila anda menjalankan git checkout COMMIT_ID”.

Git biasanya merujuk kepada senarai fail yang diserahkan sebagai "pokok" (seperti "pokok direktori"), dan anda boleh melihat semua fail yang diserahkan di atas pada GitHub:

https://github.com/rbspy/rbspy/tree/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b (ia adalah /tree/ 而不是 /commit/)

Adakah "cara Git dilaksanakan" benar-benar cara yang betul untuk menerangkannya?

Nasihat yang paling biasa saya dengar tentang pembelajaran Git mungkin "hanya pelajari cara Git mewakili sesuatu secara dalaman, dan semuanya akan menjadi lebih jelas". Saya jelas sangat menyukai perspektif ini (jika anda telah meluangkan sedikit masa membaca blog ini, anda akan tahu saya menyukainya

Tetapi sebagai cara untuk mempelajari Git, ia tidak menjadi seperti yang saya harapkan! Biasanya saya teruja mula menerangkan "Baiklah, jadi Git
komit ialah petikan, ia mempunyai penunjuk kepada komit induknya, kemudian cawangan adalah penunjuk kepada komit, kemudian...", tetapi saya cuba membantu Orang akan memberitahu saya bahawa mereka tidak benar-benar mendapati penjelasan itu berguna, bahawa mereka masih tidak memahaminya. Jadi saya telah melihat pilihan lain.

Tetapi mari kita bercakap tentang pelaksanaan dalaman dahulu.

Cara Git mewakili komit secara dalaman - Snapshot

Secara dalaman, Git mewakili komit sebagai syot kilat (ia menyimpan "pokok" versi semasa setiap fail). Saya berada dalam repositori Git, di manakah fail anda? Saya telah menulis tentang perkara ini dalam , tetapi berikut ialah gambaran keseluruhan yang sangat cepat tentang format dalaman.

Ini adalah perwakilan penyerahan:

$ git cat-file -p 24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b
tree e197a79bef523842c91ee06fa19a51446975ec35
parent 26707359cdf0c2db66eb1216bf7ff00eac782f65
author Adam Jensen1672104452 -0500
committer Adam Jensen1672104890 -0500
Fix typo in expectation message

Dan, apabila kita melihat objek pokok ini, kita melihat senarai setiap fail/subdirektori di bawah akar repositori dalam komit ini:

$ git cat-file -p e197a79bef523842c91ee06fa19a51446975ec35
040000 tree 2fcc102acd27df8f24ddc3867b6756ac554b33ef.cargo
040000 tree 7714769e97c483edb052ea14e7500735c04713eb.github
100644 blob ebb410eb8266a8d6fbde8a9ffaf5db54a5fc979a.gitignore
100644 blob fa1edfb73ce93054fe32d4eb35a5c4bee68c5bf5ARCHITECTURE.md
100644 blob 9c1883ee31f4fa8b6546a7226754cfc84ada5726CODE_OF_CONDUCT.md
100644 blob 9fac1017cb65883554f821914fac3fb713008a34CONTRIBUTORS.md
100644 blob b009175dbcbc186fb8066344c0e899c3104f43e5Cargo.lock
100644 blob 94b87cd2940697288e4f18530c5933f3110b405bCargo.toml

Ini bermakna menyemak komit Git sentiasa pantas: ia sama mudah untuk Git menyemak komit semalam seperti menyemak komit sejuta yang lalu. Git tidak perlu memohon semula 10,000 diff untuk menentukan keadaan semasa kerana commit tidak pernah disimpan sebagai diff sama sekali.

Snapshot dimampatkan menggunakan fail pack

Saya baru sahaja menyebut bahawa komit Git ialah petikan, tetapi apabila seseorang berkata "Pada pendapat saya, komit ialah petikan, tetapi saya fikir ia adalah perbezaan dalam pelaksanaan"
, itu sebenarnya benar juga! Git
commit tidak diwakili dalam bentuk diff yang mungkin anda biasa gunakan (ia tidak disimpan pada cakera sebagai beza daripada commit sebelumnya), tetapi intuisi asasnya ialah jika anda akan melakukan 10,000
fail baris Mengedit 500 kali, kemudian menyimpan 500 fail akan menjadi tidak cekap.

Git mempunyai cara untuk menyimpan fail sebagai perbezaan. Ini dipanggil "fail pek" dan Git akan mengumpul data anda secara berkala ke dalam fail pek untuk menjimatkan ruang cakera. Git juga memampatkan data apabila anda git clone repositori.

Saya tidak mempunyai ruang yang mencukupi di sini untuk menerangkan sepenuhnya cara fail pek berfungsi ("Membongkar fail pek Git" Aditya Mukerjee ialah artikel kegemaran saya untuk menerangkan cara ia berfungsi). Walau bagaimanapun, saya boleh merumuskan secara ringkas pemahaman saya tentang cara delta berfungsi dan cara ia berbeza daripada perbezaan di sini:

  • Objek disimpan sebagai rujukan kepada "fail asal" dan "delta"
  • Delta ialah urutan arahan seperti "baca bait 0 hingga 100, kemudian masukkan bait 'hello there', kemudian baca bait 120 hingga 200." Ia menyatukan teks baharu daripada fail asal. Jadi tidak ada konsep "padam", hanya salin dan tambah.
  • Saya rasa terdapat lebih sedikit tahap delta: Saya tidak tahu cara menyemak berapa banyak tahap delta yang perlu dilalui Git untuk mendapatkan objek tertentu, tetapi tanggapan saya ialah ia biasanya tidak banyak. Mungkin kurang daripada 10 tingkat? Saya ingin tahu bagaimana sebenarnya untuk mengetahui, walaupun.
  • Fail asal tidak semestinya daripada komit sebelumnya, ia boleh menjadi apa sahaja. Mungkin ia mungkin juga dari komitmen kemudian? Saya tidak pasti.
  • Tiada algoritma "betul" untuk mengira perubahan, Git hanya mempunyai beberapa anggaran heuristik

Sesuatu yang pelik sebenarnya berlaku apabila anda melihat perbezaannya

Apa yang sebenarnya berlaku apabila kita berlari git show SOME_COMMIT untuk melihat perbezaan komit adalah sedikit intuitif. Pemahaman saya ialah:

  • Git akan melihat dalam fail pek dan menggunakan perubahan untuk membina semula pepohon komit ini dan komit induknya.
  • Git akan melakukan perbandingan perbezaan antara dua pepohon direktori (pohon direktori komit semasa dan pepohon direktori komit induk). Biasanya ini pantas, kerana hampir semua fail adalah sama, jadi git hanya boleh membandingkan cincang fail yang sama, hampir sepanjang masa tidak melakukan apa-apa.
  • Akhirnya Git akan menunjukkan perbezaan
  • Jadi, Git akan menukarkan perubahan kepada syot kilat dan kemudian mengira perbezaannya. Rasanya agak pelik kerana ia bermula dengan sesuatu seperti perbezaan dan berakhir dengan perkara lain seperti perbezaan, tetapi jumlah perubahan dan perbezaan itu sebenarnya berbeza sama sekali, jadi ia masuk akal.

    Yang berkata, saya rasa Git stores commit sebagai syot kilat dan fail pek hanyalah butiran pelaksanaan untuk menjimatkan ruang cakera dan mempercepatkan pengklonan. Saya sebenarnya tidak perlu tahu cara fail pack berfungsi, tetapi ia membantu saya memahami cara syot kilat Git dilakukan tanpa mengambil terlalu banyak ruang cakera.

    Pemahaman Git yang "salah": commit adalah berbeza

    Saya rasa pemahaman yang agak biasa tentang "kesilapan" Git ialah:

    • Komit disimpan sebagai perbezaan berdasarkan komit sebelumnya (ditambah penunjuk kepada komit induk dan pengarang serta mesej).
    • Untuk mendapatkan status semasa komit, Git perlu memohon semula semua komit sebelumnya dari awal.

    Pemahaman ini sudah tentu salah (sebenarnya, commit disimpan dalam bentuk syot kilat dan perbezaan dikira daripada syot kilat ini), tetapi bagi saya ia kelihatan sangat berguna dan masuk akal! Agak pelik apabila memikirkan tentang merge commit, tetapi mungkin kita boleh mengatakan bahawa ini hanyalah perbezaan berdasarkan commit induk pertama bagi merge commit.

    Saya rasa salah faham ini kadangkala sangat berguna, dan ia nampaknya tidak menjadi masalah untuk penggunaan Git harian. Saya sangat suka bahawa ia menjadikan perkara yang paling banyak kita gunakan (perbezaan) sebagai elemen paling asas - ia sangat intuitif kepada saya.

    Saya juga telah memikirkan beberapa pemahaman lain yang berguna tetapi "salah" tentang Git, seperti:

    • Maklumat komit boleh diedit (sebenarnya tidak, anda hanya menyalin komit yang sama dan memberikan maklumat baharu, komit lama masih wujud)
    • Komit boleh dialihkan ke pangkalan yang berbeza (begitu juga, ia disalin)

    Saya rasa terdapat pelbagai pemahaman "salah" tentang Git yang sangat masuk akal, sebahagian besarnya disokong oleh antara muka pengguna Git, dan tidak menyebabkan masalah dalam kebanyakan kes. Tetapi ia boleh mengelirukan apabila anda ingin membuat asal perubahan atau berlaku masalah.

    Beberapa kelebihan memikirkan tentang penyerahan sebagai perbezaan

    Walaupun saya tahu commit ialah syot kilat dalam Git, saya mungkin menganggapnya sebagai berbeza pada kebanyakan masa kerana:

    • Kebanyakan masa saya menumpukan pada perubahan yang saya buat - jika saya hanya menukar baris kod, jelas sekali saya lebih memikirkan tentang baris kod itu dan bukannya keadaan semasa keseluruhan pangkalan kod
    • Anda akan melihat perbezaannya apabila anda mengklik pada Git commit pada GitHub atau menggunakan git show jadi ia adalah sesuatu yang biasa saya lihat
    • Saya banyak menggunakan rebasing, semuanya tentang memohon semula perbezaan

    Beberapa kelebihan menganggap komit sebagai gambar

    Tetapi saya juga kadangkala menganggap commit sebagai syot kilat kerana:

    • Git sering keliru dengan pergerakan fail: kadangkala saya mengalihkan fail dan mengeditnya, dan Git tidak menyedari bahawa ia telah dialihkan, sebaliknya ia muncul sebagai
      "old.py dialih keluar, new.py ditambah". Ini kerana Git hanya menyimpan syot kilat, jadi apabila ia berkata "Alih lama.py -> baharu.py"
      Pada masa ini, ia hanya tekaan kerana kandungan old.py dan new.py adalah serupa.
    • Dengan cara ini lebih mudah untuk memahami apa yang git checkout COMMIT_ID lakukan (idea memohon semula 10,000 komitmen membuatkan saya tertekan)
    • Komit gabungan kelihatan lebih seperti syot kilat bagi saya, memandangkan komitmen gabungan boleh menjadi apa-apa sahaja (ia hanya syot kilat baharu!). Ia membantu saya memahami sebab perubahan sewenang-wenangnya boleh dibuat semasa menyelesaikan konflik gabungan, dan mengapa perlu berhati-hati apabila menyelesaikan konflik.

    Beberapa pemahaman lain tentang penyerahan

    Beberapa balasan Mastodon juga menyebut:

    • Maklumat luar jalur "Tambahan" tentang komitmen, seperti e-mel, permintaan tarik GitHub atau perbualan yang anda ada dengan rakan sekerja
    • Fikirkan "perbezaan" sebagai "keadaan sebelum + keadaan selepas"
    • Dan, sudah tentu, ramai orang melihat penyerahan secara berbeza bergantung pada keadaan

    Beberapa perkataan lain yang digunakan orang apabila bercakap tentang komitmen yang mungkin kurang samar-samar:

    • "Semakan" (nampak lebih seperti syot kilat)
    • "Tampalan" (kelihatan lebih seperti perbezaan)

    Itu sahaja!

    Sukar untuk saya memahami perbezaan pemahaman orang tentang Git. Apa yang lebih rumit ialah, walaupun pemahaman "salah" selalunya sangat berguna, orang ramai sangat berminat untuk berhati-hati dengan model mental yang "salah" sehingga mereka enggan berkongsi idea "salah" mereka kerana bimbang sesetengah jurubahasa Git akan berdiri. Keluar dan terangkan kepada mereka mengapa mereka salah. (Penerjemah Git
    ini biasanya bermaksud baik, tetapi ia boleh memberi kesan negatif tanpa mengira)

    Tetapi saya belajar banyak! Saya masih tidak pasti sepenuhnya cara bercakap tentang komitmen, tetapi kita akan memikirkannya akhirnya.

    Terima kasih kepada Marco Rogers, Marie Flanagan dan semua orang di Mastodon kerana membincangkan komitmen Git dengan saya.

    Atas ialah kandungan terperinci Adakah Git melakukan perbezaan, syot kilat atau sejarah?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan:
    Artikel ini dikembalikan pada:mryunwei.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam