Есть несколько способов сделать это.Большинство советов в других комментариях / ответах (на момент написания статьи), на мой взгляд, подозрительно.Вот краткое изложение различных вариантов, с плюсами и минусами.
Прежде всего, есть (как минимум) три различных варианта того, как может выглядеть финальная история.У каждого есть свои плюсы и минусы.Вроде, как бы, что-то вроде.Больше похоже на то, что у каждого есть свои минусы, а плюсы в том, что у него нет минусов других способов.
Может показаться, что файл был "всегда рядом", так как до этогобыли созданы филиалы.Большим недостатком является то, что это перезапись истории, и это имеет последствия.
Может показаться, что файл был независимо добавлен каждой ветвью.Файл, скорее всего, окажется с труднодоступной историей, и существует большой потенциал для предотвращения конфликтов слияния.Но он не переписывает историю.
Может показаться, что файл был добавлен один раз, а затем объединен в каждую ветвь.Некоторые люди действительно ненавидят коммиты слияния, и даже если кто-то, кто не особенно ненавидит коммиты слияния, я думаю, что такой подход приводит к хаотичной топологии ветвей.Но это позволяет избежать переписывания истории и будет хорошо работать в будущем;то есть это функционально самый чистый вариант, но эстетически грубый.
Более подробно рассмотрим каждый из них:
История переписывания :
Если вы используете репо в одиночку и никогда не делали ничего, что делало бы ваши существующие идентификаторы коммитов («хэши») важными, тогда это довольно привлекательный вариант.Даже если вы делитесь репо, вы можете сделать это, пока вы координируете с другими пользователями репо.
Для больших переписываний мой общий совет - координировать со всеми, чтобы установить дату / время, когда все работы будут перенесены в репо.Затем все сбрасывают свои клоны, вы переписываете, и каждый повторно клонирует.Если это не практично, то большая переписка, вероятно, не очень хорошая идея;но если вы все-таки хотите это учесть, прочитайте раздел «восстановление после восходящего повтора» в git rebase
документах для получения дополнительной информации о том, что должно произойти.
Хотя rebase
, я полагаю,прототипный способ переписать историю, в этом случае это почти наверняка неправильный путь.Если у вас много веток, вам придется делать это много раз.Если у вас сложная история, это становится очень трудно сделать правильно.В частности, он плохо работает со слияниями (даже с недавно добавленными улучшениями).
Вместо этого вы можете использовать git filter-branch
.Простой способ с --tree-filter
.Вы поместите копию файла где-нибудь за пределами рабочего дерева, затем
git filter-branch --tree-filter 'cp /path/to/stored/copy/of/file path/to/file/in/worktree' -- --all
Затем filter-branch
продолжит проверять каждый коммит в вашей истории, выполните команду cp
, чтобы добавить файл врабочее дерево для этого коммита и напишите новый коммит с результирующим контентом.Затем он переместит ветки со старых коммитов на новые.Если у вас есть теги и вы хотите, чтобы они тоже перемещались, добавьте аргумент --tag-name-filter
, например
git filter-branch --tree-filter 'cp /path/to/stored/copy/of/file path/to/file/in/worktree' --tag-name-filter cat -- --all
Проблема в том, что если ваша история велика, процесс медленный.Вы можете ускорить его, используя виртуальный диск для рабочего дерева (см. Параметр -d
), или используя --index-filter
вместо --tree-filter
(но для этого необходимо использовать различные команды для непосредственного обновления индекса,и это не так просто).
Каждая ветвь добавляет файл
Это то, что cherry-pick
даст вам.Поскольку вопрос заключается в том, как автоматизировать процесс, неясно, почему кто-то прокомментировал cherry-pick
, как если бы это было решение.Процесс такой же ручной (и такой же скриптовый), как и слияние.
Единственное отличие состоит в том, что когда вы делаете это таким образом, git создает независимые коммиты, которые по отдельности добавляют файл в каждую ветку.
Для этого вы можете использовать тот же базовый сценарий, что и для слияния, просто заменив команду merge
командой cherry-pick
.
Слияния
Для этого вы уже составили разумное решение - вам нужен сценарий.Единственное, что я хотел бы отметить, это то, что git for-each-ref
часто является более подходящей командой для ввода в сценарий, чем git branch
.https://git -scm.com / документы / ГИТ-за-каждый-исх