Git команды, которые могут сломать / переписать историю

Можете ли вы предоставить список (всех или наиболее распространенных) операций или команд, которые могут поставить под угрозу историю в git?

Чего следует избегать абсолютно?

  1. Исправить коммит после нажатия этой (git commit/git push/git commit --amend)
  2. Перебазируем на то, что уже подтолкнуло

Я хотел бы, чтобы этот вопрос (если он еще не задавался где-то еще) стал своего рода ссылкой на обычные операции, которые можно избежать в 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-объекты получают метки, потому что на них нужно ссылаться в коммитах, где они впервые появляются с заданным именем файла, а коммитам даются метки, потому что они могут быть родителями других коммитов.

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

  1. Это оставляет нас без возможности ссылаться на предыдущие теги, если мы хотим создать тег тега (или более высокие уровни вложенности).
  2. Это не оставляет нам возможности записать, что тег уже был импортирован при использовании --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

Это отражает ваше локальное репо на удаленном в процессе, удаляя все другие ветви, кроме тех, которые у вас есть в вашем локальном репо.

Другие вопросы по тегам