Действительно сгладить слияние git
В "StackOverflow" мало вопросов о "сглаживании слияния", причем ответ обычно "git rebase". Эти ответы хотя пропустите один решающий момент - порядок коммитов.
Предположим, что существует ветвь A с фиксацией 1 июня и 1 августа и ветка B с фиксацией 1 июля (UPDATE), чтобы восстановить описанную ниже usecase: ветки полностью независимы и не имеют обычная родословная, например, из двух разных репозиториев). При объединении B в будет следующая история (за git журнал):
Merged branch 'B'
Aug 1
Jul 1
Jun 1
Теперь то, что я ищу, - это способ получить тот же результат, но без слияния (и, следовательно, с базовой линейной историей в этом порядке, и да, это означает, что происходит переобучение). git rebase здесь не помогает, как и с ним, вы получите следующие истории:
Jul 1
Aug 1
Jun 1
или
Aug 1
Jun 1
Jul 1
Другими словами, git rebase всегда складывает одну ветку поверх другой, в то время как я ищу решение, которое будет выполнять промежуточные коммиты, отсортированные по дате фиксации автора.
По-видимому, для простых случаев необходимая компоновка может быть достигнута путем ручной постобработки git rebase с помощью git rebase -i, но это непрактично для больших историй, поэтому я бы искал автоматическую команду /script.
USECASE? Если A и B представляют разные части одного и того же проекта, которые оказались в разных репозиториях, и настало время исправить это, объединив их вместе, то естественно, что линейная история разворачивается в реальном порядке развития.
Ответы
Ответ 1
После некоторого размышления я выяснил, как сделать Как запустить git rebase -interactive в неинтерактивном режиме?, который также предоставляет полностью сценарий решение для этого вопроса.
1. Принесите две ветки из разных репозиториев в один репозиторий (git remote add + git fetch)
2. Rebase (неинтерактивно) одна ветка поверх другой (порядок имеет значение, сначала рассмотрите, какую ветвь вы хотели бы иметь в качестве первой фиксации консолидированной ветки).
3. Подготовьте следующие script (rebase-reoder-by-date
):
#!/bin/sh
awk '
/^pick/ {
printf "%s %s ", $1, $2;
system("echo -n `git show --format='%ai' -s " $2 "`");
for (i = 3; i <= NF; i++) printf " %s", $i; printf "\n";
}
' $1 | sort -k3 > $1.tmp
mv $1.tmp $1
4. Запуск: GIT_SEQUENCE_EDITOR=./rebase-reoder-by-date git rebase -i <initial commit>
Отказ от ответственности: все эти операции должны выполняться на копиях исходных репозиториев, проверять/проверять/тестировать объединенную ветку, чтобы убедиться, что это то, что вы ожидали, и содержит то, что вы ожидаете, сохраняйте резервные копии.
Ответ 2
В чем проблема, заключающаяся в том, чтобы оставить отдельное развитие в отдельных строках до тех пор, пока они не будут объединены? Если они были разделены, то они были разделены.
Существует множество способов просмотра истории в хронологическом порядке без взлома истории, как вы пытаетесь. Вы пробовали git log --pretty --date-order
?
Ответ 3
[См. мой другой ответ для полностью автоматизированного решения. Я бы оставил это как пример пути, который привел к окончательному решению, если кто-то столкнется с подобным, не столь очевидным, чтобы решить задачу.]
Хорошо, это не реальный ответ на вопрос (полностью написанное по сценарию, автоматизированное решение), но мышление и пример того, как можно обрабатывать (на основе интерактивной рефазы) обработку.
Хорошо, прежде всего, для окончательного решения git filter-branch --parent-filter
выглядит точно, что нужно. За исключением того, что мой git -fu не позволяет мне писать, 1-, 2- или 3-лайнер с ним, а подход к написанию автономного script для синтаксического анализа через все изменения не является крутым и более трудоемким, чем rebase -i.
Таким образом, rebase -i можно было бы эффективно использовать, если бы даны авторские даты фиксации. Моя первая мысль заключалась в том, чтобы временно исправить сообщения фиксации, чтобы начать с даты автора, используя git filter-branch --msg-filter
, запустите rebase -i, а затем снова отпустите сообщения.
Вторая мысль, хотя и была: зачем беспокоиться, лучше запланировать список фиксации переадресации, как используется rebase -i. Таким образом, процесс будет:
- Приведите ветки A и B из разных репозиториев в один репо, как обычно.
- Ребаза (неинтерактивно) одна ветка на другой. Рассмотрим, какая ветвь должна быть переустановлена, на которой, чтобы иметь право на первоначальное право (которое нельзя легко переписать с помощью rebase).
- Начать
git rebase -i
- В другой консоли перейдите к $REPO/.git/rebase-merge/
- Run:
awk '/^pick/ {printf "%s %s ", $1, $2; system("echo -n git show --format='%ai' -s " $2 "
"); for (i = 3; я <= NF; я ++) printf" % s ", $i; printf" \n ";} 'git -rebase-todo > git -rebase-todo.new; mv git -rebase-todo.new git -rebase-todo
- Это кажется правильным местом/способом для изменения порядка:
sort -k3 git-rebase-todo >git-rebase-todo.new; mv git-rebase-todo.new git-rebase-todo
- Переключитесь на оригинальную консоль и перезагрузите файл git -rebase-todo в редакторе, затем откройте редактор.
Voila! На самом деле, это может быть полностью написано, если git rebase -i
может работать в "неинтерактивном" режиме, я отправил Как запустить git rebase --interactive в неинтерактивном режиме? для этого.
Ответ 4
Собственно, если я правильно понимаю, вы можете легко достичь этого с помощью git-stitch-repo.