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

Я использую GCC git mirror, и поскольку я использую только контуры 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, я не знаю, как "reset" мое дерево работы снова избавиться от этих файлов.

В качестве эксперимента я попытался отключить разреженную проверку и потянув, думая, что смогу снова включить 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 в основном сказали: "Это, вероятно, ошибка, никто не использует редкую проверку", но я надеюсь на лучший ответ;)

Update:

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

   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, по желанию. После того, как вытащил этот каталог, и эти файлы (и другие) были под ним:

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

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

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

Ответ 1

Бит скип-рабочей строки может быть изменен с помощью 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 дерево впереди, и я думаю, что есть большая вероятность, что он исправит ваши проблемы.

Ответ 2

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

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

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

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

git read-tree -mu HEAD

Ответ 3

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

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

См. совершить e596acc (10 февраля 2017 г.) Jeff Hostetler (jeffhostetler).
(слияние Junio ​​C Hamano - gitster - в commit c7e234f, 27 февраля 2017 г.)

preload-index: избегать lstat для skip-worktree элементов

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

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

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