Подтвердить что ты не робот

Git reflog expire и git fsck - недоступен

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

Итак, я играл с git, пытаясь закончить исправленную фиксацию. Мой рефлог выглядит так:

4eea1cd [email protected]{0}: commit (amend): amend commit
ff576c1 [email protected]{1}: commit: test: bar
5a1e68a [email protected]{2}: commit: test: foo
da8534a [email protected]{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 commit, я запустил 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.

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

4b9b3361

Ответ 1

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

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

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

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

параметр --rewrite

К сожалению, при удалении записи, которая ссылается на целостную транзакцию, есть несколько проблем:

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

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

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

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