Git разделенный подпроект с историей всех веток, слишком большой репозиторий - PullRequest
1 голос
/ 12 февраля 2020

У меня изначально был SVN-репозиторий с несколькими проектами.

Я преобразовал его в GIT -позиторий, используя Sub Git.

Репозиторий:

MyRepository/
    .git/
    Project1/
    Project2/
    Project3/
    ...

Этот репозиторий имеет несколько веток (v1, v2, v3, v4, v5, master).

Я пытаюсь разделить свой репозиторий на несколько репозиториев, сохраняя полную историю и ветви в каждом репозитории. .

Я смог сделать это с помощью этого сценария { ссылка }

#!/bin/bash

repoDir="C:\Sources\MyRepository"
folder="Project1"
newOrigin="https://gitlab.com/myUser/project1.git"

cd $repoDir

git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D

for remote in `git branch --remotes | grep --invert-match "\->"`
do
        git checkout --track $remote
        git add -vA *
        git commit -vam "Changes from $remote" || true
done

git remote remove origin
git filter-branch --prune-empty --subdirectory-filter $folder -- --all

#prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune

#upload to new remote
git remote add origin $newOrigin
git push origin master

for branch in `git branch | grep -v '\*'`
do
        git push origin $branch
done

Это сработало, но теперь хранилище моей подпапки составляет 2,7 ГБ, а текущие файлы имеют размер только 20 МБ.

Я попытался использовать эту команду для отображения больших файлов в хранилище и заметил, что некоторые файлы отсутствуют в моем подпроекте и должны быть удалены:

git rev-list --objects --all \
  | grep "$(git verify-pack -v .git/objects/pack/*.idx \
           | sort -k 3 -n \
           | tail -10 \
           | awk '{print$1}')"

... 
00a2e4e398bd1805ad2524d86276ee72216c1f67 OtherFolder/Distribution/NsiScripts/file.exe
...

Есть ли способ адаптировать скрипт, чтобы удалить все файлы, которые не находятся в моей подпапке, и уменьшить размер? Это то, что сценарий должен был сделать?

Ответы [ 2 ]

0 голосов
/ 03 марта 2020

Наконец, скрипт, который я использовал, работал, но я брал все ветки. И моя папка "Project2" не была в некоторых старых ветвях, поэтому она сохранила все папки для этих веток ...

Так что мне пришлось брать только те ветки, где существует "Project2"

for remote in `git branch --remotes | grep --invert-match "\->\|origin/v1\|origin/v2\|origin/v3"`

А если кто-то попытается сохранить несколько папок при разбиении, это можно сделать с помощью:

git filter-branch --index-filter 'git rm --ignore-unmatch --cached -qr -- . && git reset -q $GIT_COMMIT -- Project1/ Project2/' --prune-empty -- --all
0 голосов
/ 21 февраля 2020

У меня есть проект с библиотекой utils, который начал использоваться в других проектах и ​​хотел разбить его историю на подмодули. Не думал сначала смотреть на SO, поэтому я написал свой, он строит историю локально, так что это немного быстрее, после чего, если вы хотите, вы можете настроить файл .gitmodules вспомогательной команды и тому подобное, и pu sh сами истории подмодулей в любом месте, где вы хотите.

Сама раздетая команда находится здесь, do c в комментариях, в необработанной, которая следует. Запустите его как собственную команду с установленным subdir, например subdir=utils git split-submodule, если вы разбиваете каталог utils. Он взломан, потому что он одноразовый, но я проверял его в подкаталоге Documentation в истории Git.

#!/bin/bash
# put this or the commented version below in e.g. ~/bin/git-split-submodule
${GIT_COMMIT-exec git filter-branch --index-filter "subdir=$subdir; ${debug+debug=$debug;} $(sed 1,/SNIP/d "$0")" "$@"}
${debug+set -x}
fam=(`git rev-list --no-walk --parents $GIT_COMMIT`)
pathcheck=(`printf "%s:$subdir\\n" ${fam[@]} \
    | git cat-file --batch-check='%(objectname)' | uniq`)
[[ $pathcheck = *:* ]] || {
    subfam=($( set -- ${fam[@]}; shift;
        for par; do tpar=`map $par`; [[ $tpar != $par ]] &&
            git rev-parse -q --verify $tpar:"$subdir"
        done
    ))
    git rm -rq --cached --ignore-unmatch  "$subdir"
    if (( ${#pathcheck[@]} == 1 && ${#fam[@]} > 1 && ${#subfam[@]} > 0)); then
        git update-index --add --cacheinfo 160000,$subfam,"$subdir"
    else
        subnew=`git cat-file -p $GIT_COMMIT | sed 1,/^$/d \
            | git commit-tree $GIT_COMMIT:"$subdir" $(
                ${subfam:+printf ' -p %s' ${subfam[@]}}) 2>&-
            ` &&
        git update-index --add --cacheinfo 160000,$subnew,"$subdir"
    fi
}
${debug+set +x}

#!/bin/bash
# Git filter-branch to split a subdirectory into a submodule history.

# In each commit, the subdirectory tree is replaced in the index with an
# appropriate submodule commit.
# * If the subdirectory tree has changed from any parent, or there are
#   no parents, a new submodule commit is made for the subdirectory (with
#   the current commit's message, which should presumably say something
#   about the change). The new submodule commit's parents are the
#   submodule commits in any rewrites of the current commit's parents.
# * Otherwise, the submodule commit is copied from a parent.

# Since the new history includes references to the new submodule
# history, the new submodule history isn't dangling, it's incorporated.
# Branches for any part of it can be made casually and pushed into any
# other repo as desired, so hooking up the `git submodule` helper
# command's conveniences is easy, e.g.
#     subdir=utils git split-submodule master
#     git branch utils $(git rev-parse master:utils)
#     git clone -sb utils . ../utilsrepo
# and you can then submodule add from there in other repos, but really,
# for small utility libraries and such, just fetching the submodule
# histories into your own repo is easiest. Setup on cloning a
# project using "incorporated" submodules like this is:
#   setup:  utils/.git
#
#   utils/.git:
#       @if _=`git rev-parse -q --verify utils`; then \
#           git config submodule.utils.active true \
#           && git config submodule.utils.url "`pwd -P`" \
#           && git clone -s . utils -nb utils \
#           && git submodule absorbgitdirs utils \
#           && git -C utils checkout $$(git rev-parse :utils); \
#       fi
# with `git config -f .gitmodules submodule.utils.path utils` and
# `git config -f .gitmodules submodule.utils.url ./`; cloners don't
# have to do anything but `make setup`, and `setup` should be a prereq
# on most things anyway.

# You can test that a commit and its rewrite put the same tree in the
# same place with this function:
# testit ()
# {
#     tree=($(git rev-parse `git rev-parse $1`: refs/original/refs/heads/$1));
#     echo $tree `test $tree != ${tree[1]} && echo ${tree[1]}`
# }
# so e.g. `testit make~95^2:t` will print the `t` tree there and if
# the `t` tree at ~95^2 from the original differs it'll print that too.

# To run it, say `subdir=path/to/it git split-submodule` with whatever
# filter-branch args you want.

# $GIT_COMMIT is set if we're already in filter-branch, if not, get there:
${GIT_COMMIT-exec git filter-branch --index-filter "subdir=$subdir; ${debug+debug=$debug;} $(sed 1,/SNIP/d "$0")" "$@"}

${debug+set -x}
fam=(`git rev-list --no-walk --parents $GIT_COMMIT`)
pathcheck=(`printf "%s:$subdir\\n" ${fam[@]} \
    | git cat-file --batch-check='%(objectname)' | uniq`)

[[ $pathcheck = *:* ]] || {
    subfam=($( set -- ${fam[@]}; shift;
        for par; do tpar=`map $par`; [[ $tpar != $par ]] &&
            git rev-parse -q --verify $tpar:"$subdir"
        done
    ))

    git rm -rq --cached --ignore-unmatch  "$subdir"
    if (( ${#pathcheck[@]} == 1 && ${#fam[@]} > 1 && ${#subfam[@]} > 0)); then
        # one id same for all entries, copy mapped mom's submod commit
        git update-index --add --cacheinfo 160000,$subfam,"$subdir"
    else
        # no mapped parents or something changed somewhere, make new
        # submod commit for current subdir content.  The new submod
        # commit has all mapped parents' submodule commits as parents:
        subnew=`git cat-file -p $GIT_COMMIT | sed 1,/^$/d \
            | git commit-tree $GIT_COMMIT:"$subdir" $(
                ${subfam:+printf ' -p %s' ${subfam[@]}}) 2>&-
            ` &&
        git update-index --add --cacheinfo 160000,$subnew,"$subdir"
    fi
}
${debug+set +x}
...