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