Git команды, которые могут сломать / переписать историю
Можете ли вы предоставить список (всех или наиболее распространенных) операций или команд, которые могут поставить под угрозу историю в git?
Чего следует избегать абсолютно?
- Исправить коммит после нажатия этой (
git commit
/git push
/git commit --amend
) - Перебазируем на то, что уже подтолкнуло
Я хотел бы, чтобы этот вопрос (если он еще не задавался где-то еще) стал своего рода ссылкой на обычные операции, которые можно избежать в git.
Кроме того, я использую git reset
много, но я не полностью осознаю возможный ущерб, который я мог бы нанести хранилищу (или другим копиям участников). Можно git reset
быть опасным?
2 ответа
knittl уже собрал хороший список команд, которые переписывают историю, но я хотел развить его ответ.
Можете ли вы предоставить список [...] операций или команд, которые могут поставить под угрозу историю в git? Чего следует избегать абсолютно?
Во-первых, нет ничего плохого в переписывании / удалении истории как таковой; в конце концов, вы, вероятно, регулярно создаете ветви объектов, сохраняете их строго локальными, а затем удаляете (после их объединения или понимая, что они ни к чему вас не приведут), не задумываясь об этом.
Однако вы можете и наверняка столкнетесь с проблемами, когда будете локально переписывать / удалять историю, к которой другие люди уже имеют доступ, а затем отправлять ее на общий удаленный компьютер.
Операции, которые должны учитываться как переписывание / удаление истории локального репо
Конечно, существуют глупые способы испортить или удалить историю (например, подделать содержимое .git/objects/
), но это выходит за рамки моего ответа.
Вы можете переписать историю локального репо различными способами. В разделе книги Pro Git под названием " Переписывание истории" упоминается несколько
git amend --commit
git rebase
git filter-branch
- BFG Repo Cleaner Роберто Тайли (сторонний инструмент)
Возможно, есть и другие. Любая операция, которая может изменить или иным образом переместить несимвольную ссылку (ветвь или тег) и заставить ее указывать на коммит, который не является потомком текущей подсказки ветви, должна учитываться как перезапись локальной истории. Это включает:
git commit --amend
: заменяет последний коммит;- Все формы перебазирования (в т.ч.
git pull --rebase
); git reset
(см. пример ниже);git checkout -B
а такжеgit branch -f
: сбрасывает существующую ветку в другой коммит;git tag --force
: воссоздает тег с тем же именем, но может указывать на другой коммит.
Любое удаление несимвольной ссылки (ветви или тега) также может рассматриваться как удаление истории:
git branch -d
или жеgit branch -D
git tag -d
Можно утверждать, что удаление ветви, которая была полностью объединена с другой, следует рассматривать только как легкую форму удаления истории, если она вообще существует.
Тэги разные, хотя. Удаление облегченного тега не такая уж большая проблема, но удаление аннотированного тега, который является истинным объектом Git, должно считаться удалением локальной истории.
Операции, которые переписывают / удаляют историю удаленного репо
Насколько я знаю, только git push -f
(эквивалентно git push --force
) имеет возможность переписать / удалить историю в удаленном хранилище.
Тем не менее, можно
- отключить возможность принудительного обновления удаленных веток на ссылки без ускоренной пересылки, установив
receive.denyNonFastForwards
на сервере. - отключить возможность удаления ветки живущей в удаленном репозитории, установив
receive.denyDeletes
на сервере.
Кроме того, я использую
git reset
много, но я не полностью осознаю возможный ущерб, который я мог бы нанести хранилищу (или другим копиям участников). Можноgit reset
быть опасным?
git-reset
Как упоминалось в knittl, обычно меняется, где ветвь указывает на точку. Эта команда может быть опасной, поскольку она может сделать достижимые коммиты недоступными. Поскольку картинка говорит тысячу слов, рассмотрим следующую ситуацию:
Вы на master
ветвь, которая указывает на коммит D
, Теперь, скажем, вы бежите, например,
git reset master~2
Мягкий сброс считается наиболее благоприятной формой сброса, потому что он "только" изменяется там, куда указывает текущая ветвь, но не влияет на область подготовки или ваше рабочее дерево. Тем не менее, простое изменение того, на что ветка указывает таким образом, имеет последствия: после этого мягкого сброса вы получите
Фиксации C
а также D
которые были доступны из master
до сброса теперь стало недоступно; Другими словами, они не являются предками каких-либо ссылок (ветвь, тег или HEAD). Вы могли бы сказать, что они находятся в "хранилище неопределенности"; они все еще существуют в объектной базе данных вашего репозитория Git, но они больше не будут перечислены в выходных данных git log
,
Если вы действительно нашли эти коммиты ценными до сброса, вы должны снова сделать их доступными, указав некоторую ссылку (например, другую ветвь) для фиксации. D
снова. В противном случае фиксирует C
а также D
в конечном итоге умрет от истинной смерти, когда Git запустит автоматическую сборку мусора и удалит недоступные объекты.
Вы можете, теоретически, рыбу совершить D
вне reflog, но всегда есть риск, что вы забудете об этих недоступных коммитах или не сможете определить, какая запись в reflog соответствует коммиту D
,
В заключение да, git-reset
может быть опасным, и это хорошая идея, чтобы убедиться, что текущая вершина ветви, которую вы собираетесь сбросить, останется достижимой после сброса. Если необходимо, создайте еще одну ветку перед сбросом, на всякий случай, в качестве резервной копии; и если вы уверены, что хотите забыть эти коммиты, вы всегда можете удалить эту ветку позже.
Обратите внимание, что начиная с Git 2.24 (4 квартал 2019 г.) в приведенный выше список может не входить git filter-branch
больше.
git filter-branch
устарел (BFG тоже)
См. Коммит 483e861, коммит 9df53c5, коммит 7b6ad97 (4 сентября 2019 г.) Элайджа Ньюрен (newren
).
(Слияние Junio C Hamano -gitster
- в коммите 91243b0, 30 сен 2019)
Рекомендовать
git-filter-repo
вместо тогоgit-filter-branch
filter-branch
страдает от потока замаскированных опасностей, которые искажают переписывание истории (т.е. отклоняются от преднамеренных изменений).Многие из этих проблем незаметны и могут легко остаться незамеченными, пока новый репозиторий не будет использован.
Это может привести к проблемам, начиная с еще более запутанной истории, чем то, что привело людей кfilter-branch
в первую очередь, к потере или повреждению данных. Эти проблемы не могут быть исправлены с обратной совместимостью, поэтому добавьте предупреждение в обаfilter-branch
и его справочная страница, рекомендующая другой инструмент (например,filter-repo
) вместо этого.Кроме того, обновите другие страницы руководства, на которые ссылаются
filter-branch
.
Некоторым из них потребовались обновления, даже если бы мы могли и дальше рекомендоватьfilter-branch
либо из-за намека на то, что что-то было уникальным дляfilter-branch
когда это применялось в более общем плане ко всем инструментам переписывания истории (например,BFG
,reposurgeon
,fast-import
,filter-repo
), или потому что что-то оfilter-branch
был использован в качестве примера, несмотря на то, что сейчас существуют другие более широко известные примеры.
Измените эти разделы, чтобы исправить эти проблемы и не рекомендоватьfilter-branch
.Наконец, удалите раздел, объясняющий
BFG Repo Cleaner
как альтернативаfilter-branch
.
Мне это немного не нравится, особенно потому, что я так многому научился у BFG, что нашел хорошее применение вfilter-repo
(что намного больше, чем я могу сказать оfilter-branch
), но при сохранении этого раздела возникло несколько проблем:
- Чтобы порекомендовать людям отказаться от
filter-branch
, нам нужно дать им рекомендации по использованию чего-то еще, что может обрабатывать все те же типы перезаписи.
Насколько мне известно,filter-repo
единственный такой инструмент. Так что об этом нужно упомянуть.- Я не хочу давать пользователям противоречивые рекомендации
- Если мы рекомендуем два инструмента, мы не должны ожидать, что пользователи изучат оба и выберут, какой из них использовать; мы должны объяснить, какие проблемы один может решить, а другой - нет, или когда одна из них намного быстрее, чем другая.
BFG
а такжеfilter-repo
иметь аналогичную производительность- Все типы фильтрации, которые
BFG
сможет сделать,filter-repo
тоже могу.
По факту,filter-repo
идет с повторной реализациейBFG
названныйbfg-ish
который обеспечивает тот же пользовательский интерфейс, что иBFG
но с несколькими исправлениями и новыми функциями, которые сложно реализовать вBFG
из-за его технической основы.Хотя я все еще мог упомянуть оба инструмента, мне кажется, что мне нужно провести какое-то сравнение, и в конечном итоге я просто скажу, что
filter-repo
может всеBFG
может, поэтому в конечном итоге кажется, что лучше вообще удалить этот раздел.
операции или команды, которые могут поставить под угрозу историю в git?
По крайней мере newren/git-filter-repo
может восстановиться из любой истории, скомпрометированной его использованием.
Среди заявленных целей:
Более интеллектуальная безопасность
Запись копий исходных ссылок в специальное пространство имен в репо не обеспечивает удобный механизм восстановления. Многие с трудом оправятся от этого.
Почти все, кого я когда-либо видел, выполняя операцию фильтрации репозитория, делали это с новым клоном, потому что удаление клона в случае ошибки - намного более простой механизм восстановления.
Настоятельно поощряйте этот рабочий процесс, обнаруживая и спасая, если мы не находимся в новом клоне, если пользователь не переопределит с помощью--force
.
git filter-repo
как указано в документации, примерно работает, запустив:
git fast-export <options> | filter | git fast-import <options>
А также git fast-export
/ git fast-import
есть некоторые улучшения с git 2.24 (4 квартал 2019 г.)
См. Фиксацию 941790d, фиксацию 8d7d33c, фиксацию a1638cf, фиксацию 208d692, фиксацию b8f50e5, фиксацию f73b2ab, фиксацию 3164e6b (3 октября 2019 г.) и фиксацию af2abd8 (25 сентября 2019 г.) Элайджа Ньюрен (newren
).
(Слияние Junio C Hamano -gitster
- в коммите 16d9d71, 15 октября 2019 г.)
Например:
fast-import
: разрешить идентификацию тегов по меткамПодписано: Элайджа Ньюрен
Идентификаторы марки используются в
fast-export
а такжеfast-import
чтобы предоставить метку для ссылки на более ранний контент.BLOB-объекты получают метки, потому что на них нужно ссылаться в коммитах, где они впервые появляются с заданным именем файла, а коммитам даются метки, потому что они могут быть родителями других коммитов.
Теги никогда не получали ярлыков, вероятно, потому, что они считались ненужными, но это создает две проблемы:
- Это оставляет нас без возможности ссылаться на предыдущие теги, если мы хотим создать тег тега (или более высокие уровни вложенности).
- Это не оставляет нам возможности записать, что тег уже был импортирован при использовании
--export-marks
а также--import-marks
.Устраните эти проблемы, допустив опциональную метку для тегов.
С верхней части моей головы:
git commit --amend
перепишет предыдущий коммитgit rebase
может переписать несколько коммитов (rebase также вызывается при использованииgit pull
с--rebase
флаг илиbranch.$name.rebase
опция конфигурации)git filter-branch
может переписать несколько коммитовgit push -f
может изменить коммит, на который указывает ветвь (то же самое относится и кgit push origin +branch
синтаксис)git reset
может изменить фиксацию ветки указывает наgit branch -f
может изменить коммит, на который указывает ветвь (воссоздав ветку с тем же именем)git checkout -B
может изменить коммит, на который указывает ветвь (воссоздав ветку с тем же именем)
Из опыта одна из самых опасных команд
git push -f mirror
Это отражает ваше локальное репо на удаленном в процессе, удаляя все другие ветви, кроме тех, которые у вас есть в вашем локальном репо.