Büyük Git deposunu birçok küçük depoya bölün


86

Bir SVN deposunu Git'e başarıyla dönüştürdükten sonra, artık birden çok küçük depoya bölmek ve geçmişi korumak istediğim çok büyük bir Git deposuna sahibim.

Öyleyse, birisi şuna benzeyen bir depoyu kırmaya yardımcı olabilir mi:

MyHugeRepo/
   .git/
   DIR_A/
   DIR_B/
   DIR_1/
   DIR_2/

Aşağıdaki gibi görünen iki depoya:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/

Bu önceki sorudaki talimatları izlemeyi denedim, ancak birden çok dizini ayrı bir depoya koymaya çalışırken gerçekten uymuyor ( Alt dizini ayrı Git deposuna ayır (taşı )).


11
Bir cevaptan memnun olduğunuzda, lütfen cevap olarak işaretleyin.
Ben Fowler

1
Birden çok (iç içe geçmiş) dizini yeni bir depoya bölmek isteyenler için (bazı projelerde daha zor olabilecek birden çok dizini kaldırmak yerine) bu yanıt benim için yararlı oldu: stackoverflow.com/a/19957874/164439
thaddeusmt

Yanıtlar:


80

Bu MyABRepo'yu kuracaktır; Elbette benzer şekilde My12Repo'yu da yapabilirsiniz.

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 

.Git / refs / original / refs / Heads / master referansı kalır. Bunu şu şekilde kaldırabilirsiniz:

cd ..
git clone MyABRepo.tmp MyABRepo

Her şey yolunda giderse, MyABRepo.tmp dosyasını kaldırabilirsiniz.


Herhangi bir nedenle .git-rewrite ile ilgili bir hata alırsanız, şunu deneyebilirsiniz:

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch -d /tmp/git-rewrite.tmp --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 
cd ..
git clone MyABRepo.tmp MyABRepo

Bu, /tmp/git-rewrite.tmp yerine geçici bir dizin olarak oluşturur ve kullanır .git-rewrite. Doğal olarak, /tmp/git-rewrite.tmpyazma izniniz olduğu ve dizin zaten mevcut olmadığı sürece, bunun yerine istediğiniz herhangi bir yolu değiştirebilirsiniz .


'git filter-branch' manpage, yukarıda bahsedilen son adım yerine yeniden yazılmış deponun yeni bir klonunu oluşturmanızı önerir.
Jakub Narębski

Bunu denedim ve sonunda .git-rewrite klasörünü silmeye çalışırken bir hata aldım.
MikeM

-d <path-on-another-physical-disk> benim için çalıştı ve --tree-filter içindeki stange 'mv' hatalarını ortadan kaldırdı.
Vertigo

Dışarıda bırakılan bir yolla ( DIR_Aörneğin) ilgili ise, ilk taahhüdü nasıl çıkaracağınız konusunda bir fikriniz var mı?
2013

1
Tam sonuçlarını fark etmemiştim filter-branch. Farkında olmayanlar için tarihi yeniden yazıyor, bu yüzden bunu yaptıktan sonra repoyu zorlamayı planlıyorsanız, commit hashleri ​​şimdi farklı olacak ve çalışmayacaktır.
thaddeusmt

10

Orijinal deponuzun klonlarından / kopyalarından istenmeyen dizinleri silmek için git filter-branch --index-filterile kullanabilirsiniz git rm --cached.

Örneğin:

trim_repo() { : trim_repo src dst dir-to-trim-out...
  : uses printf %q: needs bash, zsh, or maybe ksh
  git clone "$1" "$2" &&
  (
    cd "$2" &&
    shift 2 &&

    : mirror original branches &&
    git checkout HEAD~0 2>/dev/null &&
    d=$(printf ' %q' "$@") &&
    git for-each-ref --shell --format='
      o=%(refname:short) b=${o#origin/} &&
      if test -n "$b" && test "$b" != HEAD; then 
        git branch --force --no-track "$b" "$o"
      fi
    ' refs/remotes/origin/ | sh -e &&
    git checkout - &&
    git remote rm origin &&

    : do the filtering &&
    git filter-branch \
      --index-filter 'git rm --ignore-unmatch --cached -r -- '"$d" \
      --tag-name-filter cat \
      --prune-empty \
      -- --all
  )
}
trim_repo MyHugeRepo MyABRepo DIR_1 DIR_2
trim_repo MyHugeRepo My12Repo DIR_A DIR_B

Her bir deponun gereksiz dallarını veya etiketlerini manuel olarak silmeniz gerekecektir (örn. Bir özellik-x-for-AB dalınız varsa, muhtemelen bunu “12” havuzundan silmek istersiniz).


1
:bash'da bir açıklama karakteri değildir. Bunun #yerine kullanmalısınız .
Daenyth

4
@Daenyth, :geleneksel bir yerleşik komuttur ( POSIX'te de belirtilmiştir ). Bash'e dahildir , ancak bir yorum değildir. Tercihen bunu özellikle kullandım #çünkü tüm kabuklar #tüm bağlamlarda bir yorum tanıtıcısı olarak kabul edilmiyor (örn . INTERACTIVE_COMMENTS seçeneği etkinleştirilmeden etkileşimli zsh ). Kullanmak :, metnin tamamını herhangi bir etkileşimli kabuğa yapıştırmanın yanı sıra bir komut dosyasına kaydetmeye uygun hale getirir.
Chris Johnsen

1
Parlak! Tüm dalları sağlam tutan tek çözüm buldum
pheelicks

Onunla durur benim için Tek, git remote rm originher zaman 1. dönmek gibi görünüyor Dolayısıyla ben değiştirilir &&tarafından ;bu hat için.
kynan

Güzel, $ @ gerektiğinde ikiden fazla dizin için çalışır. Bitirince ararım git remote add origin $TARGET; git push origin master.
Walter

7

Git_split projesi, tam olarak aradığınız şeyi yapan basit bir betiktir. https://github.com/vangorra/git_split

Git dizinlerini kendi konumlarında kendi depolarına dönüştürün. Alt ağaç komik işler yok. Bu komut dosyası git deponuzdaki mevcut bir dizini alacak ve bu dizini kendi başına bağımsız bir depoya dönüştürecektir. Yol boyunca, sağladığınız dizinin tüm değişiklik geçmişini kopyalar.

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to push to.


1

Cevaplarınız için teşekkürler, ancak depoyu iki kez kopyaladım ve ardından her birinden istemediğim dosyaları sildim. Daha sonraki bir tarihte filtre dalını, silinen dosyalar için tüm taahhütleri çıkarmak için kullanacağım çünkü bunlar zaten başka bir yerde sürüm kontrollüdür.

cp -R MyHugeRepo MyABRepo
cp -R MyHugeRepo My12Repo

cd MyABRepo/
rm -Rf DIR_1/ DIR_2/
git add -A
git commit -a

Bu ihtiyacım olan şey için çalıştı.

DÜZENLEME: Tabii ki aynı şey My12Repo'da A ve B dizinine karşı yapıldı. Bu bana istenmeyen dizinleri sildiğim noktaya kadar aynı geçmişe sahip iki depo verdi.


1
Bu, taahhüt tarihini korumaz.
Daenyth

nasıl yani? Silinen dosyalar için bile hala tüm geçmişe sahibim.
MikeM

1
İhtiyacınız repo A'nın repo B'nin hiç var olmadığını varsayması gerektiği için, bence bu (sadece B'yi etkileyen taahhütlerin kaydını bırakarak) uygun bir çözüm. Biraz tarihi kopyalamak onu karıştırmaktan daha iyidir.
Steve Clay
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.