Dalam kasus saya, saya memiliki my-pluginrepositori dan main-projectrepositori, dan saya ingin berpura-pura yang my-pluginselalu dikembangkan di pluginssubdirektori darimain-project .
Pada dasarnya, saya menulis ulang sejarah my-pluginrepositori sehingga tampaknya semua pengembangan terjadi di plugins/my-pluginsubdirektori. Kemudian, saya menambahkan sejarah perkembangan my-pluginke dalam main-projectsejarah, dan menggabungkan kedua pohon itu bersama-sama. Karena tidak ada plugins/my-plugindirektori yang ada dimain-project repositori, ini adalah penggabungan tanpa konflik sepele. Repositori yang dihasilkan berisi semua sejarah dari kedua proyek asli, dan memiliki dua akar.
TL; DR
$ cp -R my-plugin my-plugin-dirty
$ cd my-plugin-dirty
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
$ cd ../main-project
$ git checkout master
$ git remote add --fetch my-plugin ../my-plugin-dirty
$ git merge my-plugin/master --allow-unrelated-histories
$ cd ..
$ rm -rf my-plugin-dirty
Versi panjang
Pertama, buat salinan my-pluginrepositori, karena kita akan menulis ulang sejarah repositori ini.
Sekarang, navigasikan ke root my-pluginrepositori, periksa cabang utama Anda (mungkin master), dan jalankan perintah berikut. Tentu saja, Anda harus mengganti my-plugindan pluginsapa pun nama Anda yang sebenarnya.
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
Sekarang untuk penjelasan. git filter-branch --tree-filter (...) HEADmenjalankan (...)perintah di setiap komit yang dapat dijangkau HEAD. Perhatikan bahwa ini beroperasi langsung pada data yang disimpan untuk setiap komit, jadi kami tidak perlu khawatir tentang gagasan "direktori kerja", "indeks", "staging", dan sebagainya.
Jika Anda menjalankan filter-branchperintah yang gagal, itu akan meninggalkan beberapa file di .gitdirektori dan pada saat Anda mencobanya filter-branchakan mengeluh tentang ini, kecuali jika Anda memberikan -fopsi untukfilter-branch .
Adapun perintah yang sebenarnya, saya tidak punya banyak keberuntungan bashuntuk melakukan apa yang saya inginkan, jadi alih-alih saya gunakan zsh -cuntuk membuat zshmenjalankan perintah. Pertama saya mengatur extended_globopsi, yang memungkinkan ^(...)sintaks dalam mvperintah, serta glob_dotsopsi, yang memungkinkan saya untuk memilih dotfile (seperti .gitignore) dengan glob ( ^(...)).
Berikutnya, saya menggunakan mkdir -pperintah untuk membuat kedua pluginsdan plugins/my-pluginpada saat yang sama.
Akhirnya, saya menggunakan fitur zsh"gumpalan negatif" ^(.git|plugins)untuk mencocokkan semua file di direktori root repositori kecuali untuk .gitdan my-pluginfolder yang baru dibuat . (Mengecualikan .gitmungkin tidak diperlukan di sini, tetapi mencoba memindahkan direktori ke dalam dirinya sendiri adalah kesalahan.)
Dalam repositori saya, komit awal tidak termasuk file apa pun, jadi mvperintah mengembalikan kesalahan pada komit awal (karena tidak ada yang tersedia untuk dipindahkan). Karena itu, saya menambahkan || trueagargit filter-branch tidak dibatalkan.
The --allpilihan memberitahu filter-branchuntuk menulis ulang sejarah untuk semua cabang di repositori, dan ekstra --diperlukan untuk memberitahu gituntuk menafsirkannya sebagai bagian dari daftar pilihan untuk cabang untuk menulis ulang, bukan sebagai pilihan untukfilter-branch dirinya sendiri.
Sekarang, navigasikan ke main-projectrepositori Anda dan periksa cabang apa pun yang ingin Anda gabungkan. Tambahkan salinan lokal my-pluginrepositori Anda (dengan riwayatnya diubah) sebagai remote dari main-projectdengan:
$ git remote add --fetch my-plugin $PATH_TO_MY_PLUGIN_REPOSITORY
Anda sekarang akan memiliki dua pohon yang tidak terkait dalam riwayat komit Anda, yang dapat Anda visualisasikan dengan baik menggunakan:
$ git log --color --graph --decorate --all
Untuk menggabungkannya, gunakan:
$ git merge my-plugin/master --allow-unrelated-histories
Perhatikan bahwa pada Pra-2.9.0 Git, --allow-unrelated-historiesopsi tidak ada. Jika Anda menggunakan salah satu versi ini, cukup hapus opsi: pesan kesalahan yang --allow-unrelated-historiesmencegah juga ditambahkan di 2.9.0.
Anda seharusnya tidak memiliki konflik gabungan. Jika Anda melakukannya, itu mungkin berarti bahwa salah satu filter-branchperintah tidak berfungsi dengan benar atau sudah ada plugins/my-plugindirektori di main-project.
Pastikan untuk memasukkan pesan komit penjelas untuk kontributor masa depan yang bertanya-tanya apa peretasan yang terjadi untuk membuat repositori dengan dua root.
Anda dapat memvisualisasikan grafik komit baru, yang seharusnya memiliki dua komit root, menggunakan git logperintah di atas . Perhatikan bahwa hanya mastercabang yang akan digabung . Ini berarti bahwa jika Anda memiliki pekerjaan penting pada my-plugincabang lain yang ingin Anda gabungkan ke dalam main-projectpohon, Anda harus menahan diri dari menghapus my-pluginremote sampai Anda telah melakukan penggabungan ini. Jika tidak, maka komit dari cabang-cabang itu akan tetap berada di main-projectrepositori, tetapi beberapa tidak akan terjangkau dan rentan terhadap pengumpulan sampah akhirnya. (Selain itu, Anda harus merujuknya oleh SHA, karena menghapus remote menghapus cabang-cabang pelacakan jarak jauhnya.)
Secara opsional, setelah Anda menggabungkan semua yang ingin Anda simpan my-plugin, Anda dapat menghapus my-pluginremote menggunakan:
$ git remote remove my-plugin
Anda sekarang dapat dengan aman menghapus salinan my-pluginrepositori yang riwayatnya Anda ubah. Dalam kasus saya, saya juga menambahkan pemberitahuan penghentian ke my-pluginrepositori nyata setelah penggabungan selesai dan didorong.
Diuji pada Mac OS X El Capitan dengan git --version 2.9.0dan zsh --version 5.2. Jarak tempuh Anda mungkin beragam.
Referensi: