Отдельные строки ветки в Git

Извините, что мой вопрос такой расплывчатый, но я действительно не знаю, как лучше всего описать ситуацию.

В моем репозитории файл README содержит ссылку, в которой есть имя ветки master или develop для соответствующих веток (затрагиваются только эти две ветки, мне все равно, как это обрабатывается для разных веток). Теперь я хочу, чтобы при объединении develop в master эта разница сохранялась.

То, что я делал до сих пор, использовал

git merge --no-commit develop

И вручную исправить ссылку. Проблема здесь в том, что develop имеет независимую историю от master. Таким образом, git describe из ветки develop не включает последний тег на master. Однако я использую это для управления версиями, поэтому это необходимо. Обходной путь заключается в том, чтобы затем объединить master обратно в develop.

git merge --no-commit master

Однако это вызывает беспорядочную историю, так как у меня много этих пустых обратных слияний.

Я также попробовал это, где я добавил README.rst merge=ours. Однако это игнорирует все изменения в README, поэтому мне придется вручную обновить файл README.

Я действительно не знаю, есть ли подходящий подход. Есть ли способ заставить GitHub игнорировать ссылки (например, с помощью регулярного выражения)? Или, может быть, какая-то команда, которая расширяется до имени ветки?


person DerWeh    schedule 03.04.2018    source источник
comment
Извлечь ветку, отредактировать файл, зафиксировать изменение?   -  person evolutionxbox    schedule 03.04.2018
comment
Я действительно не понял, почему вы используете git merge с --no-commit. Слияние не означает, что вы наверняка получите все изменения из другой ветки. Вы можете удалить конфликтующее изменение в коммите слияния. Это предотвратит любые проблемы при следующих слияниях.   -  person Marinos An    schedule 03.04.2018
comment
Я выбрал --no-commit, чтобы не перезаписывать ссылку в master. Просто коммит не выдает ошибку. Он просто перезаписывает старую версию новой. То есть, если я вас правильно понял, вы предлагаете сделать коммит на master изменение ссылки там, тем самым спровоцировав конфликт слияния при будущих слияниях? Но не будет ли это расходиться в историях ветвей? Таким образом, git describe на develop никогда не будет отражать какие-либо теги в master в будущем?   -  person DerWeh    schedule 03.04.2018
comment
Просто отметим, что поведение git describe соответствует ожиданиям и не связано с вашей проблемой. слияние ветки develop с веткой master не означает слияние master с develop. см. документы   -  person Yuri G.    schedule 03.04.2018


Ответы (1)


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

Дополнительные сведения о настройке фильтров размывания и очистки см. в документации gitattributes. .

Фон

Во-первых, помните, что ветка name — это просто перемещаемый указатель на (единственную) фиксацию. Есть еще кое-что, что люди также называют словом ветка, а именно: серия коммитов, заканчивающаяся определенной фиксацией. Подробнее об этом см. Что именно мы подразумеваем под ветвью?

В общем случае Git добавляет коммиты. Вы проверяете какое-то имя ветки:

$ git checkout master

а затем выполните некоторую работу (с файлами в вашем рабочем дереве, которые затем скопируйте в область подготовки, также известную как индекс, используя git add для перезаписи копии, которые уже были в индексе, но соответствуют текущему коммиту — мы вернемся ко всему этому чуть позже):

... edit ...
$ git add README.rst

В конце концов вы запускаете git commit, который:

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

Родительским коммитом нового коммита является коммит, который вы извлекли при запуске git checkout master. Коммит новый становится фиксацией в конце ветки, которую вы выбрали при запуске git checkout master. Таким образом, имя master теперь указывает на новый коммит, который указывает на то, что было коммитом master минуту назад:

...  <-previous-tip-of-master  <-new-tip-of-master   <--master

Вы можете извлекать только одну ветку за раз, и git commit делает свою новую фиксацию в этой ветке — в частности, заставляя это имя указывать на новую фиксацию, только что сделанную Git. Все остальные имена веток не изменились: они по-прежнему указывают на некоторые другие коммиты.

Использование git merge по-прежнему просто делает новую фиксацию! Разница между этой новой фиксацией и другими новыми фиксациями, сделанными git commit, заключается в том, что эта новая фиксация имеет двух родителей: она, как обычно, указывает на предыдущую фиксацию, но также указывает на фиксацию, которую вы выбрали, когда вы бежали git merge. В любом случае этот новый коммит находится только в ветке, в которой вы находитесь:

...--B--...--o--C--M   <-- master
      \           /
       o--...-o--D   <-- develop

где M — новая фиксация слияния. Этот новый коммит слияния имеет моментальный снимок всех файлов, точно так же, как любой другой коммит имеет снимок всех файлов, поэтому файл README.rst в M создается путем выполнения каких-либо действий со снимком в C, что было подсказкой master a. минуту назад — и что-то со снимком в D, который все еще является верхушкой develop. Эти «кое-что» основаны на том, как C и D изменились со времени слияния базы версии фиксации README.rst, которая находится в моментальном снимке в фиксации B.

Использование этого: размазать и очистить фильтры

Теперь вместе с этими метаданными о том, кто это сделал, когда и с каким сообщением в журнале, каждый коммит просто записывает все исходные файлы, которые были в индексе / промежуточной области на момент запуска git commit. То, что вы получаете, когда git checkout <thing-that-specifies-commit> получаете этот снимок, но не обязательно то же самое, что и этот снимок.

Все эти детали важны! Git извлечет фиксацию в M в индексную / промежуточную область. То, что находится в этом индексе / промежуточной области в этот момент, точно соответствует тому, что находится внутри M. Но это не то, что вы видите в своем рабочем дереве. То, что вы видите в своем рабочем дереве, получено путем запуска всего, что Git скопировал в индекс, через любой определенный вами фильтр размытия.

Фильтр пятен по умолчанию в основном «оставить все без изменений». На этом этапе вы можете настроить конечные строки. Технически это отдельно от фильтров смазывания, но это часть процесса смазывания. Если вы используете это значение по умолчанию, то, что находится в вашем рабочем дереве, соответствует тому, что находится в вашем индексе.

Предположим, однако, что вы определили фильтр смазывания для применения конкретно к README.rst. Предположим далее, что вы пишете этот фильтр пятен, чтобы найти строку со ссылкой, которая должна упоминать ветку, master или develop. Напишите фильтр пятен, чтобы заменить эту строку правильной ссылкой. Например, возможно, строка, которую вы фиксируете, должна выглядеть так:

blah blah link:!replace this part! blah

и ваш фильтр пятен говорит:

sed -e "s/!replace this part!/actual link using $branch/"

(используя команду Linux/Unix/GNU sed, но вы можете написать это как хотите). Заставьте код фильтра пятен определить, какое имя ветки использовать, например, запустив git rev-parse --abbrev-ref HEAD.

Это означает, что то, что находится в рабочем дереве для файла README.rst, больше не будет соответствовать тому, что на самом деле зафиксировано.

Однако, чтобы это работало должным образом, вам нужно заставить git add написать в качестве вещи, которую нужно зафиксировать, строку, которая гласит:

blah blah link:!replace this part! blah

Чтобы сделать это автоматически, напишите себе чистый фильтр, который находит смазанную строку — как бы вы это ни делали — и заменяет ее, например, используя sed, на текст !replace this part!.

Теперь, когда вы запускаете:

$ git add README.rst

Git пропустит файл рабочего дерева через ваш чистый фильтр, чтобы получить версию README.rst для записи в индекс / промежуточную область.

Это также работает при слиянии: слияние «увидит» очищенную версию файла и объединит любые внесенные вами изменения в любой из ветвей, используя очищенный текст. «Грязная» (нечеткая) версия с фактической ссылкой отображается только в рабочем дереве. Он никогда не входит в коммит.

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

Если вы храните очищенную ссылку как версию, подходящую для большинства применений, и вам нужна только грязная версия, которая указывает на develop вместо master при использовании вне рабочего дерева, это будет работать даже в этом случае.

person torek    schedule 03.04.2018