Есть ли способ заставить git добавить файл из master в 10 других ветвей?



Есть ли способ сказать git, чтобы добавить новый файл в каждую другую ветвь?



Вместо git checkout <branch>; git merge master для каждой ветви есть ярлык для добавления newfile в каждую ветвь ниже?



     master
+-----newfile
|
---
/ |
/ |
/ |
foo bar baz


EDIT: это сценарий bash (нуждается в некоторой очистке, если реализован), который я придумал, но надеюсь, что есть лучший способ.



MSG='added newfile which contains a method to workaround issue IS-797'
for branch in $(git branch | grep -v master | sed 's#^[ *t]##g'); do
echo merging into $branch
git checkout $branch && git merge master -m "$MSG"
done
574   3  
git

3 ответов:

Существует несколько способов пойти об этом. Большинство советов в других комментариях / ответах (на момент написания этой статьи) являются подозрительными, на мой взгляд. Вот краткое изложение различных вариантов, с плюсами и минусами.

Во-первых, есть (по крайней мере) три различных варианта того, как может выглядеть окончательная история. У каждого есть свои плюсы и минусы. Что-то вроде того. Скорее, у каждого есть свои минусы, и плюсы в том, что у него нет минусов других способов.
  • Это может выглядеть так, как файл был "всегда есть", так как до этого были созданы пораженные ветви. Большой недостаток заключается в том, что это переписывание истории, и это имеет последствия.

  • Это может выглядеть так, как будто файл был независимо добавлен каждой веткой. Файл, скорее всего, окажется с трудночитаемой историей, и есть много возможностей для избежания конфликтов слияния. Но он не переписывает историю.

  • Это может выглядеть так, как будто файл был добавлен один раз, а затем объединен в каждую ветвь. Некоторые люди действительно ненавидят коммиты слияния, и даже как тот, кто Не особенно ненавидит коммиты слияния, я думаю, что этот подход приводит к беспорядочной топологии ветвей. Но он избегает переписывания истории и будет хорошо работать в будущем; то есть это функционально самый чистый вариант, но эстетически грубый.

Рассматривая каждую из них более подробно:


Переписывание Истории :

Если вы один используете свое РЕПО, и вы никогда не делали ничего, что делает ваш существующий идентификатор фиксации ("хэши") важен, тогда это довольно привлекательный вариант. Даже если вы разделяете РЕПО, вы можете сделать эту работу до тех пор, пока вы координируете с другими пользователями РЕПО.

Для больших переписок мой общий совет-согласовать со всеми, чтобы иметь установленную дату/время, когда вся работа будет перенесена в репо. Затем все отбрасывают свои клоны, вы делаете переписывание, и все повторно клонируются. Если это непрактично, то большой перепис, вероятно, не является хорошим идея; но если вы хотите рассмотреть ее в любом случае, прочитайте "восстановление из восходящей ребазы" в git rebase docs для получения дополнительной информации о том, что должно произойти.

Хотя 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
Проблема в том, что если ваша история велика, то процесс идет медленно. Вы можете ускорить его, используя ramdisk для рабочего дерева (см. опцию -d), или используя --index-filter вместо --tree-filter (но это требует использования различных команд для прямого обновления индекса, и это не так просто).

каждая ветвь добавляет файл

Это то, что cherry-pick даст вам. Так как речь идет о том, чтобы автоматизируйте процесс, непонятно, почему кто-то прокомментировал cherry-pick, как будто это решение. Процесс такой же ручной (и такой же скриптовый), как и слияние.

Единственное отличие состоит в том, что когда вы делаете это таким образом, git создает независимые коммиты, которые индивидуально добавляют файл в каждую ветвь.

Для этого можно использовать тот же базовый сценарий, что и для слияния, просто заменив команду merge командой cherry-pick команда.


слияния

Для этого вы уже разработали разумное решение-вам нужен сценарий. Единственное, что я хотел бы отметить, это то, что git for-each-ref часто является более подходящей командой для подачи в сценарий, а не git branch. https://git-scm.com/docs/git-for-each-ref

Вы можете использовать git rebase, чтобы достичь этого, но прочитайте, почему вы не должны использовать git rebase из этой статьи

Если у вас уже есть фиксация на master, я бы просто сорвал ее на каждой ветке. Это, безусловно, самый простой и надежный сценарий; сбой в одной ветви должен быть несущественным для других ветвей.

commit='deadbeef'
for branch in $(git branch | sed -n '/master/!s#^[ *\t]##p'); do
   echo "cherry-picking onto $branch"
   git checkout "$branch" && git cherry-pick "$commit"
done

В качестве отступа обратите внимание на предпочтение строчных переменных оболочки, цитирование, не используя флаг g в sed, Когда вы ожидаете только одно совпадение в каждой строке, и избегая бесполезного использования grep.

Использование \t в сценарий sed не совсем переносим; возможно, попробуйте [*[:space:]] вместо [ *\t].

Выбор отдельного коммита, конечно, также гораздо более специфичен, чем слияние всех master в каждую ветвь, что вполне может быть полным нет-нет для других, кто борется с этим.

Comments

    Ничего не найдено.