Git интерактивное сквош перебазирования создает совершенно новую ветку

Вот изображение последней части моей простой и понятной истории (из SourceTree, время идет снизу вверх):

Git интерактивное сквош перебазирования создает совершенно новую ветку

Итак, в этой ситуации я попросил SourceTree выполнить интерактивную перебазировку дочерних элементов самого нижнего коммита («Xcode 10.2, Swift 5»), потому что я хотел свернуть следующие два коммита («черт возьми, кодировка списка свойств» и « v1.1.1build24") в один коммит. У меня нет пульта, поэтому я могу переписать историю и сохранить ее в чистоте и информативности.

Но когда я это сделал, была создана целая куча новых коммитов, ответвляющихся от «Xcode 10.2, Swift 5» — копий существующей цепочки коммитов. Я не мог понять, почему, и мне потребовалось много суеты, чтобы убрать это.

Это была не совсем новая «ветвь» (как указано в заголовке моего вопроса); но существующие коммиты до «v1.1.2build28» оказались на своей собственной тупиковой ветке, и master теперь в ней были эти новые коммиты, дублирующие эти коммиты, но без тегов и с сегодняшней датой.

Мой вопрос: почему это произошло, и что я должен был сделать вместо этого?


273
2

Ответы:

Решено

Это сделано, как и ожидалось.

«черт, кодировка списка свойств» и «v1.1.1build24» сжимаются как одна фиксация. Git реализует этот сквош, создавая новую фиксацию, родителем которой является «Xcode 10.2, Swift 5», и чьи изменения эквивалентны изменениям «штопать, кодировка списка свойств» и «v1.1.1build24».

Родителем или базой "v1.1.1build25" была "v1.1.1build24". Теперь новый коммит заменил «v1.1.1build24» и «черт, кодировка списка свойств». В результате родителем "v1.1.1build25" должен быть новый коммит. В противном случае коммиты выше «v1.1.1build24» больше не будут существовать на master. Чтобы переместить «v1.1.1build25» из старой базы в новую, Git также создает новую фиксацию для «v1.1.1build25», чьим родителем теперь является сжатый коммит и чьи изменения эквивалентны изменениям «v1 .1.1сборка 25". Соответственно, все остальные потомки пересоздаются, потому что их родители/базы изменены.

Git создает новые коммиты, как если бы старые были заменены, но старые все еще существуют в репозитории, за исключением того, что они больше не доступны из master. Однако такие теги, как «v1.1.1build25» и ветки, такие как «temp», по-прежнему указывают на старые коммиты. Поскольку этих старых коммитов сейчас нет в текущем master, эти теги и ветки также не видны в master.


Ничего плохого. Именно так работает git. Git rebase — это не что иное, как небольшой робот, который делает новую версию кучи коммитов.

Это просто плохая формулировка, что некоторые люди, даже документы, говорят о «переписывании истории». Переписать историю в git вообще невозможно — то, что однажды было зафиксировано, уже нельзя будет изменить снова. git rebase помогает только копировать старой истории в новую версию истории. Однако если в старой истории, как в вашем случае, есть другие теги или ветки, они будут продолжать указывать на историю Старый даже после перебазирования.

Так что совершенно нормально, что репозиторий git состоит из множества мертвых веток. Иногда их можно увидеть (поскольку другие теги/ветки все еще ссылаются на них), иногда нельзя — но всегда можно сослаться на них, если случайно запомнили SHA ID. (Время от времени появляется сборщик мусора git и собирает действительно мертвые части истории, на которые ничего не указывает).

Это здорово, потому что вы не можете сделать никаких ошибок (1). Вы всегда можете просто git reset --hard в какой-то момент истории, потому что история никогда не может быть изменен в git. Если вы пробовали выполнить перебазирование, слияние или что-то еще, и это не сработало, как ожидалось, - если вы запомнили SHA, которым вы были раньше (или если вы пометили его), вы можете вернуться туда. (Если вы этого не сделали, вы можете найти его по git reflog). И у вас всегда есть пара дней, чтобы сделать это до того, как мусор будет вывезен.

Очевидно, это плохо для вас, потому что у вас есть много тегов, которые вы хотите указать на новую историю. Я немного погуглил, могут быть инструменты для переноса их в новую ветку, но я никогда не использовал такой инструмент. Попробуйте или примите как факт, что у git неизменная история. Возможно, когда-нибудь вам понравится, что вы можете экспериментировать без какого-либо риска :-)

(1) Единственный способ действительно потерять работу — это внести изменения в свой рабочий каталог и не фиксировать их. Если у вас есть незафиксированные изменения и вы сделаете reset --hard, они будут безвозвратно утеряны, и вас никто не предупредит.