git reflog expire и git fsck - недоступны - PullRequest
18 голосов
/ 08 февраля 2012

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

Так что я играл с git, пытаясь истечь исправленный коммит.Мой рефлог выглядит так:

4eea1cd HEAD@{0}: commit (amend): amend commit
ff576c1 HEAD@{1}: commit: test: bar
5a1e68a HEAD@{2}: commit: test: foo
da8534a HEAD@{3}: commit (initial): initial commit

Это означает, что я сделал два коммита (da8534a и 5a1e68a), затем третий коммит ff576c1, который я исправил с помощью 4eea1cd.

Как и ожидалось, мой git log выглядит примерно так:

* 4eea1cd (HEAD, master) amend commit
* 5a1e68a test: foo
* da8534a initial commit

Из того, что я (хотя я) знаю об истечении срока действия коммитов, когда-нибудь (скорее всего, через 30 дней по умолчанию) git gc должен собрать ff576c1.Теперь я не хочу ждать 30 дней, чтобы это произошло, поэтому сначала я запускаю несколько команд:

git fsck --unreachable --no-reflogs

Что, как и ожидалось, дает мне:

unreachable blob 5716ca5987cbf97d6bb54920bea6adde242d87e6
unreachable tree 1e60e555e3500075d00085e4c1720030e077b6c8
unreachable commit ff576c1b4b6df57ba1c20afabd718c93dacf2fc6

Все уверены, что у меня закончится этот бедный одинокий ff576c1 коммит, затем я запускаю git reflog expire:

git reflog expire --dry-run --expire-unreachable=now --all

Что в тот раз дает мне:

would prune commit: test: bar
would prune commit (amend): amend commit

Сначала я думал, что мой HEAD не ссылается на master, но, как вы можете видеть в выводе git log, который я дал ранее, это действительно так.Кроме того, cat .git/HEAD подтверждает это (сдача ref: refs/heads/master).Во всяком случае, даже если это было глупо, поскольку 4eea1cd является главой моей master ветви.

Так что я здесь, все сбиты с толку, что эти две команды не дадут мне одинаковые коммиты, и мне интереснокак, черт возьми, 4eea1cd может быть недоступен, так как это фактический наконечник моей master ветви.

Есть идеи о том, что происходит?

РЕДАКТИРОВАТЬ :Я только заметил, что если я добавлю --rewrite параметр к git reflog expire, например:

git reflog expire --dry-run --expire-unreachable=now --all --rewrite

Тогда я получу только исправленный коммит:

would prune commit: test: bar

Я до сих пор не могупонимаю, потому что согласно git help reflog:

   --rewrite
       While expiring or deleting, adjust each reflog entry to ensure that
       the old sha1 field points to the new sha1 field of the previous
       entry.

Что не имеет смысла в моем случае.Ну, по крайней мере, я не понимаю, так как это, конечно, что-то меняет.

1 Ответ

11 голосов
/ 11 февраля 2012

Это происходит из-за взаимодействия философии проектирования reflog и требований сборки мусора.

Чтобы коммит был безопасно удален сборщиком мусора, все ссылки на этот коммит должны быть удалены & mdash; включая ссылки в записях reflog. Несмотря на появление reflog show, каждая запись reflog фактически содержит два идентификатора SHA1: значение ref до изменения и значение ref после изменения. Чтобы обеспечить безопасную сборку мусора, reflog expire просто удаляет любую запись, где один из двух SHA1 идентифицирует недоступный коммит.

В вашем случае значение перед изменением самой последней записи reflog относится к недостижимой фиксации. Даже если фиксация, определенная значением после изменения, все еще достижима, reflog expire удаляет запись.

Этот проект прост в реализации и приводит к неполному, но точному журналу.

опция --rewrite

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

  • в журнале остается пробел
  • полезная информация, связанная с еще достижимыми коммитами, потеряна

Опция --rewrite решает эти проблемы путем изменения поведения следующим образом:

  • Как и прежде, записи, в которых фиксация, определенная SHA1 после изменения, недоступна, удаляется.
  • Записи, в которых фиксация перед изменением недоступна, модифицируются так, чтобы сократить разрыв, оставленный удаленной записью (SHA1 перед изменением устанавливается равным значению SHA1 после изменения предыдущей записи).

К сожалению, изменение записи приводит к журналу, который больше не точно отражает историю ссылки. Например, причина изменения может больше не иметь смысла после перезаписи. Вот почему --rewrite не является значением по умолчанию.

...