Как git трансплантаты и замена отличаются? (Сейчас ли прививки теперь устарели?)

Есть очень мало Q & A на git grafts по сравнению с replace. Поиск [git] + grafts + replace только нашел два, которые считались релевантными 5. what-are-git-info-grafts-for и git-what-is-a-graftcommit-or-a-graft-id. Также есть примечание к git.wiki.kernel.org: GraftPoint

Являются ли теперь трансплантаты полностью обгоняемыми replace и filter-branch, или они все еще необходимы для некоторых специальных угловых случаев (и обратной совместимости)?

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

EDIT: больше информации найдено.
Поиск в www.kernel.org/pub/software/scm/ git/docs для graft нашел только 3 результата:

  • git -filter-branch (1),
  • v1.5.4.7/ git -filter-ветвь (1),
  • v1.5.0.7/ git -svn (1).

Несколько более широкий поиск найден RelNotes/1.6.5.txt, который содержит:

  • refs/replace/hierarchy предназначена для использования в качестве замены механизма "трансплантатов", с дополнительным преимуществом, что это может быть передается через репозитории.

К сожалению, gitrepository-layout (5) еще не обновлен с информацией о компоновке refs/replace/repository (и примечаниями), а также никакое примечание об инфо/трансплантации.

Это приближается к поддержке того, о чем я думал, но я бы приветствовал любое подтверждение или разъяснение.

Ответы

Ответ 1

В то же обсуждение о Commit Generation Number, о котором вы упоминаете, Jakub Narębski подтверждает, что трансплантаты являются более привлекательными, чем решение:

трансплантаты настолько ужасны, что я не буду против выключения чисел поколений, если они будут использоваться.
В случае замены объектов вам нужны как замененные, так и замененные Числа генерации DAG.
[...] Прививки непередаваемы, и если вы используете их для отбраковки, а не для добавления истории они небезопасны против сбора мусора... Я думаю.

(публикация всегда позаботилась git filter-branch, как показано на рисунке поток 2008 года на рабочем процессе трансплантатов.)

Разница между трансплантатами и git заменить лучше всего иллюстрируется этим вопросом SO "Установка родительского указателя git для другого родителя" и комментариев (Якуб снова) ответ.

Он включает ссылку на Git1.6.5

Из того, что я понимаю (из GraftPoints), git replace заменил git grafts (если у вас есть git 1.6.5 или позже)

(Jakub:)

  • если вы хотите переписать историю, тогда grafts + git-filter-branch (или интерактивная переадресация, или быстрый экспорт +, например, reposurgeon) - это способ сделать это.
  • Если вам нужно/нужно сохранить историю, то git-replace намного превосходит трансплантат

Ответ 2

Если вам нужно переписать родительский фиксатор с помощью git replace, вот как это сделать.

Как отметил Филипп Оукли, git replace просто заменяет одно commit другим. Чтобы трансформировать родителя в существующую фиксацию, вам нужно сначала создать фальшивый коммит с правильным родителем.

Скажем, у вас есть две ветки git, которые вы хотите пересадить:

(a)-(b)-(c) (d)-(e)-(f)

Теперь мы хотим (d) быть родителем (c). Таким образом, мы создаем замену для (c) с правильным родителем (позвольте этому c1), затем git replace (c) с (c1). На этих этапах каждое из букв ссылается на хэш SHA1, представляющий это commit.

Чтобы создать новый коммит:

git checkout d
git rm -rf * # remove all files from working direcotry
git checkout c -- . # commit everything from c over top of it
GIT_AUTHOR_DATE="..." GIT_COMMITTER_DATE="..." git commit -m "..." # create replacement commit with date author

Теперь у вас есть commit (c1), у которого есть правильный родитель (d). Итак, все, что нам нужно сделать, это заменить существующий (c) на (c1):

git replace c c1

Теперь ваша история выглядит так:

(a)-(b)-(c1)-(d)-(e)-(f)

Бинго!

Ответ 3

EDIT: git replace --graft <commit> [<parent>...] выполняет то же самое, что и трансплантаты, и может добавлять или удалять родителей. документация говорит:

Создайте фиксацию трансплантата. Новый коммит создается с тем же содержимым, что и <commit> за исключением того, что его родители будут [<parent> ...] вместо родителей <commit> . Затем создается замена ref для замены вновь созданной фиксацией.

(Я оставляю старый ответ ниже в качестве справки.)


AFAIK, существует один вариант использования grafts, но replace не может: добавление или удаление родителей. Это инструмент для рефакторинга.

Например, если вы импортируете историю из старого репозитория SVN в Git, информация о слиянии отсутствует. То, что вы можете делать (и я делал это много раз), - это прочитать сообщения фиксации, чтобы узнать, где было выполнено слияние SVN, а затем использовать Git трансплантаты, чтобы добавить родителя к фиксации слияния.

IIRC, у меня также были случаи, когда я удалил родителя коммита, чтобы сделать его первым фиксатором в истории. Создание чистой истории, основанной на множественных хаотичных хранилищах, иногда требует радикальных мер (есть некоторый опыт миграции проектов к Git в моем блоге).

Затем, после того как вы очистили всю историю, перед публикацией нового репозитория Git вы сделаете git filter-branch.