Перемещение части истории git-репозитория в другой репозиторий - PullRequest
5 голосов
/ 21 февраля 2011

Здесь много сообщений о перемещении папки из одного репозитория в новый репозиторий с использованием git filter-branch;мне нужно переместить один файл в новый репозиторий.

Я уже создал новый репозиторий и добавил старый из файловой системы как «удаленный».и создал новый «корневой коммит» (просто добавив README для нового однофайлового проекта.) Теперь мне нужно перенести коммиты, относящиеся к этому конкретному файлу, на этот новый root-коммит.

(мне следуетОтметим, что ни в коем случае этот файл не изменялся в том же коммите, что и любые другие файлы; я подозреваю, что это может немного облегчить эту задачу.)

Ответы [ 4 ]

5 голосов
/ 21 февраля 2011

Это основано на примере в странице-ветке фильтра :

git filter-branch --index-filter 'git ls-files -s | grep $'\t'<file-to-keep>$ | \
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --prune-empty -- --all

Фильтр индекса печатает текущее содержимое индекса с помощью git ls-files -s, выдает толькофайл для хранения (этот grep довольно навязчивый - поля разделены табуляцией, а имя файла - последним), затем создает новый индекс, используя эту информацию, и перемещает его поверх старого.

Опция --prune-empty заставляет filter-branch удалять любые коммиты, которые теперь ничего не делают (т. Е. Они только касались других файлов), а -- --all говорит ему переписать все ссылки.

Как всегда с filter-ветвь, лучше всего сделать это в новом клоне, так что если вы действительно что-то испортили, вы в безопасности, хотя filter-branch сохраняет резервные копии в ссылках / оригиналах.Вы также можете прочитать контрольный список для сокращения хранилища на странице руководства;В результате, как только вы закончите, лучший способ избавиться от всего, что вам больше не нужно, - просто клонировать отфильтрованный репозиторий.

Это на самом деле будет работать, даже если файл был изменен вте же самые коммиты, что и в других файлах, хотя я полагаю, что вы можете попытаться быть хитрым и воспользоваться этим фактом, просто сгенерировав патчи для всех коммитов, которые коснулись этого файла *, затем перейдите и создайте новый репозиторий, применивэти патчи ... но зачем?

(Примечание: гораздо проще удалить отдельный файл, чем сохранить один файл. Все, что вам нужнов этом случае используйте git rm --cached --ignore-unmatch <filename> для индексного фильтра.)

2 голосов
/ 05 февраля 2013

Решение в другом ключе - добавьте старый репозиторий в качестве другого пульта дистанционного управления, и тогда могут работать rebase и cherry-pick.

git clone old_repo
git clone new_repo
cd new_repo
git remote add temp_repo old_repo
git fetch temp_repo

# bring the changed from old_repo into new_repo
git rebase --onto <...> temp_repo/master
OR
git cherry-pick [list of relevant commits]

git remote rm temp_repo
git push origin HEAD
2 голосов
/ 27 февраля 2011

В итоге я использовал ответы из этого (иначе неуместного) поста для построения решения. Вместо того, чтобы переходить в дерево с новым корнем, я изменил старый корень и --onto переназначил содержимое на новый корень:

Можно ли удалить начальный коммит из репозитория Git?

0 голосов
/ 28 марта 2014

Перепробовав различные подходы для перемещения файла или папки из одного Git-репозитория в другой, единственный, который, кажется, работает надежно, описан ниже.

Это включает в себя клонирование репозитория, из которого вы хотите переместить файл или папку, перемещение этого файла или папки в корень, переписывание истории Git, клонирование целевого репозитория и перенос файла или папки с историей непосредственно в этот целевой репозиторий.

Первый этап

  1. Сделайте копию хранилища A, так как следующие шаги делают основной изменения в этой копии, которые вы не должны нажимать!

    git clone --branch <branch> --origin origin --progress -v <git repository A url>
    eg. git clone --branch master --origin origin --progress -v https://username@giturl/scm/projects/myprojects.git
    

    (при условии, что myprojects - это хранилище, из которого вы хотите скопировать)

  2. CD в него

    cd <git repository A directory>          eg. cd /c/Working/GIT/myprojects
    
  3. Удалить ссылку на исходный репозиторий, чтобы избежать случайного внесение любых удаленных изменений (например, нажатием)

    git remote rm origin
    
  4. Просматривайте свою историю и файлы, удаляя все, что не находится в каталог 1. В результате содержимое каталога 1 извергается на базу хранилища А.

    git filter-branch --subdirectory-filter <directory> -- --all
    eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
    
  5. Только для перемещения одного файла: пройдите через то, что осталось, и удалите все, кроме желаемого файла. (Вам может понадобиться удалить файлы вы не хотите с тем же именем и коммитом.)

    git filter-branch -f --index-filter \
    'git ls-files -s | grep $'\t'FILE_TO_KEEP$ |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
    git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE || echo "Nothing to do"' --prune-empty -- --all
    

    например. FILE_TO_KEEP = pom.xml, чтобы сохранить только файл pom.xml из FOLDER_TO_KEEP

Второй этап

  1. Шаг очистки

    git reset --hard
    
  2. Шаг очистки

    git gc --aggressive
    
  3. Шаг очистки

    git prune
    

Возможно, вы захотите импортировать эти файлы в хранилище B в каталоге, а не в корне:

  1. Сделать этот каталог

    mkdir <base directory>             eg. mkdir FOLDER_TO_KEEP
    
  2. Переместить файлы в этот каталог

    git mv * <base directory>          eg. git mv * FOLDER_TO_KEEP
    
  3. Добавить файлы в этот каталог

    git add .
    
  4. Передайте ваши изменения, и мы готовы объединить эти файлы в новый репозиторий

    git commit
    

стадия три

  1. Сделайте копию хранилища B, если у вас ее еще нет

    git clone <git repository B url>
    eg. git clone https://username@giturl/scm/projects/FOLDER_TO_KEEP.git
    

    (при условии, что FOLDER_TO_KEEP - это имя нового репозитория, в который вы копируете)

  2. CD в него

    cd <git repository B directory>          eg. cd /c/Working/GIT/FOLDER_TO_KEEP
    
  3. Создать удаленное соединение с хранилищем A как ответвление в хранилище B

    git remote add repo-A-branch <git repository A directory>
    

    (repo-A-branch может быть любым - это просто произвольное имя)

    eg. git remote add repo-A-branch /c/Working/GIT/myprojects
    
  4. Извлечь из этой ветви (содержит только каталог, который вы хотите переместить) в хранилище Б.

    git pull repo-A-branch master
    

    Пул копирует как файлы, так и историю. Примечание: вы можете использовать слияние вместо вытягивания, но вытягивание работает лучше.

  5. Наконец, вы, вероятно, хотите немного почистить, удалив пульт подключение к хранилищу A

    git remote rm repo-A-branch
    
  6. Нажмите и все готово.

    git push
    
...