ProjectB adalah submodul dari projectA. Beberapa pengembangan pada projectB terjadi, dan saya memperbarui submodule projectA untuk menunjuk ke komit projectB terbaru. Untuk melakukannya, saya menarik perubahan upstream ke projectB ke dalam submodul projectA saya. Saya melakukan perubahan ke submodule di projectA. Saya membuat kode dengan riang, tetapi menyadari bahwa status git submodule projectA saya adalah:

git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
nothing to commit, working directory clean

Meskipun tidak pernah membuat perubahan lokal pada submodul projectA. Log git saya untuk submodule adalah:

git log --oneline --decorate
2703249 (HEAD, master) Bugfix L148: correctly filling raw_hitmap_neig_s
9f1db21 (origin/master, origin/HEAD) created QL2P.xml for MCgen
1a3dfe5 Changed column name of files for DB output.
...

2703249 adalah komit projectB terbaru, dan tidak satu pun dari ini yang saya lakukan secara lokal. Saya ingin tahu bagaimana menafsirkan log git dalam kasus ini, dan juga bagaimana cara menghilangkan komit asing di repo saya (tanpa membuat perubahan apa pun pada remote projectB).

Berdasarkan artikel ini, di bagian, Mendapatkan pembaruan dari remote submodule Saya yakin sumber masalahnya ada hubungannya dengan fakta bahwa saya menarik ke submodule saya, tetapi saya tidak mengerti mengapa itu menghasilkan komit tambahan, atau bagaimana cara memperbaikinya.

0
lia 6 Juli 2020, 19:00

1 menjawab

Jawaban Terbaik

Seperti yang tercantum dalam komentar (dan diperbaiki untuk jawaban ini), Anda hanya perlu:

cd projectB && git fetch

Untuk memperbarui origin/master submodule.

Alasan untuk ini adalah versi Git khusus Anda, yang cukup lama (Git sekarang menggunakan 2.26). Versi Git di bawah 1.8.4—yang tentu saja menyertakan 1.8.3.1 Anda—memiliki kebiasaan buruk untuk tidak memperbarui nama origin/* dalam berbagai kasus, khususnya termasuk kasus yang dihasilkan dari penggunaan git pull.

Panjang

Setiap Git memiliki salinan independen dari beberapa repositori. Ini termasuk submodul, yang hanya merupakan repositori Git yang akan ditarik oleh beberapa superproject repositori Git tingkat yang lebih tinggi sesuai kebutuhan. Untungnya kita dapat mengabaikan sebagian besar aspek submodul di sini karena tidak berpengaruh pada satu masalah tertentu yang sedang kita bicarakan.

Meskipun setiap Git adalah independen—memiliki nama cabangnya sendiri, tidak bergantung pada nama cabang Git lainnya—kita selalu dapat menghubungkan satu Git ke Git lainnya. Kami biasanya melakukan ini dengan menghubungkan beberapa repositori Git ke repositori tempat kami mengkloning. Artinya, kami membuat repositori ini dengan menjalankan git clone url. Jika kita terhubung ke URL lagi, Git mereka mungkin memiliki barang baru yang bisa kita ambil. Atau, jika kita memiliki barang baru yang bisa kita berikan kepada mereka, kita bisa melakukannya. Jelas, kita akan membutuhkan URL itu lagi.

Remote mengingat URL untuk Anda

Repositori Git akan mengingat URL untuk Anda. Untuk mengingat URL tersebut, kami menggunakan remote, yang hanya merupakan nama pendek seperti origin—dan sebenarnya, nama standar untuk remote pertama, dari mana kami melakukan git clone, adalah origin. Jadi sebagian besar repositori Git memiliki nama pendek origin untuk URL apa pun yang sebenarnya kita ketik saat itu—atau, dengan submodule, URL yang digunakan superproject untuk menjalankan git clone untuk membuat submodul Git.

Untuk situasi yang lebih rumit, Anda dapat menambahkan lebih banyak remote: setiap remote mengingat satu URL. Tapi kami hanya akan mempertimbangkan kasus satu-jarak jauh.

Perintah untuk menghubungkan Gits adalah git fetch dan git push

Untuk menghubungkan Git Anda dengan yang lain, Anda akan menjalankan git fetch atau git push. Bagaimana dengan git pull? Nah, git pull hanyalah pembungkus untuk melakukan dua hal: ini dimulai dengan menjalankan git fetch untuk Anda:

  • Perintah git fetch menghubungkan Git Anda ke Git lain dan mengambil sesuatu dari mereka. Anda dapat memberikan URL, https://example.com/some/path/to/repo.git, atau nama pendek origin—lebih mudah diketik, mudah diingat, dan memiliki berbagai manfaat. Atau Anda dapat membiarkan Git mengetahui bahwa origin adalah satu-satunya remote, dan jalankan saja git fetch.

  • Perintah git push menghubungkan Git Anda ke Git lain dan memberikan sesuatu kepada mereka. Seperti halnya git fetch, Anda dapat memberinya URL, atau nama jarak jauh origin yang bagus.

Dengan kata lain, kami memilih Git lain, dan arah untuk transfer—tidak ada opsi "mendapatkan sesuatu dari, dan memberikan sesuatu kepada, Git lain" dua arah, meskipun hal seperti itu dapat berguna. Jika kita ingin melakukan itu, kita harus menjalankan dua perintah terpisah. Operasinya juga tidak cukup simetris, tetapi kita hanya akan melihat git fetch di sini.

Saat Anda menggunakan git fetch, Git Anda terhubung ke Git lain dan membuatnya mencantumkan semua cabang dan tagnya serta nama lain semacam itu, bersama dengan detail internal Git tentang mereka.1 Jika Anda jalankan git fetch sendiri, Git Anda memeriksa ini dan mengambil semua nama cabang mereka, secara default, lalu mengganti nama mereka: master menjadi origin/master Anda, misalnya.

Git Anda kemudian mendapatkan komit baru yang mereka miliki, yang tidak Anda miliki, dan kemudian memperbarui semua nama origin/* Anda. Nama origin/* ini adalah nama pelacakan jarak jauh Anda.2 Itu adalah memori Git Anda untuk beberapa nama cabang Git lainnya, terakhir kali Git Anda memanggil Git dan membawa hal-hal baru.

Agar penggantian nama ini berfungsi, Anda harus menggunakan nama jarak jauh yang pendek. Jika Anda menggunakan URL, Git tidak tahu nama jarak jauh mana yang harus diletakkan di depan nama cabangnya ! Nama pendek biasanya lebih mudah diketik, jadi kebanyakan orang hanya menggunakan nama pendek, dan memperbarui nama origin/* mereka.

Terkadang Anda mungkin tidak menginginkan semuanya: jika Anda hanya menginginkan origin/master, misalnya, Anda dapat meminta Git Anda untuk hanya melihat master mereka. Kadang-kadang dapat menghemat sedikit waktu: mungkin master mereka tidak diperbarui sama sekali, atau memiliki sedikit pembaruan, sementara cabang develop atau experimental mereka memiliki banyak hal baru yang tidak Anda lakukan. tidak perlu.

Versi Git sebelum 1.8.4 berbeda di sini. Untuk alasan apa pun—orang-orang Git berubah pikiran pada 1.8.4, dan saya tidak begitu mengerti apa yang mereka pikirkan sebelum itu—mereka menetapkan sesuatu up sehingga dalam versi Git tersebut, git fetch origin master tidak memperbarui origin/master, tetapi git fetch origin melakukan memperbarui origin/*.


1

2Git memanggil nama cabang pelacakan jarak jauh ini. Mereka sebenarnya bukan nama branch, dan kata branch sudah terlalu sering digunakan di Git, jadi saya ingin membuang kata tambahan itu dan menyebutnya remote -nama pelacakan. Kata jarak jauh dan pelacakan juga digunakan secara berlebihan di Git, jadi meskipun ini masih kurang bagus, tapi kita harus menyebutnya sesuatu!


git pull

git fetch yang git pull dijalankan menggunakan opsi "perbarui hanya satu cabang". Artinya, ia mengetahui cabang mana yang ingin diambil Git Anda dari, dan hanya meminta satu cabang itu. Kemudian ia melakukan langkah kedua, yaitu menjalankan perintah Git kedua—biasanya git merge—untuk benar-benar memasukkan itu ke dalam cabang Anda sendiri.3

Ini dimaksudkan agar nyaman. Lagi pula, hanya melakukan git fetch hanya melakukan satu hal: mendapatkan barang baru dari mereka, memperbarui (mungkin, di pra-1.8.4) beberapa atau semua nama origin/* di prosesnya, sehingga Git Anda sekarang mengingat apa yang mereka miliki. Itu tidak membantu Anda menyelesaikan pekerjaan Anda sendiri, karena pekerjaan Anda sendiri biasanya terjadi di cabang Anda. Jadi setelah git fetch, Anda memerlukan langkah kedua: campurkan pekerjaan mereka ke cabang saya. Langkah kedua itu mungkin menggunakan git merge, atau mungkin menggunakan git rebase, atau Anda bahkan mungkin melakukan sesuatu yang sama sekali berbeda—mungkin membuat cabang baru Anda sendiri—tetapi hampir selalu ada beberapa tahap kedua.

Jadi, git pull melakukan git fetch, dan kemudian menjalankan perintah Git kedua. Anda harus—dan harus—memilih, terlebih dahulu, apakah perintah Git kedua itu git merge atau git rebase, tanpa mengetahui apa yang akan masuk. Saya tidak sangat menyukai git pull, tetapi untuk beberapa alur kerja yang terdefinisi dengan baik, itu benar-benar lebih lebih nyaman, dan jika itu berhasil untuk Anda, tidak apa-apa.

Namun, seperti yang terjadi, dalam Git versi sebelum 1.8.4, git pull menjalankan git fetch sedemikian rupa sehingga nama origin/* Anda pasti tidak' t diperbarui. Jadi Anda akan memukul perilaku khusus ini setiap saat.

Jika Anda meningkatkan ke 1.8.4 atau lebih baru, git pull akan memperbarui satu nama pelacakan jarak jauh—origin/master, misalnya—yang sesuai dengan nama cabang yang diambilnya. Atau, Anda dapat menghindari git pull, seperti yang saya pelajari di masa Git 1.6,4 dan lakukan saja kedua langkah tersebut secara manual.


3Saat menggunakan submodul, operasi penggabungan ini seringkali tidak diperlukan sama sekali. Dukungan submodul di Git modern jauh lebih baik daripada dukungan submodul di Git versi lama ini, dan sekarang Anda dapat menggunakan perintah git submodule untuk mengambil pembaruan, daripada masuk ke setiap submodul satu per satu secara manual. Meski begitu, itu masih agak kasar di sekitar tepi bahkan di Git modern, dan ada alasan orang menyebutnya sob-modul ini. :-) Detailnya bisa sangat berantakan.

4Pada masa itu, git pull memiliki beberapa bug buruk. Saya kehilangan beberapa minggu pekerjaan karena mereka. Sejauh yang saya tahu, bug itu tidak pernah kembali, tetapi karena saya kebanyakan menghindari git pull, saya tidak akan melihatnya.

0
torek 9 Juli 2020, 16:19