Листинг и удаление Git совершают те, у которых нет ветки (висит?)

У меня есть репозиторий Git с большим количеством коммитов, которые не имеют никакой отдельной ветки, я могу git show их, но когда я пытаюсь перечислить ветки, которые их содержат, он ничего не сообщает.

Я думал, что это ошибка оборванных коммитов/деревьев (в результате -D-ветки), поэтому я обрезал репо, но после этого я все еще вижу такое же поведение:

$ git fetch origin

$ git fsck --unreachable
$ git fsck

Нет вывода, ничего не болтается (правильно?). Но фиксация существует

$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...

и это невозможно для любой ветки как

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

не выводит результат.

Что такое состояние этого коммита? Как я могу перечислить все коммиты в аналогичном состоянии? Как я могу удалить такие коммиты?

Ответы

Ответ 1

Нет вывода, ничего не болтается (правильно?)

Обратите внимание, что фиксации, ссылающиеся на ваш рефлок, считаются доступными.

Что такое состояние этого коммита? Как я могу перечислить все коммиты с аналогичным состоянием

Pass --no-reflogs, чтобы убедить git fsck показать их вам.

Как я могу удалить такие коммиты?

Как только ваши записи в журнале будут истекли, эти объекты также будут очищены git gc.

Истечение регулируется параметрами gc.pruneexpire, gc.reflogexpire и gc.reflogexpireunreachable. Ср git help config.

По умолчанию все разумно.

Ответ 2

Чтобы удалить все оборванные коммиты и те, которые доступны из журналов, выполните следующие действия:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

Но будьте уверены, что это то, что вы хотите. Я рекомендую вам читать страницы руководства, но вот суть:

git gc удаляет недостижимые объекты (commits, trees, blobs (файлы)). Объект недоступен, если он не является частью истории какой-либо ветки. На самом деле это немного сложнее:

git gc делает некоторые другие вещи, но они здесь не актуальны и не опасны.

Недоступные объекты, которые моложе двух недель, не удаляются, поэтому мы используем --prune=now, что означает "удалить недоступные объекты, которые были созданы до этого момента".

Объекты также могут быть достигнуты через reflog. В то время как ветки записывают историю какого-либо проекта, в журналах регистрируются истории этих веток. Если вы вносите изменения, reset и т.д. Коммиты удаляются из истории ветвлений, но git поддерживает их, если вы осознаете, что совершили ошибку. Reflogs - это удобный способ узнать, какие деструктивные (и другие) операции выполнялись на ветке (или HEAD), что облегчает отмену деструктивной операции.

Таким образом, нам также необходимо удалить блокировки, чтобы удалить все, недоступные из ветки. Мы делаем это, заканчивая --all reflogs. Опять же, git хранит бит reflogs для защиты пользователей, поэтому мы снова должны сказать ему, чтобы он этого не делал: --expire-unreachable=now.

Так как я в основном использую reflog для восстановления после деструктивных операций, я обычно использую --expire=now, что полностью блокирует reflogs.

Ответ 3

git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

возможно, просто нужно

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

также сообщать о ветвях из пультов

Ответ 4

У меня была такая же проблема, все еще после всех советов в этой теме:

git reflog expire --expire-unreachable=now --all
git gc --prune=now
git fsck --unreachable --no-reflogs   # no output
git branch -a --contains <commit>     # no output
git show <commit>                     # still shows up

Если это не reflog, а не ветка,... он должен быть тегом!

git tag                             # showed several old tags created before the cleanup

Я удалил теги git tag -d <tagname> и удалил очистку, а старые коммиты исчезли.

Ответ 5

У меня была аналогичная проблема. Я побежал git branch --contains <commit>, и он не возвращал результат, как в вопросе.

Но даже после запуска

git reflog expire --expire-unreachable=now --all
git gc --prune=now

my commit все еще был доступен с помощью git show <commit>. Это было связано с тем, что один из коммитов в его отсоединенной "ветке" был помечен. Я удалил тег, снова выполнил приведенные выше команды, и я был золотым. git show <commit> вернулся fatal: bad object <commit> - именно то, что мне нужно. Надеюсь, это поможет кому-то другому, который был так же застрял, как и я.

Ответ 6

git gc --prune=<date> defaults обрезает объекты старше двух недель назад. Вы можете установить более позднюю дату. Но команды git, которые создают свободные объекты, обычно будут запускать git gc --auto (которые обрезают свободные объекты, если их число превышает значение переменной конфигурации gc.auto).

Вы уверены, что хотите удалить эти коммиты? Значение gc.auto по умолчанию гарантирует, что свободные объекты не занимают неоправданный объем памяти, а хранение незакрепленных объектов в течение некоторого времени обычно является хорошей идеей. Таким образом, если вы осознаете, что ваша удаленная ветка содержит требуемую фиксацию, вы можете ее восстановить.

Ответ 7

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

Это то, что я сделал, чтобы сделать его действительно недоступным.

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now