2016-07-04 1 views
2

Мое требование: Разбить один репозиторий git на несколько репозиториев git, сохраняя ту же структуру каталогов, что и в исходном репо, и сохранить историю фиксации для файлы, которые копируются в новое репо. То, что я уже пробовал:Скопируйте несколько файлов и каналов из одного git-репо в другой, сохраняя при этом свою первоначальную историю.

  1. Сначала я попытался мерзавец фильтр-ветви --subdirectory фильтр на основе предложений в http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/ Результат: История сохраняется, но можно увидеть только на управлении git log --follow Кроме того, оригинальная история фиксации не может быть видна на Github. Он просто отображает мою фиксацию слияния как единственную фиксацию для этого файла и не отображает никаких предыдущих коммитов. Я все еще могу жить с этим ограничением и принимать его в качестве решения. Но другое беспокойство, которое я испытываю при таком подходе, заключается в том, что для каждой папки и каждого файла, который я хочу скопировать, мне нужно клонировать исходное репо несколько раз, а также повторять все эти 12 или 13 шагов каждый раз. Я хотел бы знать, есть ли более простой способ сделать это, так как я перемещаю много файлов. Кроме того, поскольку должность 5 лет, просто интересно, доступны ли более простые решения? (Удивительно Google в основном показывает этот блог в качестве первого результата поиска)

  2. Следующая вещь, которую я попробовал, был комментарий на ранее пост Greg Байера http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/#comment-2685894846 Это решение сделало вещи немного проще, используя GIT поддерево разделить но результаты были такими же, как указано в первом случае.

  3. Затем я попробовал журнал мерзавец --patch-с-стат и мерзавца я вариант, основанный на этот ответ https://stackoverflow.com/a/11426261/5497551 Результат: Это обычно дает ошибки при встрече слияния, при применении патча. Я пробовал одно из предложений по этому вопросу: -m --first-parent Это разрешило ошибки, но не расширяет никаких слияний с их коммитами, просто перечисляет слияние как единое целое. Следовательно, большая часть истории фиксации теряется. Итак, я добавил еще одну опцию - 3way. Это продолжалось снова и снова через коммиты и не приводило к приемлемому решению.

В заключение, я предпочел бы использовать 3-го решения, если только там была возможность иметь все коммиты в слиянии должны быть перечислены в истории нового репо. Иначе я должен придерживаться первого решения, которое немного неудобно и утомительно в моей ситуации. Любые советы, помощь будут очень признательны.

Спасибо.

+0

', а также сохранить фиксации истории для всех files' - так просто удалить биты вы не хотите сохранить? Вы можете найти это полезным: [Новое репо с копией истории только отслеживаемых файлов] (http://stackoverflow.com/a/17909526/761202). – AD7six

+0

Спасибо. Когда вы говорите «удаляйте все и просто восстанавливайте файлы, которые хотите сохранить»: можете ли вы помочь мне понять, на каком этапе мы восстанавливаем файлы, которые я хочу сохранить? Потому что keep-these.txt будет иметь список всех файлов, присутствующих в текущем репо? Или я должен сначала удалить ненужные файлы, а затем сделать git ls-files> keep-these.txt'? Я довольно новичок в git, поэтому не очень хорошо разбираюсь во всех его концепциях. – neel

+0

Пожалуйста, отредактируйте свой вопрос, чтобы быть понятным. непонятно из описания вопроса, почему 'git rm somefolder; git commit -m «удаление некоторой папки» 'не делает того, что вы хотите - вы специально просите сохранить историю фиксации для _all_ файлов; также быть конкретным с тем, что у вас есть, и тем, что вы ожидаете в результате; поместите папки/файлы верхнего уровня в вопрос - и чего вы хотите достичь. – AD7six

ответ

3

Вот что сработало для меня (сочетая ответы от @ AD7six и @Olivier), чтобы разделить мой orig-repo на несколько новых репозиториев. Я перечисляю здесь шаги для создания только одного нового репо new-repo1. Но то же самое было использовано и для создания других.

Сначала создайте новый пустой репозиторий на Github с именем new-repo1

git clone [Github url of orig-repo] 

git clone --no-hardlinks orig-repo new-repo1 
cd new-repo1 
git remote rm origin 
git checkout -b master //This step can be skipped. I had to do it since the default branch on my orig-repo was `develop`, but on the new-repo1 I wanted to create it as `master` 

//I used a script here to delete files and directories not required in the new-repo1. 
//But if you have very few files/dirs to be deleted then you can do the below. 
git rm <path of file 1 to be deleted> 
git rm <path of file 2 to be deleted> 
git rm -rf <path of dir 1 to be deleted> 

git commit -m "Deleted non-new-repo1 code" 

git ls-files > keep-these.txt 
git filter-branch --force --index-filter "git rm --ignore-unmatch --cached -qr . ; cat $PWD/keep-these.txt | xargs git reset -q \$GIT_COMMIT --" --prune-empty --tag-name-filter cat -- --all 

rm -rf .git/refs/original/ 
git reflog expire --expire=now --all 
git gc --prune=now 

git init 
git remote add origin [Github url of new-repo1] 
git push -u origin master 

После этого, я могу просмотреть историю файлов в new-repo1 на Github, а также с помощью командной строки, используя git log

0

С помощью метода 1 вы клонируете локальный каталог или URL-адрес? Если вы клонируете из локального каталога, вы должны использовать опцию --no-hardlinks. В противном случае то, что вы делаете в одном клоне, может повлиять на каталоги .git других, потому что git файлы с жесткой привязкой.

Вот как я это делаю:

  • Clone локальный репозиторий:

    git clone --no-hardlinks source_repo detached_repo 
    
  • В detached_repo, удалить происхождение (больше информации here для сохранения отличных от текущей ветви):

    git remote rm origin 
    
  • Удалить теги, которые вы не хотите хранить. Чтобы удалить все теги, используйте git tag -l | xargs git tag -d

  • Используйте ветвь фильтра, чтобы исключить другие файлы, чтобы их можно было обрезать. Давайте также добавить --tag-name-filter cat --prune-empty удалить пустые фиксации и переписать тег (более подробной информации here если у вас есть несколько ветвей, чтобы держать):

    git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter folder/to/keep HEAD 
    
  • Затем удалите резервную копию reflogs поэтому пространство может быть действительно утилизирован (теперь операция деструктивный):

    git reset --hard 
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d 
    git reflog expire --expire=now --all 
    git gc --aggressive --prune=now 
    

    и теперь у вас есть локальный репозиторий в folder/to/keep подкаталоге со всеми его истории сохранились.

EDIT

Так как вам нужно держать более одного подкаталог, я буду считать, что у вас есть список файлов, чтобы сохранить в файле с именем files_to_keep. Затем измените git filter-branch шаг:

git filter-branch --tag-name-filter cat --prune-empty \ 
    --index-filter 'git ls-tree -z -r --name-only --full-tree $GIT_COMMIT \ 
    | grep -z -v -F -f /absolute/path/to/files_to_keep \ 
    | xargs -0 -r git rm --cached -r' HEAD 

Вы можете создать список файлов, чтобы сохранить, выполнив команду:

git log --pretty=format: --name-status | cut -f2- | sort -u > all_files 

и удаление файлов, которые вы не хотите сохранить.

+0

Спасибо за ваш ответ. Но мое требование состоит в том, чтобы сохранить несколько папок и файлов в новом репо, а не только одну папку/в/сохранить. Можете ли вы изменить это решение? – neel

+0

Кроме того, в конце концов, как я могу создать новое репо Github из 'detached_repo'? Будет ли использовать параметр «--no-hardlinks» и шаги очистки, чтобы я мог сделать «git init» на 'detached_repo' и направить его как новый репо на Github? Также я хочу пояснить, что эти шаги не изменят исходное репо каким-либо образом, то есть его файлы и история остаются неизменными? – neel

+0

Хорошо, я получил ответ на свой второй комментарий. Я сделал 'git init', затем' remote add origin '' git push -u origin develop'. – neel

0

Для таких сценарий, который можно попробовать дать git-import.

Он в основном создает исправления из данного файла или каталога ($object) одного репо и применяет их к другому, сохраняя историю.

cd old_repo 
git format-patch --thread -o "$temp" --root -- "$object" 

Эти патчи затем получить применяется к новому хранилищу:

cd new_repo 
git am "$temp"/*.patch 

(. Эта процедура может быть повторена для различных частей старого хранилища в случае необходимости)

Для получения дополнительной информации, пожалуйста, смотрите вверх :

Смежные вопросы