git fsck, объединяющий --lost-found и --unreachable

Я нашел много интересных сообщений о git fsck, поэтому я хотел немного поэкспериментировать с ними. Прежде всего источники, которые я прочитал перед этим вопросом:

Я начал с этого репо:

      * 9c7d1ea (HEAD -> test) f
* cd28884 e
| * 7b7bac0 (master) d
| * cab074f c
|/  
* d35af2c b
| * f907f39 r # unreferenced commit
|/
* 81d6675 a

Где был создан из отдельного HEADиз a. Затем я хотел перебазировать masterна test, но у меня были некоторые неустановленные изменения, поэтому я сделал:

      git rebase --autostash test

Получение (не показываю, но все равно есть):

      * caee68c (HEAD -> master) d
* 2e1cb7d c
* 9c7d1ea (test) f
* cd28884 e
* d35af2c b
* 81d6675 a

Далее я запускаю:

      $ git fsck
#...
dangling commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
#...
      $ git fsck --unreachable
#...
unreachable commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
unreachable commit d8bb677ce0f6602f4ccad46123ee50f2bf6b5819 # stash index
#...
      $ git fsck --lost-found
#...
dangling commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
dangling commit f907f39d41763accf6d64f4c736642c0120d5ae2 # r
#...

Первый вопрос

Почему только версия возвращает rсовершить? А почему не те cа также dперед rebaseпоказан среди недосягаемых? Я думал, что понял разницу, читая связанные вопросы, но я явно что-то упускаю. У меня все еще есть полный рефлог, но я думаю, он вам не нужен, так как все коммиты (кроме связанных с stash) ссылаются.


Я знаю, что должен создать еще один пост, но второй вопрос частично связан. Я попробовал из любопытства:

      $ git fsck --lost-found --unreachable
#...
unreachable commit 6387b70fe14f1ecb90e650faba5270128694613d # stash
unreachable commit d8bb677ce0f6602f4ccad46123ee50f2bf6b5819 # stash index
unreachable commit f907f39d41763accf6d64f4c736642c0120d5ae2 # r
unreachable commit 7b7bac0608936a0bcc29267f68091de3466de1cf # c before rebase
unreachable commit cab074f2c9d63919c3fa59a2dd63ec874b0f0891 # d before rebase
#...

Второй вопрос

Комбинируя оба варианта, я получаю все недостижимые коммиты (а не только объединение --lost-foundа также --unreachable), это очень неожиданно. Почему оно так себя ведет?

1 ответ

Кое-что из этого действительно вызывает недоумение и, по-видимому, не задокументировано должным образом, но беглый взгляд на встроенный/fsck.c показывает, что использование:

  1. включается ;
  2. включается .

Пункт 1 не особенно интересен, так как --fullв любом случае теперь включено по умолчанию, но в документации действительно должно быть указано, что отключает --no-full. Пункт 2 объясняет большую часть остального; У меня есть предположение о последней части [ Редактировать : остальное].

Обратите внимание, что когда вы запускали:

       git checkout master && git rebase --autostash test

это заставило Git запуститься, что создало новый тайник, состоящий из двух новых коммитов. Затем Git, как обычно, выполнил перебазирование, которое скопировало cab074fа также 7b7bac0коммиты, видимые в оригинале git log --all --decorate --oneline --graphвывод, к новому 2e1cb7dа также caee68cкоммиты видны во втором выводе.

Почему только версия возвращает коммит? И почему среди недостижимых не отображаются и до ребазы?

Предположительно, этот коммит все еще находится в reflog. Это делает его доступным по ссылке, но, поскольку подразумевает , на этот раз он становится недостижимым. То же самое касается оригиналов cи: они доступны через несколько записей reflog, как из HEADreflog и masterс.

Комбинируя оба варианта, я получаю все недостижимые коммиты (а не только объединение и ), это очень неожиданно. Почему оно так себя ведет?

Это более загадочно. [ Изменить : решено; см. ниже.] Давайте запустим их в порядке ваших команд:

  • fsck 1 и fsck 2: оба обнаруживают коммиты autostash. Это потому что git stash pushскопировал оригинал в stash reflog, чтобы он мог указывать на коммит autostash (рабочее дерево). Тогда подразумеваемый git stash apply && git stash drop( git stash pop) применил тайник и бросил его, переместив stash@{1}вход обратно и удаление stash reflog. Так что коммит из автосташа действительно "болтается". Это не в refs/stashи дело даже не в stashрефлог, потому что git stash(ab) использует этот журнал ссылок как «стек тайника». Однако он указывает на фиксацию из автозакладки.

    Тогда первая fsck печатает 6387b70fe14f1ecb90e650faba5270128694613dи называет это «висячим». Это коммит, который был удален. Секунда fsck, с , добавляет d8bb677ce0f6602f4ccad46123ee50f2bf6b5819: соответствующая фиксация, которая была удалена.

  • fsck 3: коммиты и перебазированные оставались невидимыми под git fsck --unreachableпотому что на них есть ссылки из reflogs. Но теперь, с , fsck не смотрит на reflogs. Мы должны ожидать, что фиксация autostash, фиксация и pre-rebase будут висящими. [ Изменить : согласно комментарию , это неправильно: ссылки на i и , так что это скроется.]

    Мы действительно видим и rсовершает , но не фиксирует . Почему бы и нет? Это мое предположение , но его легко проверить, если у вас все еще есть настройки: когда вы используете git rebaseуспешно, Git создает или обновляет псевдоссылку с именем, чтобы запомнить хэш-идентификатор фиксации подсказки до завершения перебазирования. Обратите внимание, что это же имя используется для запоминания предыдущего значения ссылки после успешного выполнения. git resetкоторая перемещает один, и после любой другой операции, которая может переместить имя ветки на некоторое расстояние (например, ускоренное слияние).

    Совершенно очевидно, что git fsckнеобходимо учитывать все различные *_HEADпсевдоссылки как отправные точки для достижимости. Это тоже не задокументировано (и даже не совсем ясно, было ли это преднамеренным здесь — в последнее время код ссылок подвергался довольно серьезной переработке для поддержки альтернативных бэкэндов ссылок).

  • fsck 4, как раз перед вашим разделом ВТОРОЙ ВОПРОС: либо отключили включение псевдоссылки, либо — я думаю, что это более вероятно — вы сделали что-то промежуточное, что коснулось ORIG_HEADтак что он больше не выбирал исходный коммит до перебазирования. [ править ] С тех пор --unreachableперечисляет все недостижимые коммиты, тот факт, что dдоступен косвенно из автотайника wcommit не имеет значения, и мы все видим.

Если вы хотите сообщить об ошибке документации Git, в документации fsck не указано, что --lost-foundподразумевает --no-reflogs, вы должны сделать это.

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