Возвращение объединенных деревьев в Git

У меня есть что-то похожее на следующую историю (но сложнее с несколькими слияниями):

F - G - H - K - L - …
 / /
 / I - J - M - …
 / /
A - B - C - D - E - …
A′- B′- C′- D′- E′

A и A '- это одинаковые деревья с разными историями.

Я хочу переустановить все фиктивные коммиты на эквивалентные коммиты на первичной ветки, сохраняя слияния (предположительно вручную указывая хэши, где эквивалентные коммиты находятся на восстановленном дереве). Как сообщить K′, что он должен сливаться с H′ и J′? Или мне нужно воссоздать эти слияния вручную?

Если я делаю git rebase -p --onto B′ B L, он не может применяться чисто. Я мог бы переустановить H на B′ и M на D′, а затем воссоздать слияние K сам, затем rebase L на K′ (и так далее для других ветвей/объединений не показано), но это будет честная работа.

Я просмотрел несколько других questions, но ни одна из них не показала слияния.

2 ответа

Предполагая, что это либо не публичный репозиторий, либо любые другие пользователи репозитория в порядке со значительным переписыванием, наиболее эффективным способом для этого является git filter-branch. Один из возможных фильтров - --parent-filter, который позволяет вам изменять происхождение конкретных коммитов, несколько аналогично привитию или переустановке части дерева, но поскольку вы также можете передать параметр --all, вы можете выполнить эффект на нескольких ветвях в одном вызове. Это также может быть выполнено с помощью --commit-filter; но это более общее решение, предназначенное для изменения других аспектов отдельных обязательств, а не только для родителей. Вероятно, вы также захотите использовать --tag-name-filter cat для перемещения любых тегов в частях перезаписываемого дерева.

Итак, последняя команда будет выглядеть примерно так:

git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all
</somescript>

где либо правильно процитирован/экранирован bash код для замены A на A' для фиксации B (подробности о том, как именно информация предоставляется script и какие результаты из script должен быть найден в git help filter-branch), или имя фактической оболочки script, которая выполняет то же самое.

После этого также выполняется некоторая очистка - filter-branch оставляет исходные ветки на месте, но с новыми именами (refs/original/...), поэтому вы можете восстановить, если что-то не выглядит правильным. Там есть много информации о том, как удалить мертвые ветки, как только вы удовлетворены тем, что filter-branch сделал то, что вы хотели, и повторно упаковал свой репозиторий, чтобы восстановить пространство для хранения, поэтому я не буду реплицировать это здесь...


Пробовали ли вы использовать интерактивную перезагрузку? В принципе, git rebase -i A и git будут запускать ваш текстовый редактор с фиксациями после A. Затем вы можете перемещаться, и сквош фиксируется друг в друге до вашего сердечного содержимого.

licensed under cc by-sa 3.0 with attribution.