Почему исключенные файлы продолжают появляться в моем git sparse checkout?

Я использую зеркало git GCC и, поскольку я использую только внешние интерфейсы C и C++, я использую функцию разреженного извлечения git, чтобы исключить сотни ненужных мне файлов:

$ git config core.sparseCheckout
true
$ cat .git/info/sparse-checkout 
/*
!gnattools/
!libada/
!libgfortran/
!libgo/
!libjava/
!libobjc/
!libquadmath/
!gcc/ada/
!gcc/fortran/
!gcc/go/
!gcc/java/
!gcc/objc/
!gcc/objcp/
!gcc/testsuite/ada/
!gcc/testsuite/gfortran.dg/
!gcc/testsuite/gfortran.fortran-torture/
!gcc/testsuite/gnat.dg/
!gcc/testsuite/go.dg/
!gcc/testsuite/go.go-torture/
!gcc/testsuite/go.test/
!gcc/testsuite/objc/
!gcc/testsuite/objc.dg/
!gcc/testsuite/obj-c++.dg/
!gcc/testsuite/objc-obj-c++-shared/

Это работает некоторое время, но время от времени я замечаю, что некоторые из этих исключенных файлов вернулись, иногда их много:

$ ls gnattools/
ChangeLog  configure  configure.ac  Makefile.in
$ ls  gcc/fortran/ | wc -l 
86

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

Как относительный новичок в git, я не знаю, как "перезагрузить" мое рабочее дерево, чтобы снова избавиться от этих файлов.

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

$ git config core.sparseCheckout false
$ git config core.sparseCheckout 
false
$ git pull
remote: Counting objects: 276, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 117 (delta 98), reused 0 (delta 0)
Receiving objects: 100% (117/117), 64.05 KiB, done.
Resolving deltas: 100% (98/98), completed with 64 local objects.
From git://gcc.gnu.org/git/gcc
   7618909..0984ea0  gcc-4_5-branch -> origin/gcc-4_5-branch
   b96fd63..bb95412  gcc-4_6-branch -> origin/gcc-4_6-branch
   d2cdd74..2e8ef12  gcc-4_7-branch -> origin/gcc-4_7-branch
   c62ec2b..fd9cb2c  master     -> origin/master
   2e2713b..29daec8  melt-branch -> origin/melt-branch
   c62ec2b..fd9cb2c  trunk      -> origin/trunk
Updating c62ec2b..fd9cb2c
error: Your local changes to the following files would be overwritten by merge:
        gcc/fortran/ChangeLog
        gcc/fortran/iresolve.c
        libgfortran/ChangeLog
        libgfortran/io/intrinsics.c
Please, commit your changes or stash them before you can merge.
Aborting

Очевидно, у меня есть локальные модификации файлов, о которых я никогда не просил, и AFAIK никогда не трогал!

Но git status не показывает эти изменения:

$ git st
# On branch master
# Your branch is behind 'origin/master' by 9 commits, and can be fast-forwarded.
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       libstdc++-v3/53270.txt
#       libstdc++-v3/TODO

я пробовал git read-tree -m -u HEAD но это ничего не делает.

Итак, мои вопросы:

  • Почему файлы появляются снова?
  • Как я могу заставить их исчезнуть снова?
  • Как я могу предотвратить их возвращение?
  • Возможно, это связано с тем, что мой .git/info/exclude файл содержит ссылки на файлы в каталогах, которые должны быть исключены (т.е. !) в sparse-checkout файл? Я следовал инструкциям, чтобы игнорировать те же файлы, что и SVN

    $ git svn show-ignore >> .git/info/exclude

Так что мой exclude файлы включают в себя пути, такие как

# /gcc/fortran/
/gcc/fortran/TAGS
/gcc/fortran/TAGS.sub
/gcc/fortran/gfortran.info*

Который будет ниже одного из каталогов, названных в sparse-checkout файл:

!gcc/fortran/

Я пытался воспроизвести проблему с тестовым репозиторием, в котором я клонирую несколько копий и редактирую каждую из них, создаю / переключаю / удаляю ветки и объединяю изменения между ними, но в моих игрушечных тестовых примерах это никогда не ошибалось. Репозиторий GCC немного велик (более 2 ГБ), и время между "сбоями" (порядка недели или двух) слишком велико, чтобы ожидать, что люди попытаются точно воспроизвести проблему. Я не экспериментировал с такими же путями в sparse-checkout а также excludeКак мне сегодня казалось, там может быть конфликт.

Я спрашивал об этом на #git на freenode несколько недель назад, и IIRC в основном сказали: "это, вероятно, ошибка, никто не использует редкие проверки", но я надеюсь на лучший ответ;-)

Обновить:

В самый последний раз, когда я увидел, что проблема действительно произошла (то есть, файлов не было, а затем появилось после одной команды), выполнял извлечение из исходного потока:

   bac6f1f..6c760a6  master     -> origin/master

и среди показанных изменений были эти переименования:

 create mode 100644 libgo/go/crypto/x509/root.go
 rename libgo/go/crypto/{tls => x509}/root_darwin.go (90%)
 rename libgo/go/crypto/{tls => x509}/root_stub.go (51%)
 rename libgo/go/crypto/{tls => x509}/root_unix.go (76%)
 create mode 100644 libgo/go/crypto/x509/root_windows.go

Прежде чем тянуть libgo каталог отсутствовал, по желанию. После того, как тяга dir присутствовала, и эти файлы (и никакие другие) были под ним:

$ ls libgo/go/crypto/x509/root_<TAB>
root_darwin.go  root_stub.go    root_unix.go    

Я не знаю, потеряли ли переименованные файлы свои skip-worktree немного, как я могу это проверить?

Я уверен, что проблема не всегда возникает при переименовании, потому что, например, libgfortran/ChangeLog Файл, показанный в примере выше, не является новым файлом или недавно переименован.

3 ответа

Решение

Бит skip-worktree можно изменить с помощью git update-index --skip-worktree, Когда вы заметите наличие файлов, вы можете проверить git ls-files -v |grep ^S (S - это файл, помеченный skip-worktree).

Но, как говорят люди #git, если вы видите странное поведение, это, скорее всего, ошибка в git. Ведь это довольно эзотерическая особенность. Вы, вероятно, должны сообщить о своих выводах в список рассылки git.

Изменить: Кроме того, если вы используете git 1.7.7.6, я настоятельно рекомендую обновить. 1.7.10 дерево далеко впереди, и я думаю, что есть большая вероятность, что оно решит ваши проблемы.

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

Когда я пытался git reset --hard 123456Я получил следующую ошибку:

error: Entry 'a.c' not uptodate. Cannot update sparse checkout.
fatal: Could not reset index file to revision '123456'.

Решением было удалить файлы из моего рабочего дерева, повторно применив правила sparse-checkout:

git read-tree -mu HEAD

Проверьте, сохраняется ли проблема в последней версии Git 2.13 (второй квартал 2017 года, 5 лет спустя).
Любой файл skip-worktree больше не должен изменяться или даже просматриваться во время разреженной проверки, потому что:

preload-index Код научили не беспокоить индексные записи, которые являются путями, которые не извлекаются "разреженным извлечением".

Смотрите коммит e596acc (10 февраля 2017 г.) Джеффа Хостетлера ( jeffhostetler )
(Объединено Юнио С Хамано - gitster - в коммите c7e234f, 27 февраля 2017 г.)

preload-index: избегать lstat за skip-worktree Предметы

Учат preload-index избежать lstat() вызовы записей индекса с установленным битом skip-worktree.
Это оптимизация производительности.

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

В системе Windows 10 с очень большим репо (индекс 450 МБ) и различными уровнями разреженности производительность была улучшена в {preloadindex=true, fscache=false} на 80% и в {preloadindex=true, fscache=true} случай на 20% для различных команд.

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