Benim durumumda, bir my-plugin
depom ve bir main-project
depom my-plugin
vardı ve her zaman için plugins
alt dizininde geliştirilmiş gibi davranmak istedim main-project
.
Temel olarak, my-plugin
deponun tarihini yeniden yazdım, böylece tüm gelişme plugins/my-plugin
alt dizinde gerçekleşti. Sonra, geliştirilmesi öyküsü eklendi my-plugin
içine main-project
tarih ve birlikte iki ağaç birleşti. plugins/my-plugin
Havuzda zaten bir dizin bulunmadığından main-project
, bu önemsiz bir çatışmasız birleşmeydi. Ortaya çıkan depo, her iki orijinal projeden tüm geçmişi içeriyordu ve iki kökü vardı.
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
Uzun versiyon
İlk olarak, my-plugin
deponun bir kopyasını oluşturun , çünkü bu deponun tarihini yeniden yazacağız.
Şimdi, my-plugin
deponun kök dizinine gidin , ana dalınızı kontrol edin (muhtemelen master
) ve aşağıdaki komutu çalıştırın. Tabii ki, gerçek isimlerinizin yerine my-plugin
ve plugins
ne olursa olsun.
$ 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
Şimdi bir açıklama için. komutu, ulaşılabilir her komutta git filter-branch --tree-filter (...) HEAD
çalıştırır . Bunun doğrudan her bir taahhüt için depolanan veriler üzerinde çalıştığına dikkat edin, bu nedenle "çalışma dizini", "dizin", "aşamalandırma" ve benzeri kavramlar hakkında endişelenmemize gerek yoktur.(...)
HEAD
filter-branch
Başarısız olan bir komut çalıştırırsanız , .git
dizindeki bazı dosyaların arkasında kalır ve bir daha denediğinizde filter-branch
, -f
seçeneği sağlamadığınız sürece bu durumdan şikayet eder filter-branch
.
Gerçek komutu gelince, ben alıyorum çok şans yoktu bash
ne istediğini yapmak için, bunun yerine kullandığım zsh -c
yapmak için zsh
bir komut çalıştırmak. İlk önce komutta sözdizimini extended_glob
sağlayan seçeneği ve bir glob ( ) ile nokta dosyalarını (örneğin ) seçmeme izin veren seçeneği ayarladım .^(...)
mv
glob_dots
.gitignore
^(...)
Sonra, kullandığım mkdir -p
her iki oluşturmak için komut plugins
ve plugins/my-plugin
aynı anda.
Son olarak, deponun kök dizinindeki ve yeni oluşturulan klasör dışındaki tüm dosyaları eşleştirmek için zsh
"negatif glob" özelliğini ^(.git|plugins)
kullanıyorum . (Burada hariç tutmak gerekli olmayabilir, ancak bir dizini kendi içine taşımaya çalışmak bir hatadır.).git
my-plugin
.git
Depomda, ilk işlem herhangi bir dosya içermediğinden, ilk işlemde mv
komut bir hata döndürdü (taşınacak hiçbir şey olmadığından). Bu nedenle, bir katma || true
böylece git filter-branch
değil iptal olur.
--all
Seçenek söyler filter-branch
için tarihi yeniden yazmaya tüm depo şubeleri ve ekstra --
söylemek gerekir git
yerine bir seçenek olarak, yeniden yazma için dalları için seçenek listesinin bir parçası olarak yorumlamak filter-branch
kendisi.
Şimdi main-project
deponuza gidin ve birleştirmek istediğiniz dalı kontrol edin. Deponun yerel kopyasını my-plugin
(geçmişi değiştirilmiş olarak) aşağıdakilerle bir uzaktan kumanda olarak ekleyin main-project
:
$ git remote add --fetch my-plugin $PATH_TO_MY_PLUGIN_REPOSITORY
Artık işlem geçmişinizde, kullanarak güzel bir şekilde görselleştirebileceğiniz iki alakasız ağacınız olacak:
$ git log --color --graph --decorate --all
Bunları birleştirmek için şunu kullanın:
$ git merge my-plugin/master --allow-unrelated-histories
2.9.0 Git'ten önce --allow-unrelated-histories
seçeneğin mevcut olmadığını unutmayın. Bu sürümlerden birini kullanıyorsanız, seçeneği atlamanız yeterlidir: --allow-unrelated-histories
önleyen hata mesajı 2.9.0'da da eklenmiştir.
Herhangi bir birleştirme çatışması olmamalıdır. Bunu yaparsanız, muhtemelen filter-branch
komutun düzgün çalışmadığı veya zaten bir plugins/my-plugin
dizin olduğu anlamına gelir main-project
.
Gelecekteki katkıda bulunanlar için, iki köklü bir depo yapmak için neler olduğunu merak eden açıklayıcı bir taahhüt mesajı girdiğinizden emin olun.
Yukarıdaki git log
komutu kullanarak, iki kök işleme sahip olması gereken yeni tamamlama grafiğini görselleştirebilirsiniz . O Not sadece master
dal birleştirilecektir . Bu my-plugin
, main-project
ağaca birleştirmek istediğiniz diğer dallar üzerinde önemli çalışmalarınız my-plugin
varsa, bu birleştirmeleri yapana kadar uzaktan kumandayı silmekten kaçınmanız gerektiği anlamına gelir . Bunu yapmazsanız, bu şubelerden gelen taahhütler yine de main-project
depoda olacaktır, ancak bazılarına ulaşılamayacak ve nihai çöp toplamaya duyarlı olacaktır. (Ayrıca, uzaktan kumandanın silinmesi uzaktan izleme dallarını kaldırdığından onlara SHA tarafından başvurmanız gerekecektir.)
İsteğe bağlı olarak, saklamak istediğiniz her şeyi birleştirdikten sonra uzaktan kumandayı aşağıdakileri kullanarak my-plugin
kaldırabilirsiniz my-plugin
:
$ git remote remove my-plugin
Artık my-plugin
geçmişini değiştirdiğiniz deponun kopyasını güvenle silebilirsiniz . Benim durumumda, my-plugin
birleştirme işlemi tamamlandıktan ve itildikten sonra gerçek depoya bir kullanımdan kaldırma bildirimi ekledim .
Mac OS X El Capitan üzerinde git --version 2.9.0
ve ile test edilmiştir zsh --version 5.2
. Kilometreniz değişebilir.
Referanslar: