Bagaimana cara memindahkan satu direktori dari repositori git ke repositori baru sambil mempertahankan riwayat?

110

Saya telah mewarisi repositori git yang berisi banyak proyek dalam direktori terpisah. Saya ingin membagi repositori menjadi repositori individu baru, satu untuk setiap proyek dan kemudian memiliki repositori master berisi proyek-proyek sebagai submodul. Saya ingin melakukan semua ini sambil mempertahankan riwayat revisi masing-masing proyek jika memungkinkan.

Saya bisa mengkloning repositori untuk setiap proyek dan menghapus semua proyek lain setiap saat, tetapi apakah ada cara yang lebih baik untuk menghindari riwayat kloning di setiap repositori proyek baru?

cidered
sumber
2
Menambahkan tag git-submodules karena ini sangat berguna untuk mengubah bagian repo menjadi submodul.
idbrii
Kemungkinan duplikat dari subpohon Ekspor di Git dengan riwayat
pengguna

Jawaban:

99

Anda dapat menggunakan git filter-branchuntuk menulis ulang sejarah proyek. Dari dokumentasi:

Untuk menulis ulang repositori agar terlihat seolah-olah foodir / telah menjadi root proyeknya, dan buang semua histori lainnya:

git filter-branch --subdirectory-filter foodir -- --all

Buat beberapa salinan repo Anda, lakukan itu untuk setiap subdirektori yang ingin Anda pisahkan, dan Anda akan mendapatkan apa yang Anda cari.

Brian Campbell
sumber
1
Bagaimana jika saya ingin mengecualikan foodir, dan menghapus semua sejarahnya?
saeedgnu
1
Catatan: jika Anda menginginkan beberapa direktori, Anda perlu menentukan --subdirectory-filterbeberapa kali. EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardir, dll. Tidak --subdirectoryakan mengambil banyak direktori, tetapi dapat ditentukan beberapa kali.
EnabrenTane
3
@Adam Jika Anda ingin menyimpan riwayat foodirdalam proyek asli, tidak menulis ulang riwayatnya, git rm -r foodirsebaiknya cukup (itu juga akan menghapus salinan di pohon kerja Anda; jika Anda tidak menginginkannya, gunakan --cached). Jika Anda ingin menghapus seluruhnya dari riwayat (menjawab pertanyaan @ ilius juga), Anda menginginkan sesuatu sepertigit filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell
2
@ilius Maaf saya melewatkan pertanyaan Anda sebelumnya, lihat balasan saya di atas untuk jawaban tentang cara menghapus direktori dan riwayatnya.
Brian Campbell
2
@ilius Yap, itu juga berfungsi. Untuk proyek besar, --index-filtersolusinya lebih cepat daripada --tree-filter, karena tidak harus benar-benar memeriksa file, itu hanya dapat memanipulasi indeks secara langsung. Namun, --tree-filterini bisa sedikit lebih mudah digunakan, karena Anda dapat menggunakan operasi filsystem biasa daripada harus bekerja dengan operasi manipulasi indeks.
Brian Campbell
4

Untuk mengekspor folder sebagai repositori baru, Anda memerlukan:

  1. Untuk mengkloning repositori tempat folder yang ingin Anda ekspor berada.
  2. Untuk membuat repositori kosong di penyedia hosting Anda sebagai GitHub, untuk menyimpan folder yang diekspor.
  3. Buka folder repositori kloning dan jalankan perintah ini:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    
pengguna
sumber
1
git subtreetidak tersedia sebagai paket Cygwin. Jika Anda membutuhkannya: stackoverflow.com/a/27116828/2484903
Jack Miller
2

Inti dari git adalah bahwa sejarah diwujudkan dalam setiap komit dengan melakukan hashing pada komit induk. Anda dapat "memutar ulang" komit (pada dasarnya ini adalah cara kerja svn-importer) ke dalam repositori baru dan hanya menyimpan setiap sub-proyek. Ini, bagaimanapun, akan menghancurkan arti dari hash komit. Jika Anda tidak memiliki masalah dengan itu maka biarlah.

Di masa lalu saya baru saja mengkloningnya dan melanjutkan. Hal ini membuat segalanya lebih besar tetapi ruang disk murah; waktu saya mahal.

Saya juga tidak tahu alat apa pun untuk memisahkan direktori. Saya kira Anda bisa git-log di direktori untuk menemukan semua komit di dalamnya lalu memutar ulang komit dengan sesuatu seperti git-fast-export?

Colin Burnett
sumber
Saya memberi suara positif karena ini karena tidak pantas menjadi negatif - saya pasti tidak akan mengikuti pendekatan ini tetapi saya dapat melihat dia mencoba
Alvin