Beberapa trik terkadang diperlukan saat bekerja dengan git

Saya ingin berbagi resep untuk menyelesaikan beberapa masalah yang terkadang muncul ketika bekerja dengan git, dan yang tidak "secara langsung cukup jelas."


Awalnya saya berpikir untuk mengumpulkan lebih banyak resep seperti itu, tetapi semuanya memiliki waktu. Saya pikir jika ada manfaatnya, maka itu mungkin dan sedikit demi sedikit ...


Jadi ...


Merg cabang-cabang tua dengan sedikit rasa sakit


Pembukaan. Ada cabang utama ( master ), yang secara aktif melakukan fitur dan perbaikan baru; ada cabang feature paralel, di mana para pengembang berlayar untuk sementara waktu di nirwana mereka sendiri, dan kemudian tiba-tiba menemukan bahwa mereka belum bersama master selama sebulan sekarang, dan penggabungan "di dahi" (head to head) sudah tidak ada artinya.


(Ya, ini bukan tentang dunia ideal di mana segala sesuatunya benar, kejahatan tidak ada, anak-anak selalu patuh dan bahkan menyeberang jalan dengan ketat dengan tangan bersama ibu mereka, dengan hati-hati melihat sekeliling).


Tujuan: untuk marah. Pada saat yang sama, sehingga itu merupakan gabungan "murni", tanpa fitur. Yaitu sehingga dalam repositori publik dalam grafik cabang, dua utas terhubung pada satu titik dengan pesan "gabungan cabang 'master' menjadi fitur". Dan seluruh "yang satu ini" sakit kepala tentang berapa banyak waktu dan usaha yang diperlukan, berapa banyak konflik yang diselesaikan, dan berapa banyak rambut yang ternoda tanpa perlu.


Plotnya. Fakta bahwa di git Anda dapat mengedit komit terakhir dengan kunci - --amend tahu. Kuncinya adalah bahwa "komit terakhir" ini dapat ditemukan di mana saja dan berisi apa saja. Misalnya, itu bisa bukan hanya "komit terakhir ke cabang linear", di mana mereka lupa untuk memperbaiki kesalahan ketik, tetapi juga komit gabungan dari gabungan biasa atau "gurita". --amend hanya --amend menggulung perubahan yang diajukan dan "menanamkan" komit yang diubah di pohon, seolah-olah itu benar-benar muncul sebagai hasil dari penggabungan yang jujur โ€‹โ€‹dan penyelesaian konflik. Intinya, git merge dan git commit --amend memungkinkan git commit --amend untuk sepenuhnya memisahkan "tempat taruhan" ("komit di pohon ini akan DI SINI") dan isi dari komit itu sendiri.


Gagasan utama komit gabungan kompleks dengan riwayat bersih adalah sederhana: pertama, โ€œbuat tempatโ€ dengan membuat komit gabungan bersih (terlepas dari kontennya), lalu tulis ulang dengan - --amend , menjadikan konten "benar".


  1. "Tempatkan pil." Ini mudah dilakukan dengan menetapkan strategi merger yang tidak akan mengajukan pertanyaan yang tidak perlu tentang resolusi konflik.


     git checkout feature git merge master -s ours 

  2. Oh ya Sebelum penggabungan, diperlukan cabang "cadangan" dari kepala fitur. Setelah semua, tidak ada yang benar-benar digabungkan ... Tapi biarlah paragraf ke-2, dan bukan ke-0. Secara umum, kami beralih ke fitur yang tidak digabungkan, dan sekarang secara jujur โ€‹โ€‹bergabung. Sedapat mungkin, terlepas dari "peretasan kotor" apa pun. Cara pribadi saya adalah dengan melihat cabang master dari saat penggabungan terakhir dan mengevaluasi kemungkinan masalah yang terjadi (misalnya: mengoreksi kesalahan ketik di satu tempat - bukan masalah. Secara besar-besaran (banyak file) mereka berganti nama menjadi entitas - masalah, dll.). Dari masalah commit, kami membuat cabang baru (saya lakukan dengan cerdik - master1, master2, master3, dll.). Dan kemudian kita menggabungkan cabang demi cabang, bergerak dari konflik lama ke konflik baru dan memperbaiki (yang biasanya jelas dengan pendekatan ini). Sarankan metode lain (saya bukan pesulap; Saya hanya belajar; Saya akan senang memberikan komentar yang membangun!). Pada akhirnya, menghabiskan (mungkin) beberapa jam untuk operasi rutin murni (yang dapat dipercayakan kepada junior, karena tidak ada konflik yang rumit dengan pendekatan ini), kami mendapatkan status akhir dari kode: semua inovasi / perbaikan wizard berhasil dipindahkan ke cabang fitur, semua tes yang relevan berjalan pada kode ini, dll. Kode yang sukses harus dilakukan.


  3. Menulis ulang "kisah sukses". Berada di komit, di mana "semuanya dilakukan", jalankan yang berikut:



 git tag mp git checkout mp git reset feature git checkout feature git tag -d mp 

(Saya menguraikan: menggunakan tag (mp - merge point), kami beralih ke keadaan HEAD yang terlepas, dari sana atur ulang ke kepala cabang kami, di mana pada awalnya sebuah "cadangan" dibuat oleh komit gabungan yang curang. Tag tidak lagi diperlukan, jadi kami menghapusnya). Sekarang kita berada di komit gabungan "murni" asli; pada saat yang sama dalam copy pekerjaan kami memiliki file "benar", di mana semua yang Anda butuhkan ditemukan. Sekarang Anda perlu menambahkan semua file yang diubah ke indeks, dan terutama hati-hati melihat non-bertahap (akan ada semua file baru yang muncul di cabang utama). Kami menambahkan semua yang kami butuhkan dari sana juga.


Akhirnya, ketika semuanya sudah siap, kita memasukkan komit kita yang benar ke tempat yang dipesan:


 git commit --amend 

Hore! Semuanya berhasil! Anda dapat dengan mudah mendorong cabang ke repositori publik, dan tidak ada yang akan tahu bahwa Anda benar-benar menghabiskan setengah hari bekerja pada penggabungan ini.


Pembaruan: Cara yang lebih ringkas


Tiga bulan setelah publikasi ini, artikel " Bagaimana dan mengapa mencuri pohon di git " oleh capslocky


Berdasarkan motifnya, adalah mungkin untuk mencapai tujuan yang persis sama dengan cara yang lebih pendek dan tanpa mekanisme tambahan: tidak perlu "memposting ruang", pertimbangkan file yang tidak dipentaskan setelah reset dan ubah; Anda dapat membuat komit gabungan langsung dengan konten yang diinginkan dalam satu langkah.


Kami segera mulai dengan merger menggunakan metode apa pun yang tersedia (seperti pada paragraf 2 di atas). Kisah perantara dan peretasan yang tidak jelas masih tidak relevan. Dan kemudian, alih-alih klaim 3, dengan penggantian komit gabungan, kami membuat gabungan buatan , seperti dalam artikel:


 git tag mp git checkout feature git merge --ff $(git commit-tree mp^{tree} -m "merged branch 'master' into 'feature'" -p feature -p master) git tag -d mp 

Semua keajaiban di sini dilakukan dalam satu langkah oleh perintah ketiga (git commit-tree).


Pilih bagian dari file, simpan histori


Pembukaan: file itu dikodekan-disandikan, dan akhirnya disandikan sehingga bahkan studio visual mulai melambat, mencernanya (belum lagi JetBrains). (Ya, kita kembali ke dunia "tidak sempurna". Seperti biasa).


Otak pintar berpikir, berpikir, dan memilih beberapa entitas yang dapat dirender menjadi file terpisah. Tapi! Jika Anda hanya mengambilnya, salin dan tempel sepotong file dan tempel ke file lain - ini akan menjadi file yang benar-benar baru dari sudut pandang git. Jika ada masalah, pencarian riwayat hanya akan menunjukkan "di mana orang cacat ini?" Siapa yang berbagi file. Dan mungkin perlu untuk menemukan sumber asli sama sekali tidak "untuk penindasan", tetapi murni konstruktif - untuk mencari tahu mengapa garis ini diubah; bug apa yang diperbaiki (atau tidak diperbaiki apa pun). Saya ingin file menjadi baru, tetapi pada saat yang sama seluruh sejarah perubahan masih ada!


Plotnya. Dengan beberapa efek tepi yang sedikit mengganggu, ini bisa dilakukan. Untuk kepastian, ada file file.txt , dari mana saya ingin menyorot bagian dalam file2.txt . (dan masih menyimpan ceritanya, ya). Jalankan cuplikan ini:


 f=file.txt; f1=file1.txt; f2=file2.txt cp $f $f2 git add $f2 git mv $f $f1 git commit -m"split $f step 1, converted to $f1 and $f2" 

Akibatnya, kami mendapatkan file file1.txt dan file2.txt . Mereka berdua memiliki cerita yang persis sama (asli; seperti file asli). Ya, file.txt asli harus diganti namanya; ini adalah efek tepi "sedikit mengganggu". Sayangnya, saya tidak dapat menemukan cara untuk menyimpan cerita, tetapi untuk TIDAK mengganti nama file sumber (jika ada yang bisa, beri tahu saya!). Namun, git akan menanggung segalanya; sekarang tidak ada yang mau mengganti nama file menjadi komit terpisah:


 git mv $f1 $f git commit -m"split finish, rename $f1 to $f" 

Sekarang file2.txt gilt akan menampilkan riwayat baris yang sama dengan file asli. Hal utama adalah jangan menggabungkan kedua komitmen ini bersama-sama (jika tidak semua sihir akan hilang; saya sudah mencobanya!). Tetapi pada saat yang sama tidak ada yang mengganggu untuk mengedit file secara langsung dalam proses pemisahan; tidak perlu melakukan ini nanti dengan komitmen terpisah. Dan ya, Anda dapat memilih banyak file sekaligus!


Titik kunci dari resep: ganti nama file sumber ke yang lain di komit yang sama, di mana itu dibuat (dan mungkin diedit) salinan (salinan). Dan biarkan komitmen ini hidup di masa depan (itu tidak akan pernah membuat kesalahan dengan penamaan ulang terbalik).


Upd: sepasang resep dari Lissov


Pisahkan bagian repositori histori


Anda berada di versi terbaru dari repositori awal. Tugasnya adalah memisahkan satu folder. (Saya melihat opsi untuk beberapa folder, tetapi lebih mudah dan lebih mudah dipahami untuk melipat semuanya menjadi satu, atau mengulangi beberapa kali berikut.)


Penting! Semua gerakan harus dilakukan dengan perintah git mv , jika tidak git akan kehilangan histori.


Kami melakukan:


 git filter-branch --prune-empty --subdirectory-filter "{directory}" [branch] 

{directory} adalah folder yang harus dipisahkan. Sebagai hasilnya, kami mendapatkan folder beserta riwayat komit hanya untuk itu, yaitu, di setiap komit, hanya file dari folder ini yang ditampilkan. Secara alami, sebagian dari commit akan kosong, --prune-empty menghapusnya.
Sekarang ubah asal:


 git remote set-url origin {another_repository_url}` git checkout move_from_Repo_1 

Jika repositori kedua bersih, Anda bisa langsung ke master. Baiklah, dorong:


 git push -u move_from_Repo_1 

Seluruh cuplikan (untuk mudah disalin-tempel):


 directory="directory_to_extract"; newurl="another_repository_url" git filter-branch --prune-empty --subdirectory-filter "$directory" git remote set-url origin "$newurl" git checkout move_from_Repo_1 git push -u move_from_Repo_1 

Gabungkan dua repositori bersama


Misalkan Anda melakukan sesuatu 2 kali lebih tinggi dan mendapat move_from_Repo_1 dan move_from_Repo_2 , dan di setiap Anda ditransfer file menggunakan git mv ke tempat mereka seharusnya setelah penggabungan. Sekarang tinggal kontrol:


 br1="move_from_Repo_1"; br2="move_from_Repo_2" git checkout master git merge origin/$br1 --allow-unrelated-histories git merge origin/$br2 --allow-unrelated-histories git push 

Seluruh trik ada di --allow-un-related-histories. Sebagai hasilnya, kami mendapatkan satu repositori dengan riwayat lengkap dari semua perubahan.

Source: https://habr.com/ru/post/id424045/


All Articles