Действительно сгладить слияние 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.