Statüko
Kendi deposu repo-old
olan bir alt modüle dönüştürmek istediğimiz bir alt dizini içeren bir depomuz olduğunu varsayalım .sub
repo-sub
Ayrıca, orijinal deponun , önceden var olan alt dizine dokunan tüm taahhütlerin artık çıkarılan alt modül depomuzun karşılık gelen taahhütlerini göstereceği repo-old
değiştirilmiş bir depoya dönüştürülmesi amaçlanmaktadır .repo-new
sub
repo-sub
Hadi değiştirelim
Bunu git filter-branch
iki aşamalı bir süreçte gerçekleştirmek mümkündür:
- Den Alt Dizin çıkarma
repo-old
için repo-sub
(zaten kabul belirtilen cevap )
- Den Alt Dizin yedek
repo-old
için repo-new
(işlemek uygun haritalama ile)
Not : Bu sorunun eski olduğunu biliyorum ve bundan daha önce de belirtildiği gibi git filter-branch
, kullanımdan kaldırılmış ve tehlikeli olabilir. Ancak diğer yandan, dönüştürmeden sonra doğrulanması kolay kişisel havuzlarla başkalarına yardımcı olabilir. Öyleyse uyarılmalıdır ! Ayrıca, kullanımdan kaldırılmadan aynı şeyi yapan ve kullanımı güvenli olan başka bir araç varsa lütfen bana bildirin!
Linux'ta her iki adımı da aşağıdaki 2.26.2 sürümüyle nasıl gerçekleştirdiğimi açıklayacağım. Eski sürümler bir miktar çalışabilir, ancak bunun test edilmesi gerekir.
Basitlik adına, orijinal depoda sadece bir master
şube ve bir origin
uzaktan kumanda olduğu durumla sınırlı kalacağım repo-old
. Ayrıca temp_
, işlem sırasında kaldırılacak ön ekli geçici git etiketlerine güvendiğim konusunda da uyarıda bulunun . Dolayısıyla, benzer şekilde adlandırılmış etiketler varsa, aşağıdaki öneki ayarlamak isteyebilirsiniz. Ve son olarak, bunu kapsamlı bir şekilde test etmediğimi ve tarifin başarısız olduğu bazı köşe durumları olabileceğini lütfen unutmayın. Lütfen devam etmeden önce her şeyi yedekleyin !
Aşağıdaki bash parçacıkları, daha sonra deponun repo-org
yaşadığı aynı klasörde çalıştırılması gereken büyük bir komut dosyası halinde birleştirilebilir . Her şeyi doğrudan bir komut penceresine kopyalayıp yapıştırmanız önerilmez (bunu başarıyla test etmiş olmama rağmen)!
0. Hazırlık
Değişkenler
# Root directory where repo-org lives
# and a temporary location for git filter-branch
root="$PWD"
temp='/dev/shm/tmp'
# The old repository and the subdirectory we'd like to extract
repo_old="$root/repo-old"
repo_old_directory='sub'
# The new submodule repository, its url
# and a hash map folder which will be populated
# and later used in the filter script below
repo_sub="$root/repo-sub"
repo_sub_url='https://github.com/somewhere/repo-sub.git'
repo_sub_hashmap="$root/repo-sub.map"
# The new modified repository, its url
# and a filter script which is created as heredoc below
repo_new="$root/repo-new"
repo_new_url='https://github.com/somewhere/repo-new.git'
repo_new_filter="$root/repo-new.sh"
Komut dosyasını filtrele
# The index filter script which converts our subdirectory into a submodule
cat << EOF > "$repo_new_filter"
#!/bin/bash
# Submodule hash map function
sub ()
{
local old_commit=\$(git rev-list -1 \$1 -- '$repo_old_directory')
if [ ! -z "\$old_commit" ]
then
echo \$(cat "$repo_sub_hashmap/\$old_commit")
fi
}
# Submodule config
SUB_COMMIT=\$(sub \$GIT_COMMIT)
SUB_DIR='$repo_old_directory'
SUB_URL='$repo_sub_url'
# Submodule replacement
if [ ! -z "\$SUB_COMMIT" ]
then
touch '.gitmodules'
git config --file='.gitmodules' "submodule.\$SUB_DIR.path" "\$SUB_DIR"
git config --file='.gitmodules' "submodule.\$SUB_DIR.url" "\$SUB_URL"
git config --file='.gitmodules' "submodule.\$SUB_DIR.branch" 'master'
git add '.gitmodules'
git rm --cached -qrf "\$SUB_DIR"
git update-index --add --cacheinfo 160000 \$SUB_COMMIT "\$SUB_DIR"
fi
EOF
chmod +x "$repo_new_filter"
1. Alt dizin çıkarma
cd "$root"
# Create a new clone for our new submodule repo
git clone "$repo_old" "$repo_sub"
# Enter the new submodule repo
cd "$repo_sub"
# Remove the old origin remote
git remote remove origin
# Loop over all commits and create temporary tags
for commit in $(git rev-list --all)
do
git tag "temp_$commit" $commit
done
# Extract the subdirectory and slice commits
mkdir -p "$temp"
git filter-branch --subdirectory-filter "$repo_old_directory" \
--tag-name-filter 'cat' \
--prune-empty --force -d "$temp" -- --all
# Populate hash map folder from our previously created tag names
mkdir -p "$repo_sub_hashmap"
for tag in $(git tag | grep "^temp_")
do
old_commit=${tag#'temp_'}
sub_commit=$(git rev-list -1 $tag)
echo $sub_commit > "$repo_sub_hashmap/$old_commit"
done
git tag | grep "^temp_" | xargs -d '\n' git tag -d 2>&1 > /dev/null
# Add the new url for this repository (and e.g. push)
git remote add origin "$repo_sub_url"
# git push -u origin master
2. Alt dizin değiştirme
cd "$root"
# Create a clone for our modified repo
git clone "$repo_old" "$repo_new"
# Enter the new modified repo
cd "$repo_new"
# Remove the old origin remote
git remote remove origin
# Replace the subdirectory and map all sliced submodule commits using
# the filter script from above
mkdir -p "$temp"
git filter-branch --index-filter "$repo_new_filter" \
--tag-name-filter 'cat' --force -d "$temp" -- --all
# Add the new url for this repository (and e.g. push)
git remote add origin "$repo_new_url"
# git push -u origin master
# Cleanup (commented for safety reasons)
# rm -rf "$repo_sub_hashmap"
# rm -f "$repo_new_filter"
Not: Yeni oluşturulan depo repo-new
sırasında takılırsa git submodule update --init
, bunun yerine depoyu bir kez yinelemeli olarak yeniden klonlamayı deneyin:
cd "$root"
# Clone the new modified repo recursively
git clone --recursive "$repo_new" "$repo_new-tmp"
# Now use the newly cloned one
mv "$repo_new" "$repo_new-bak"
mv "$repo_new-tmp" "$repo_new"
# Cleanup (commented for safety reasons)
# rm -rf "$repo_new-bak"