Объединение двух хранилищ git для получения линейной истории

У меня есть два репозитория git и много нереакционных изменений между ними:

   ftp -->            C-- (untracked changes) --D
                     /                           \
   git        A--B--C <-- old/master              \
                                                   \
                                                    \
                                  new/master -->     D--E--F 

Как я могу объединить старый репозиторий в новый репозиторий с линейной историей, например

A--B--C--D--E--F

EDIT:

вдохновленный Как объединить хранилища git в линейную историю?

Я сделал:

git clone url://new new
cd new/
git remote add old url://old
git fetch old
git reset --hard origin/master
git filter-branch --parent-filter 'sed "s_^\$_-p old/master_"' HEAD
git push origin master

Единственная проблема заключается в том, что каждая фиксация из нового /master была удвоена (из-за изменения родителя, я думаю), поэтому я теперь (M - фиксация слияния)

         D---E---F--         
                    \
A--B--C--D'--E'--F'--M 

Как я могу легко удалить ненужные коммиты (D - F и, возможно, M)?

Ответ 1

Просто проверьте свою ветку и запустите:

  git reset --hard **SHA-OF-F'**

Это удалит M и D - F из вашей ветки.

Ответ 2

Фиксация результатов git filter-branch

Если у вас есть репозиторий, который выглядит так:

         D---E---F--
                    \
A--B--C--D'--E'--F'--M <-master

и вы хотите, чтобы результат выглядел следующим образом:

A--B--C--D'--E'--F' <-master

то вы можете просто заставить master указать на F':

git checkout master
git reset --hard <sha1-of-F'>

Это приведет к тому, что commits D, E, F и M станут недоступными, эффективно удаляя их (через некоторое время они будут собираться мусором).

Начиная с нуля

Предполагая, что у вас есть два репозитория, которые выглядят следующим образом:

  • old: A--B--C <-master
  • new: D--E--F <-master

и вы хотите получить результат:

  • в сочетании: A--B--C--D'--E'--F' <- master

вы можете выполнить следующие шаги:

  • Инициализируйте репозиторий combined:

    git init combined
    cd combined
    git remote add old url:/to/old
    git remote add new url:/to/new
    git remote update
    

    В этот момент ваш репозиторий combined выглядит так:

    A--B--C <-old/master
    
    D--E--F <-new/master
    

    Обратите внимание, что две ветки не связаны каким-либо образом.

  • Установите ветку master, чтобы указать на C:

    git reset --hard old/master
    

    Теперь ваш репозиторий выглядит следующим образом:

          old/master
          |
          v
    A--B--C <-master
    
    D--E--F <-new/master
    
  • Найдите sha1 D:

    d=$(git rev-list --reverse new/master | head -n 1)
    
  • Импортируйте D в свой рабочий каталог и индексируйте, прочитав содержимое комманды

    git read-tree -u --reset $d
    
  • передать содержимое D с использованием того же сообщения фиксации, автора, даты и т.д. в качестве исходного D commit:

    git commit -C $d
    

    Теперь ваш репозиторий выглядит следующим образом:

          old/master
          |
          v
    A--B--C--D' <-master
    
    D--E--F <-new/master
    
  • вишня - выберите остальные коммиты:

    git cherry-pick $d..new/master
    

    Теперь ваш репозиторий выглядит следующим образом:

          old/master
          |
          v
    A--B--C--D'--E'--F' <-master
    
    D--E--F <-new/master
    
  • Очистка:

    git remote rm old
    git remote rm new
    

    Теперь ваш репозиторий выглядит следующим образом:

    A--B--C--D'--E'--F' <-master
    

Ответ 3

Если ftp не является правильной ветвью и просто заданием копирования, это может работать для вас

cd git
git rm -r .
cp -r ../ftp/. .
git add
git commit

Ответ 4

Ну, я не уверен, в чем проблема. Но я должен удалить одну ветку, содержащую копию. Эти коммиты не нужны и, вероятно, исчезнут при удалении ветки. Если они удваиваются в одном и том же дереве, вы всегда можете использовать git rebase на свой страх и риск.

делать что-то вроде

git rebase -i HEAD~5

Откроет редактор с помощью вещей, которые вы можете сделать. Если вы удалите строку с фиксацией, она удалит ее из дерева, вы можете скворовать фиксацию вместе и т.д. Если вы сохраните пустой файл, он ничего не сделает.

Тем не менее, имейте в виду, что после такой перезагрузки главная ветка не будет быстрой перемоткой вперед, и вам придется переопределить главную ветвь на сервере. Заставляя толчок. Другими словами, убедитесь, что переформатирован правильно, и после нажатия новой ветки все будут синхронизироваться в этой ветке. Если у кого-то есть хозяин и попытаться нажать, и это не поможет, это может ухудшить ситуацию.

Git rebase - это как повторение истории фиксации. Удаление фиксации больше похоже на пропущенное изменение. Если вы пропустите фиксацию, которая удваивается, это не будет иметь никакого эффекта. Но каждая фиксация будет иметь другой shasum, а также означает, что ветвь расходится с исходным мастером.

В любом случае, прежде чем делать что-либо, сохраните sha1 мастера, а затем, если что-то пойдет не так, вы всегда можете проверить владельца на фиксацию, пока нет сбора мусора.

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