Вы можете написать свой собственный код для этого, но вы не можете сделать это с помощью Git «из коробки».Самое близкое, что вы можете получить, это сделать то, что вы сказали не хотите сделать:
git update-index --assume-unchanged [<file>...]
примет файл без изменений навсегда.
На самом деле, вы, вероятно, должны использовать --skip-worktree
здесь.(См. Git - Разница между «предположим, без изменений» и «skip-worktree» .) Используйте --no-assume-unchanged
или --no-skip-worktree
для очистки бит, который вы только что установили.Составьте список файлов, для которых вы установили биты предположения без изменений или биты пропуска рабочего дерева, и вы можете очистить, а затем заново установить эти биты, когда захотите;это самое близкое к тому, что вы получаете от Git на сегодняшний день.
Длинно: почему Git такой упрямый
В частности, давайте рассмотрим итоговую строку темы:
Как [можно] выборочно удалить определенные файлы из локального списка изменений (не из поэтапного списка), не удаляя из индекса?
Это все равно, что спросить, как вы можете убедить папу перейти от исламав буддизм.Это начинается с неверной предпосылки!
По сути, нет никакого «локального списка изменений», и при этом нет «поэтапного списка».Существует только коммитов , index и work-tree .
Каждый такой объект содержит некоторый набор файлов:
Файлы в любом заданном коммите замораживаются и сжимаются в специальный формат Git-only для экономии места.Вы никогда не сможете изменить любой файл, сохраненный внутри коммита: все, что вы можете сделать, это сделать новый коммит, который очень похож на старый, но с некоторыми другими замороженными файлами, и переключиться сНапример, ваш текущий коммит (в котором была заморожена версия 17 файла A) с новым коммитом (который теперь имеет замороженную версию 18 файла A).
(И, конечно, вы не можете добавить файл взамороженный коммит или удалите его. Опять же, вы можете сделать только новый коммит, который в основном, но не совсем так, как предыдущий.)
Файлы в вашем рабочем дереве размораживаются в обычном формате.Вы и все ваши компьютерные программы могут работать с ними (отсюда и название «рабочее дерево» или «рабочее дерево»).Вы можете читать их, писать их, уничтожать их, делать все, что угодно.
index - также называемый, по-разному, область подготовки или иногда кеш , в зависимости от того, кто или что делает вызов, живет этими двумя позициями.Файлы в индексе имеют специальный формат Git-only, но они не заморожены.Вы можете заменить их оптом в любое время.
Давайте добавим в качестве примечания, что HEAD
всегда представляет ваш текущий коммит.(Это верно даже в новом пустом хранилище, в котором нет коммитов: HEAD
по-прежнему представляет текущий коммит, который не существует. Это то, что заставляет несколько команд Git действовать немного squirrelly в этот момент.)
Первоначально копии в индексе совпадают с копиями в текущем (и замороженном) коммите - и если вы переключитесь с , то коммит для некоторого другого коммита, копии в индексе все еще соответствуют фиксированному коммиту.Обновление с коммита a123456...
до fedcba9...
заставляет Git переключать ваш индекс с «копии a123456
» на «копию fedcba9
».В общем случае - есть несколько конкретных исключений для команд сантехники - когда Git отключает копирование индексных копий, Git также отключает рабочее дерево копий.
Чтоgit add
делает это заменить индексную копию некоторого файла тем, который вы берете из рабочего дерева.Таким образом, нормальный процесс в Git - это git checkout
некоторый коммит, так что HEAD
имеет замороженные копии, индекс оттаивает их (но так же, как HEAD
), и ваше рабочее дерево их раскрываетв полезную форму (и так же, как в указателе).Затем вы меняете один в рабочем дереве и запускаете git add
в копирование it из рабочего дерева обратно в индекс.
Теперь индексная копия не соответствует копии HEAD
, но соответствует копии рабочего дерева.Так что в Git довольно часто иметь индексную копию каждого совпадения файла одну другую активную копию: либо копию HEAD
, либо копию рабочего дерева.Но, конечно, возможно, чтобы индексное совпадение совпадало с или , потому что мы можем изменить файл рабочего дерева, скопировать его в индекс и затем изменить его снова .Теперь все три копии будут различаться.
В любой момент мы можем запустить git commit
.Это мгновенно замораживает копии index - которые уже находятся в формате Git, поэтому все они уже готовы - и помещает замороженные копии в хранилище в качестве файлов для нашего нового коммита.Новый коммит затем становится текущим (HEAD
) коммитом, и теперь коммит и индекс совпадают. 1
(Это также возможно, конечно,иметь файлы в одном или нескольких местах, которые не являются в других. Если мы создадим совершенно новый файл рабочего дерева, его сейчас нет в индексе. Использование git add
скопирует его в индекс, в специальной сжатой форме Git-only, но не в замороженном виде. Или, если файл уже находится в индексе и рабочем дереве, мы можем использовать git rm
, чтобы удалить его из обоих. Конечнони один из них не может повлиять на любую замороженную копию в любом существующем коммите.)
Мы можем в любое время попросить Git сравнить текущий коммит - точнее, все HEAD
замороженные файлы - к индексу:
git diff --cached
Если мы хотим, чтобы имена из "M" были одифицированы, недавно - "A" dded или "D" eleted "файлы, возможно, включая буквенный код для этого состояния, мы говорим git diff
печатать только имена или имена и буквенный код для каждого файла:
git diff --cached --name-only
git diff --cached --name-status
Во всех случаях Git находит ответ по , сравнивая замороженный HEAD
с слякотным индексом.
Аналогично, мы можем попросить Git сравнить индекс с рабочим деревом:
git diff
git diff --name-only
git diff --name-status
Это делает то же самое, что и раньше, за исключением того, что вместо сравнения замороженного HEAD
с слякотным индексом он сравнивает слякотный индекс с жидким рабочим деревом.
Что git status
делает, чтобырассказать о файлах, это запустить обе эти две git diff
операции .Эти создают тех списков, которые вы упомянули выше, но только на время выполнения git status
: как только git status
напечатает списки и выйдет, эти списки больше не будут существовать.
Что --assume-unchanged
и --skip-worktree
do is установить определенный бит флага для некоторых внутренних флагов, сохраняемых с каждой записью файла, хранящейся в индексе.Эти флаги говорят Git: Не беспокойтесь о сравнении индексов и копий рабочего дерева, просто предположите, что они одинаковы. Так что в этот момент git status
не будет говорить что-либоо файле.Более того, git add
будет предполагать, что копия индекса хороша, и не будет обновлять ее - обновление копии индекса требует повторного сжатия копии рабочего дерева, в конце концов, что занимает заметное количество времени.(Это значительная часть , почему Git держит в индексе слякотную, не совсем замороженную копию, готовую к отправке. Когда файл готов к отправке, в коммите next вы сделаетеmake, делает git commit
удивительно быстрее, чем старые системы контроля версий.)
Примечаниечто, поскольку является отдельной копией в индексе, новые коммиты, которые вы сделаете, будут заморожены в них.У них просто есть копия index - такая же, как у старой копии HEAD
- в них.Но если вы используете git checkout
для переключения с этого коммита на какой-то другой коммит, и этот другой коммит имеет другую копию замороженного файла, ваш индекскопия будет обновлена в соответствии с копией другой коммита.Вот где Git - разница между «предположим, без изменений» и «skip-worktree» снова появляется.