2016-12-30 2 views
1

У меня есть репозиторий Git с двумя основными ветвями: master и dev. В настоящее время она выглядит следующим образом:Git rebase/merge branch со многими перемещенными файлами и папками

master ()----()----(A)----(B)----(C) 
       \ 
       \ 
dev    ()----()----()----()----(~ 30 additional commits...) 

Довольно просто, за исключением того, что совершает на мастер содержат значительные изменения в структуру файлов и папок (в основном, я использовал the steps shown here для перемещения хранилища на один уровень вверх в иерархии).

Я хотел бы возобновить работу над веткой dev, но когда я попытался переустановить dev на master, чтобы принести новую файловую структуру в dev, Git вырвал массу ошибок. I git reset мой путь обратно в нормальное состояние, но в моем (несколько ограниченном) опыте с Git, что многие ошибки обычно означают, что я принимал неправильный подход.

Есть ли лучший способ получить реорганизованную структуру папок в ветку dev? Если это помогает, изменения в других коммитов на хозяине (B и C) довольно незначительны, и мне будет хорошо, если они потеряют их, если это облегчит ситуацию.

+0

Я не на самом деле * пробовал * это, но если ваш Git достаточно новый, 'rebase' теперь имеет' -s 'и' -X ', поэтому вы можете добавить' -X find -renames = ', чтобы заставить rebase использовать вишневый выбор слияния с определенным порогом обнаружения переименования или просто' git rebase -m', чтобы заставить его использовать слияние с вишней в первую очередь (хотя, re, что теперь также зависит от версии Git, а также зависит от команды rebase-command). Поскольку вы попадаете в Git minutiae, вы можете захотеть включить точные команды. – torek

ответ

1

Да, есть разумный способ сделать это.

Предисловие

master теперь (если я правильно понял):

project 
    src 
    file.c 

dev есть, так как он не содержит обязательство A:

src 
    file.c   # with some changes 

ветками, как это:

master ()----(A0)----(A)----(B)----(C) 
       \ 
       \ 
dev    (D1)----(D2)----(D3)----()----(~ 30 additional commits...) 

Я также предполагаю, что A отличается от A0 никоим образом, кроме project/, вставляемого во все пути к файлу («перемещение вашего дерева вверх» в новый корень project в соответствии с вашим связанным вопросом).

Давайте сделаем это ...

Мы именно то, что git rebase бы внутренне, в то время как валять git немного, на каждом шагу, делая наши собственные «вишневого выбрать» шаг вместо того, что git бы себя ,

Мы используем второй рабочий каталог. $WD1 - это абсолютный путь к исходному рабочему каталогу, $WD2 - это еще один абсолютный путь (вне этого).

Во-первых, создать вспомогательный каталог как клон оригинал:

cd $WD2 
git clone $WD1 dev . 

Затем запустите ветвь newdev, которая в конечном счете будет dev перебазировались на A.

cd $WD1 
git checkout A 
git checkout -b newdev 

Мы получаем D1 совершить в newdev, не давая git шанс испортить его:

cd $WD2 
git checkout D1 

cd $WD1 
rm -r project/src 
cp -r $WD2/src project/ 
git add -A 
git commit -m "`cd $WD2 ; git log -1 --format=%s`" 

Теперь ситуация:

newdev      (D1')  
         /
         /
master ()----(A0)----(A)----(B)----(C) 
       \ 
       \ 
dev    (D1)----(D2)----(D3)----()----(~ 30 additional commits...) 

Теперь повторите для D2:

cd $WD2 
git checkout D2 

cd $WD1 
rm -r project/src 
cp -r $WD2/src project/ 
git add -A 
git commit -m "`cd $WD2 ; git log -1 --format=%s`" 

Теперь ситуация:

newdev      (D1')----(D2')  
         /
         /
master ()----(A0)----(A)----(B)----(C) 
       \ 
       \ 
dev    (D1)----(D2)----(D3)----()----(~ 30 additional commits...) 

Повторите, пока не закончено.

Конечно, вы захотите создать небольшой скрипт оболочки для тех команд, которые итерации через все коммиты D1 ... D30.

Впоследствии, простой git rebase master сделает перебазу от A до C, как обычно. Тогда, чтобы избавиться от newdev, изменив название вокруг:

git checkout newdev 
git branch olddev dev   # just in case... 
git branch -D dev 
git checkout -b dev 

Общие замечания

Почему второй рабочий каталог?

Обратите внимание, что в этом конкретном случае могут быть способы избежать использования вторичного рабочего каталога, напрямую используя rm -r project/src ; git checkout D1 src ; mv src project/. Я предпочитаю делать это, как показано выше, просто чтобы быть на 100% уверенным, что все очень чисто и «видимо» всегда. Таким образом, операция проверки полностью отделена от модификации, которую мы применяем самостоятельно.

Существует буквально ничего, что могло бы пойти не так, и этот подход работает со всеми другими изменениями. Для нетривиального изменения предположите, что кто-то изменил все пробелы в каждом исходном файле в A. Этот подход делает тривиальным переустанавливать другие ветви на это (если вы также можете внести это пробел в скрипт).

+0

Спасибо за очень тщательное решение. Это заставило меня указать в правильном направлении: клонирование репо во вторую папку, а затем прокрутку коммитов на dev и ручное «воспроизведение» их поверх мастера. Я использовал инструмент diff для применения изменений в каждой фиксации от dev (вместо rm и cp), но он сработал! –

+0

Хорошая работа, «get'er done», это идея, которая имеет значение. :) – AnoE

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